From 6b70b59c83c9c2442925fb147b6903a8456b77d7 Mon Sep 17 00:00:00 2001
From: Vinil Vadakkepurakkal <82436391+vinil-v@users.noreply.github.com>
Date: Mon, 7 Oct 2024 19:30:01 +0530
Subject: [PATCH 1/6] Updating cloud bursting repos for Hybrid Scenarios
Updating cloud bursting repo for created Hybrid HPC clusters using CycleCloud 8.4 & Slurm 23.11.9-1.
---
cloud_bursting/slurm-23.11.9-1/README.md | 188 ++++++
.../cyclecloud/cyclecloud-project-build.sh | 23 +
.../slurm-23.11.9-1/cyclecloud/slurm.txt | 588 ++++++++++++++++++
.../scheduler/cyclecloud-integrator.sh | 115 ++++
.../scheduler/slurm-scheduler-builder.sh | 387 ++++++++++++
.../scheduler/useradd_example.sh | 46 ++
6 files changed, 1347 insertions(+)
create mode 100644 cloud_bursting/slurm-23.11.9-1/README.md
create mode 100644 cloud_bursting/slurm-23.11.9-1/cyclecloud/cyclecloud-project-build.sh
create mode 100644 cloud_bursting/slurm-23.11.9-1/cyclecloud/slurm.txt
create mode 100644 cloud_bursting/slurm-23.11.9-1/scheduler/cyclecloud-integrator.sh
create mode 100644 cloud_bursting/slurm-23.11.9-1/scheduler/slurm-scheduler-builder.sh
create mode 100644 cloud_bursting/slurm-23.11.9-1/scheduler/useradd_example.sh
diff --git a/cloud_bursting/slurm-23.11.9-1/README.md b/cloud_bursting/slurm-23.11.9-1/README.md
new file mode 100644
index 00000000..4b908eb8
--- /dev/null
+++ b/cloud_bursting/slurm-23.11.9-1/README.md
@@ -0,0 +1,188 @@
+# Slurm Cloud Bursting Using CycleCloud
+
+This repository provides detailed instructions and scripts for setting up Slurm bursting using CycleCloud on Microsoft Azure, allowing you to seamlessly scale your Slurm cluster into the cloud for additional compute resources.
+
+## Overview
+
+Slurm bursting enables the extension of your on-premises Slurm cluster into Azure for flexible and scalable compute capacity. CycleCloud simplifies the management and provisioning of cloud resources, bridging your local infrastructure with cloud environments.
+
+## Table of Contents
+
+- [Requirements](#requirements)
+- [Setup Instructions](#setup-instructions)
+- [Importing a Cluster Using the Slurm Headless Template in CycleCloud](#importing-a-cluster-using-the-slurm-headless-template-in-cyclecloud)
+- [Slurm Scheduler Installation and Configuration](#slurm-scheduler-installation-and-configuration)
+- [CycleCloud UI Configuration](#cyclecloud-ui-configuration)
+- [CycleCloud Autoscaler Integration with Slurm Scheduler](#cyclecloud-autoscaler-integration-on-slurm-scheduler)
+- [User and Group Setup (Optional)](#user-and-group-setup-optional)
+- [Testing the Setup](#testing-the-setup)
+- [Contributing](#contributing)
+
+## Requirements
+
+Ensure you have the following prerequisites in place:
+
+- **OS Version supported**: AlmaLinux release 8.7 (`almalinux:almalinux-hpc:8_7-hpc-gen2:latest`) & Ubuntu HPC 22.04 (`microsoft-dsvm:ubuntu-hpc:2204:latest`)
+- **Slurm Version**: 23.11.9-1
+- **CycleCloud Version**: 8.6.4-3320
+
+## Setup Instructions
+
+### Importing a Cluster Using the Slurm Headless Template in CycleCloud
+
+- This step must be executed on the **CycleCloud VM**.
+- Make sure that the **CycleCloud 8.6.4 VM** is running and accessible via the `cyclecloud` CLI.
+- Execute the `cyclecloud-project-build.sh` script and provide the desired cluster name (e.g., `hpc1`). This will set up a custom project based on the `cyclecloud-slurm-3.0.9` version and import the cluster using the Slurm headless template.
+- In the example provided, `hpc1` is used as the cluster name. You can choose any cluster name, but be consistent and use the same name throughout the entire setup.
+
+
+```bash
+git clone https://github.com/Azure/cyclecloud-slurm.git
+cd cyclecloud-slurm/cloud_bursting/slurm-23.11.9-1/cyclecloud
+sh cyclecloud-project-build.sh
+```
+
+Output :
+
+```bash
+[user1@cc86vm ~]$ cd cyclecloud-slurm/cloud_bursting/slurm-23.11.9-1/cyclecloud
+[user1@cc86vm cyclecloud]$ sh cyclecloud-project-build.sh
+Enter Cluster Name: hpc1
+Cluster Name: hpc1
+Use the same cluster name: hpc1 in building the scheduler
+Importing Cluster
+Importing cluster Slurm_HL and creating cluster hpc1....
+----------
+hpc1 : off
+----------
+Resource group:
+Cluster nodes:
+Total nodes: 0
+Locker Name: HPC+AI storage
+Fetching CycleCloud project
+Uploading CycleCloud project to the locker
+```
+
+### Slurm Scheduler Installation and Configuration
+
+- A VM should be deployed using the specified **AlmaLinux 8.7** or **Ubuntu 22.04** image.
+- If you already have a Slurm Scheduler installed, you may skip this step. However, it is recommended to review the script to ensure compatibility with your existing setup.
+- Run the Slurm scheduler installation script (`slurm-scheduler-builder.sh`) and provide the cluster name (`hpc1`) when prompted.
+- This script will install and configure Slurm Scheduler.
+
+
+
+```bash
+git clone https://github.com/Azure/cyclecloud-slurm.git
+cd cyclecloud-slurm/cloud_bursting/slurm-23.11.9-1/scheduler
+sh slurm-scheduler-builder.sh
+```
+Output
+
+```bash
+------------------------------------------------------------------------------------------------------------------------------
+Building Slurm scheduler for cloud bursting with Azure CycleCloud
+------------------------------------------------------------------------------------------------------------------------------
+
+Enter Cluster Name: hpc1
+------------------------------------------------------------------------------------------------------------------------------
+
+Summary of entered details:
+Cluster Name: hpc1
+Scheduler Hostname: masternode2
+NFSServer IP Address: 10.222.1.26
+```
+
+### CycleCloud UI Configuration
+
+- Access the **CycleCloud UI** and navigate to the settings for the `hpc1` cluster.
+- Edit the cluster settings to configure the VM SKUs and networking options as needed.
+- In the **Network Attached Storage** section, enter the NFS server IP address for the `/sched` and `/shared` mounts.
+- Select the OS from Advance setting tab - **Ubuntu 22.04** or **AlmaLinux 8** from the drop down based on the scheduler VM.
+- Once all settings are configured, click **Save** and then **Start** the `hpc1` cluster.
+
+
+
+### CycleCloud Autoscaler Integration on Slurm Scheduler
+
+- Integrate Slurm with CycleCloud using the `cyclecloud-integrator.sh` script.
+- Provide CycleCloud details (username, password, and ip address) when prompted.
+
+```bash
+cd cyclecloud-slurm/cloud_bursting/slurm-23.11.9-1/scheduler
+sh cyclecloud-integrator.sh
+```
+Output:
+
+```bash
+[root@masternode2 scripts]# sh cyclecloud-integrator.sh
+Please enter the CycleCloud details to integrate with the Slurm scheduler
+
+Enter Cluster Name: hpc1
+Enter CycleCloud Username: user1
+Enter CycleCloud Password:
+Enter CycleCloud IP (e.g., 10.222.1.19): 10.222.1.19
+------------------------------------------------------------------------------------------------------------------------------
+
+Summary of entered details:
+Cluster Name: hpc1
+CycleCloud Username: user1
+CycleCloud URL: https://10.222.1.19
+
+------------------------------------------------------------------------------------------------------------------------------
+```
+
+### User and Group Setup (Optional)
+
+- Ensure consistent user and group IDs across all nodes.
+- It is advisable to use a centralized User Management system like LDAP to maintain consistent UID and GID across all nodes.
+- In this example, we are using the `useradd_example.sh` script to create a test user `user1` and a group for job submission. (User `user1` already exists in CycleCloud)
+
+```bash
+cd cyclecloud-slurm/cloud_bursting/slurm-23.11.9-1/scheduler
+sh useradd_example.sh
+```
+
+### Testing the Setup
+
+- Log in as a test user (e.g., `user1`) on the Scheduler node.
+- Submit a test job to verify that the setup is functioning correctly.
+
+```bash
+su - user1
+srun hostname &
+```
+Output:
+```bash
+[root@masternode2 scripts]# su - user1
+Last login: Tue May 14 04:54:51 UTC 2024 on pts/0
+[user1@masternode2 ~]$ srun hostname &
+[1] 43448
+[user1@masternode2 ~]$ squeue
+ JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)
+ 1 hpc hostname user1 CF 0:04 1 hpc1-hpc-1
+[user1@masternode2 ~]$ hpc1-hpc-1
+```
+
+
+You should see the job running successfully, indicating a successful integration with CycleCloud.
+
+For further details and advanced configurations, refer to the scripts and documentation within this repository.
+
+---
+
+These instructions provide a comprehensive guide for setting up Slurm bursting with CycleCloud on Azure. If you encounter any issues or have questions, please refer to the provided scripts and documentation for troubleshooting steps. Happy bursting!
+
+# Contributing
+
+This project welcomes contributions and suggestions. Most contributions require you to agree to a
+Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
+the rights to use your contribution. For details, visit https://cla.microsoft.com.
+
+When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
+a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
+provided by the bot. You will only need to do this once across all repos using our CLA.
+
+This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
+For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
+contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
\ No newline at end of file
diff --git a/cloud_bursting/slurm-23.11.9-1/cyclecloud/cyclecloud-project-build.sh b/cloud_bursting/slurm-23.11.9-1/cyclecloud/cyclecloud-project-build.sh
new file mode 100644
index 00000000..b3fad5ce
--- /dev/null
+++ b/cloud_bursting/slurm-23.11.9-1/cyclecloud/cyclecloud-project-build.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+# This script need to run on cyclecloud VM.
+# This script will fetch the CycleCloud project and upload it to the locker.
+# Author : Vinil Vadakkepurakkal
+# Date : 01/10/2024
+set -e
+read -p "Enter Cluster Name: " cluster_name
+echo "Cluster Name: $cluster_name"
+echo "Use the same cluster name: $cluster_name in building the scheduler"
+
+echo "Importing Cluster"
+cyclecloud import_cluster $cluster_name -c Slurm_HL -f slurm.txt
+
+# creating custom project and upload it to the locker
+
+CCLOCKERNAME=$(cyclecloud locker list | sed 's/(.*)//; s/[[:space:]]*$//')
+echo "Locker Name: $CCLOCKERNAME"
+echo "Fetching CycleCloud project"
+SLURM_PROJ_VERSION="3.0.9"
+cyclecloud project fetch https://github.com/Azure/cyclecloud-slurm/releases/$SLURM_PROJ_VERSION slurm-$SLURM_PROJ_VERSION
+cd slurm-$SLURM_PROJ_VERSION
+echo "Uploading CycleCloud project to the locker"
+cyclecloud project upload "$CCLOCKERNAME"
\ No newline at end of file
diff --git a/cloud_bursting/slurm-23.11.9-1/cyclecloud/slurm.txt b/cloud_bursting/slurm-23.11.9-1/cyclecloud/slurm.txt
new file mode 100644
index 00000000..60249a65
--- /dev/null
+++ b/cloud_bursting/slurm-23.11.9-1/cyclecloud/slurm.txt
@@ -0,0 +1,588 @@
+
+################################
+## Cluster Configuration File ##
+################################
+
+
+[cluster Slurm_HL]
+FormLayout = selectionpanel
+Category = Schedulers
+
+Autoscale = $Autoscale
+
+ [[node defaults]]
+ UsePublicNetwork = $UsePublicNetwork
+ Credentials = $Credentials
+ SubnetId = $SubnetId
+ Region = $Region
+ KeyPairLocation = ~/.ssh/cyclecloud.pem
+ Azure.Identities = $ManagedIdentity
+
+ # Slurm autoscaling supports both Terminate and Deallocate shutdown policies
+ ShutdownPolicy = $configuration_slurm_shutdown_policy
+
+ # Lustre mounts require termination notifications to unmount
+ EnableTerminateNotification = ${NFSType == "lustre" || NFSSchedType == "lustre" || AdditionalNFSType == "lustre" || EnableTerminateNotification}
+ TerminateNotificationTimeout = 10m
+
+ [[[configuration]]]
+
+ slurm.install_pkg = azure-slurm-install-pkg-3.0.9.tar.gz
+ slurm.autoscale_pkg = azure-slurm-pkg-3.0.9.tar.gz
+
+ slurm.version = $configuration_slurm_version
+ slurm.disable_pmc = $configuration_slurm_disable_pmc
+ slurm.user.name = slurm
+ slurm.user.uid = 11100
+ slurm.user.gid = 11100
+ munge.user.name = munge
+ munge.user.uid = 11101
+ munge.user.gid = 11101
+
+ # Disable ip-XXXXXXXX hostname generation
+ cyclecloud.hosts.standalone_dns.enabled = ${NodeNameIsHostname==false}
+ cyclecloud.hosts.simple_vpc_dns.enabled = ${NodeNameIsHostname==false}
+
+ # For fast spin-up after Deallocate, force an immediate re-converge on boot
+ cyclecloud.converge_on_boot = true
+
+ # Disable normal NFS exports and mounts
+ cyclecloud.mounts.sched.disabled = true
+ cyclecloud.mounts.shared.disabled = true
+ cyclecloud.exports.sched.disabled = true
+ cyclecloud.exports.shared.disabled = true
+ cyclecloud.exports.sched.samba.enabled = false
+ cyclecloud.exports.shared.samba.enabled = false
+ cyclecloud.exports.defaults.samba.enabled = false
+ cshared.server.legacy_links_disabled = true
+
+ # May be used to identify the ID in cluster-init scripts
+ cluster.identities.default = $ManagedIdentity
+
+ [[[cluster-init slurm:default:3.0.9]]]
+ Optional = true
+
+ [[[volume boot]]]
+ Size = ${ifThenElse(BootDiskSize > 0, BootDiskSize, undefined)}
+ SSD = True
+
+ [[[configuration cyclecloud.mounts.nfs_shared]]]
+ type = $NFSType
+ mountpoint = /shared
+ export_path = ${ifThenElse(NFSType == "lustre", strcat("tcp:/lustrefs", NFSSharedExportPath), NFSSharedExportPath)}
+ address = $NFSAddress
+ options = $NFSSharedMountOptions
+
+ [[[configuration cyclecloud.mounts.nfs_sched]]]
+ type = $NFSSchedType
+ mountpoint = /sched
+ export_path = ${ifThenElse(NFSSchedType == "lustre", strcat("tcp:/lustrefs", NFSSchedExportPath), NFSSchedExportPath)}
+ address = $NFSSchedAddress
+ options = $NFSSchedMountOptions
+
+ [[[configuration cyclecloud.mounts.additional_nfs]]]
+ disabled = ${AdditionalNFS isnt true}
+ type = $AdditionalNFSType
+ address = $AdditionalNFSAddress
+ mountpoint = $AdditionalNFSMountPoint
+ export_path = ${ifThenElse(AdditionalNFSType == "lustre", strcat("tcp:/lustrefs", AdditionalNFSExportPath), AdditionalNFSExportPath)}
+ options = $AdditionalNFSMountOptions
+
+ [[node nodearraybase]]
+ Abstract = true
+ [[[configuration]]]
+ slurm.autoscale = true
+
+ slurm.node_prefix = ${ifThenElse(NodeNamePrefix=="Cluster Prefix", StrJoin("-", ClusterName, ""), NodeNamePrefix)}
+ slurm.use_nodename_as_hostname = $NodeNameIsHostname
+
+ [[[cluster-init slurm:execute:3.0.9]]]
+
+ [[[network-interface eth0]]]
+ AssociatePublicIpAddress = $ExecuteNodesPublic
+
+ [[nodearray hpc]]
+ Extends = nodearraybase
+ MachineType = $HPCMachineType
+ ImageName = $HPCImageName
+ MaxCoreCount = $MaxHPCExecuteCoreCount
+ Azure.MaxScalesetSize = $HPCMaxScalesetSize
+ AdditionalClusterInitSpecs = $HPCClusterInitSpecs
+ EnableNodeHealthChecks = $EnableNodeHealthChecks
+
+
+ [[[configuration]]]
+ slurm.default_partition = true
+ slurm.hpc = true
+ slurm.partition = hpc
+
+
+ [[nodearray htc]]
+ Extends = nodearraybase
+ MachineType = $HTCMachineType
+ ImageName = $HTCImageName
+ MaxCoreCount = $MaxHTCExecuteCoreCount
+
+ Interruptible = $HTCUseLowPrio
+ MaxPrice = $HTCSpotMaxPrice
+ AdditionalClusterInitSpecs = $HTCClusterInitSpecs
+
+ [[[configuration]]]
+ slurm.hpc = false
+ slurm.partition = htc
+ # set pcpu = false for all hyperthreaded VMs
+ slurm.use_pcpu = false
+
+[parameters About]
+Order = 1
+
+ [[parameters About Slurm]]
+
+ [[[parameter slurm]]]
+ HideLabel = true
+ Config.Plugin = pico.widget.HtmlTemplateWidget
+ Config.Template = '''
 |
Follow the instructions in theREADMEfor details on instructions on extending and configuring the Project for your environment.
|
Slurm is the most widely used workload manager in HPC, as the scheduler of choice for six of the top ten systems in the TOP500 and with market penetration of more than 70%. Slurm is an advanced, open-source scheduler designed to satisfy the demanding needs of high-performance computing (HPC), high-throughput computing (HTC), and artificial intelligence (AI). |
Commercial Support provided by SchedMD |
Get more from your HPC investment! SchedMD, the company behind Slurm development, can answer your Slurm questions and explain our options for consultation, training, support, and migration. Contact SchedMD |
View more details about Slurm?
Slurm at a glance |
Slurm provides massive scalability and can easily manage performance requirements for small cluster, large cluster, and supercomputer needs. Slurm outperforms competitive schedulers with compute rates at: |
- 100K+ nodes/GPU
- 17M+ jobs per day
- 120M+ jobs per week
|
Slurm’s plug-in based architecture enables optimization and control in scheduling operations to meet organizational priorities. With first class resource management for GPUs, Slurm allows users to request GPU resources alongside CPUs. This flexibility ensures that jobs are executed quickly and efficiently, while maximizing resource utilization.
|
Other Slurm features include: |
- NVIDIA and AMD GPU support for AI, LLM, and ML environments
- Advanced scheduling policies
- Unique HPC, HTC, AI/ML workload expertise
- Cloud bursting capabilities
- Power saving capabilities, accounting, and reporting
- Provided REST API daemon
- Native support of containers
- Tailored Slurm consulting and training available through SchedMD
|
'''
+
+[parameters Required Settings]
+Order = 10
+
+
+ [[parameters Virtual Machines ]]
+ Description = "The cluster, in this case, has two roles: the scheduler node with shared filer and the execute hosts. Configure which VM types to use based on the requirements of your application."
+ Order = 20
+
+ [[[parameter Region]]]
+ Label = Region
+ Description = Deployment Location
+ ParameterType = Cloud.Region
+
+ [[[parameter HPCMachineType]]]
+ Label = HPC VM Type
+ Description = The VM type for HPC execute nodes
+ ParameterType = Cloud.MachineType
+ DefaultValue = Standard_F2s_v2
+
+ [[[parameter HTCMachineType]]]
+ Label = HTC VM Type
+ Description = The VM type for HTC execute nodes
+ ParameterType = Cloud.MachineType
+ DefaultValue = Standard_F2s_v2
+
+
+ [[parameters Auto-Scaling]]
+ Description = "The cluster can autoscale to the workload, adding execute hosts as jobs are queued. To enable this check the box below and choose the initial and maximum core counts for the cluster."
+ Order = 30
+
+ [[[parameter Autoscale]]]
+ Label = Autoscale
+ DefaultValue = true
+ Widget.Plugin = pico.form.BooleanCheckBox
+ Widget.Label = Start and stop execute instances automatically
+
+ [[[parameter MaxHPCExecuteCoreCount]]]
+ Label = Max HPC Cores
+ Description = The total number of HPC execute cores to start
+ DefaultValue = 100
+ Config.Plugin = pico.form.NumberTextBox
+ Config.MinValue = 1
+ Config.IntegerOnly = true
+
+ [[[parameter MaxHTCExecuteCoreCount]]]
+ Label = Max HTC Cores
+ Description = The total number of HTC execute cores to start
+ DefaultValue = 100
+ Config.Plugin = pico.form.NumberTextBox
+ Config.MinValue = 1
+ Config.IntegerOnly = true
+
+
+ [[[parameter HPCMaxScalesetSize]]]
+ Label = Max VMs per VMSS
+ Description = The maximum number of VMs created per VM Scaleset e.g. switch in Slurm.
+ DefaultValue = 100
+ Config.Plugin = pico.form.NumberTextBox
+ Config.MinValue = 1
+ Config.IntegerOnly = true
+
+
+ [[[parameter HTCUseLowPrio]]]
+ Label = HTC Spot
+ DefaultValue = false
+ Widget.Plugin = pico.form.BooleanCheckBox
+ Widget.Label = Use Spot VMs for HTC execute hosts
+
+ [[[parameter HTCSpotMaxPrice]]]
+ Label = Max Price HTC
+ DefaultValue = -1
+ Description = Max price for Spot VMs in USD (value of -1 will not evict based on price)
+ Config.Plugin = pico.form.NumberTextBox
+ Conditions.Excluded := HTCUseLowPrio isnt true
+ Config.MinValue = -1
+
+ [[parameters Networking]]
+ Order = 40
+
+ [[[parameter SubnetId]]]
+ Label = Subnet ID
+ Description = Subnet Resource Path (ResourceGroup/VirtualNetwork/Subnet)
+ ParameterType = Azure.Subnet
+ Required = True
+
+
+[parameters Network Attached Storage]
+Order = 15
+
+ [[parameters Shared Storage]]
+ Order = 10
+
+ [[[parameter About Shared Storage]]]
+ HideLabel = true
+ Config.Plugin = pico.widget.HtmlTemplateWidget
+ Config.Template = '''The directories /sched and /shared are network attached mounts and exist on all nodes of the cluster.
+
+ Options for providing these mounts:
+ [Builtin]: The scheduler node is an NFS server that provides the mountpoint to the other nodes of the cluster (not supported for HA configurations).
+ [External NFS]: A network attached storage such as Azure Netapp Files, HPC Cache, or another VM running an NFS server provides the mountpoint.
+ [Azure Managed Lustre]: An Azure Managed Lustre deployment provides the mountpoint.
+
+
+ Note: the cluster must be terminated for changes to filesystem mounts to take effect.
+
'''
+ Conditions.Hidden := false
+
+ [[parameters Scheduler Mount]]
+ Order = 20
+ Label = File-system Mount for /sched
+
+ [[[parameter About sched]]]
+ HideLabel = true
+ Config.Plugin = pico.widget.HtmlTemplateWidget
+ Config.Template = ''' Slurm's configuration is linked in from the /sched directory. It is managed by the scheduler node
'''
+ Order = 6
+
+ [[[parameter About sched part 2]]]
+ HideLabel = true
+ Config.Plugin = pico.widget.HtmlTemplateWidget
+ Config.Template = ''' To disable the built-in NFS export of the /sched directory, and to use an external filesystem, select the checkbox below.
'''
+ Order = 7
+ Conditions.Hidden := configuration_slurm_ha_enabled
+
+ [[[parameter UseBuiltinSched]]]
+ Label = Use Builtin NFS
+ Description = Use the builtin NFS for /sched
+ DefaultValue = false
+ ParameterType = Boolean
+ Conditions.Hidden := configuration_slurm_ha_enabled
+ Disabled = configuration_slurm_ha_enabled
+
+ [[[parameter NFSSchedDiskWarning]]]
+ HideLabel = true
+ Config.Plugin = pico.widget.HtmlTemplateWidget
+ Config.Template := "Warning: switching an active cluster over to NFS or Lustre from Builtin will delete the shared disk.
"
+ Conditions.Hidden := UseBuiltinSched || configuration_slurm_ha_enabled
+
+ [[[parameter NFSSchedType]]]
+ Label = FS Type
+ ParameterType = StringList
+ Config.Label = Type of shared filesystem to use for this cluster
+ Config.Plugin = pico.form.Dropdown
+ Config.Entries := {[Label="External NFS"; Value="nfs"], [Label="Azure Managed Lustre"; Value="lustre"]}
+ DefaultValue = nfs
+ Conditions.Hidden := UseBuiltinSched && !configuration_slurm_ha_enabled
+
+ [[[parameter NFSSchedAddress]]]
+ Label = IP Address
+ Description = The IP address or hostname of the NFS server or Lustre FS. Also accepts a list comma-separated addresses, for example, to mount a frontend load-balanced Azure HPC Cache.
+ Config.ParameterType = String
+ Conditions.Hidden := UseBuiltinSched && !configuration_slurm_ha_enabled
+
+ [[[parameter NFSSchedExportPath]]]
+ Label = Export Path
+ Description = The path exported by the file system
+ DefaultValue = /sched
+ Conditions.Hidden := UseBuiltinSched && !configuration_slurm_ha_enabled
+
+ [[[parameter NFSSchedMountOptions]]]
+ Label = Mount Options
+ Description = NFS Client Mount Options
+ Conditions.Hidden := UseBuiltinSched && !configuration_slurm_ha_enabled
+
+
+ [[[parameter SchedFilesystemSize]]]
+ Label = Size (GB)
+ Description = The filesystem size (cannot be changed after initial start)
+ DefaultValue = 30
+ Config.Plugin = pico.form.NumberTextBox
+ Config.MinValue = 10
+ Config.MaxValue = 10240
+ Config.IntegerOnly = true
+ Conditions.Excluded := !UseBuiltinSched || configuration_slurm_ha_enabled
+
+
+
+ [[parameters Default NFS Share]]
+ Order = 30
+ Label = File-system Mount for /shared
+
+ [[[parameter About shared]]]
+ HideLabel = true
+ Config.Plugin = pico.widget.HtmlTemplateWidget
+ Config.Template = ''' Users' home directories reside within the /shared mountpoint with the base homedir /shared/home.
'''
+ Order = 6
+
+ [[[parameter About shared part 2]]]
+ HideLabel = true
+ Config.Plugin = pico.widget.HtmlTemplateWidget
+ Config.Template = ''' To disable the built-in NFS export of the /shared directory, and to use an external filesystem, select the checkbox below.
'''
+ Order = 7
+ Conditions.Hidden := configuration_slurm_ha_enabled
+
+ [[[parameter UseBuiltinShared]]]
+ Label = Use Builtin NFS
+ Description = Use the builtin NFS for /share
+ DefaultValue = false
+ ParameterType = Boolean
+ Conditions.Hidden := configuration_slurm_ha_enabled
+ Disabled = configuration_slurm_ha_enabled
+
+ [[[parameter NFSDiskWarning]]]
+ HideLabel = true
+ Config.Plugin = pico.widget.HtmlTemplateWidget
+ Config.Template := "Warning: switching an active cluster over to NFS or Lustre from Builtin will delete the shared disk.
"
+ Conditions.Hidden := UseBuiltinShared || configuration_slurm_ha_enabled
+
+ [[[parameter NFSType]]]
+ Label = FS Type
+ ParameterType = StringList
+ Config.Label = Type of shared filesystem to use for this cluster
+ Config.Plugin = pico.form.Dropdown
+ Config.Entries := {[Label="External NFS"; Value="nfs"], [Label="Azure Managed Lustre"; Value="lustre"]}
+ DefaultValue = nfs
+ Conditions.Hidden := UseBuiltinShared && !configuration_slurm_ha_enabled
+
+ [[[parameter NFSAddress]]]
+ Label = IP Address
+ Description = The IP address or hostname of the NFS server or Lustre FS. Also accepts a list comma-separated addresses, for example, to mount a frontend load-balanced Azure HPC Cache.
+ Config.ParameterType = String
+ Conditions.Hidden := UseBuiltinShared && !configuration_slurm_ha_enabled
+
+ [[[parameter NFSSharedExportPath]]]
+ Label = Export Path
+ Description = The path exported by the file system
+ DefaultValue = /shared
+ Conditions.Hidden := UseBuiltinShared && !configuration_slurm_ha_enabled
+
+ [[[parameter NFSSharedMountOptions]]]
+ Label = Mount Options
+ Description = NFS Client Mount Options
+ Conditions.Hidden := UseBuiltinShared && !configuration_slurm_ha_enabled
+
+
+ [[[parameter FilesystemSize]]]
+ Label = Size (GB)
+ Description = The filesystem size (cannot be changed after initial start)
+ DefaultValue = 100
+ Config.Plugin = pico.form.NumberTextBox
+ Config.MinValue = 10
+ Config.MaxValue = 10240
+ Config.IntegerOnly = true
+ Conditions.Excluded := !UseBuiltinShared || configuration_slurm_ha_enabled
+
+ [[parameters Additional NFS Mount]]
+ Order = 40
+ Label = Additional Filesystem Mount
+ [[[parameter Additional Shared FS Mount Readme]]]
+ HideLabel = true
+ Config.Plugin = pico.widget.HtmlTemplateWidget
+ Config.Template := "Mount another shared filesystem endpoint on the cluster nodes.
"
+ Order = 20
+
+ [[[parameter AdditionalNFS]]]
+ HideLabel = true
+ DefaultValue = false
+ Widget.Plugin = pico.form.BooleanCheckBox
+ Widget.Label = Add Shared Filesystem mount
+
+ [[[parameter AdditionalNFSType]]]
+ Label = FS Type
+ ParameterType = StringList
+ Config.Label = Shared filesystem type of the additional mount
+ Config.Plugin = pico.form.Dropdown
+ Config.Entries := {[Label="External NFS"; Value="nfs"], [Label="Azure Managed Lustre"; Value="lustre"]}
+ DefaultValue = nfs
+ Conditions.Excluded := AdditionalNFS isnt true
+
+ [[[parameter AdditionalNFSAddress]]]
+ Label = IP Address
+ Description = The IP address or hostname of the additional mount. Also accepts a list comma-separated addresses, for example, to mount a frontend load-balanced Azure HPC Cache.
+ Config.ParameterType = String
+ Conditions.Excluded := AdditionalNFS isnt true
+
+ [[[parameter AdditionalNFSMountPoint]]]
+ Label = Mount Point
+ Description = The path at which to mount the Filesystem
+ DefaultValue = /data
+ Conditions.Excluded := AdditionalNFS isnt true
+
+ [[[parameter AdditionalNFSExportPath]]]
+ Label = Export Path
+ Description = The path exported by the file system
+ DefaultValue = /data
+ Conditions.Excluded := AdditionalNFS isnt true
+
+ [[[parameter AdditionalNFSMountOptions]]]
+ Label = Mount Options
+ Description = Filesystem Client Mount Options
+ Conditions.Excluded := AdditionalNFS isnt true
+
+
+[parameters Advanced Settings]
+Order = 20
+
+ [[parameters Azure Settings]]
+ Order = 10
+
+ [[[parameter Credentials]]]
+ Description = The credentials for the cloud provider
+ ParameterType = Cloud.Credentials
+
+ [[[parameter ManagedIdentity]]]
+ Label = Managed Id
+ Description = Optionally assign an Azure user assigned managed identity to all nodes to access Azure resources using assigned roles.
+ ParameterType = Azure.ManagedIdentity
+ DefaultValue = =undefined
+
+ [[[parameter BootDiskSize]]]
+ Description = Optional: Size of the OS/boot disk in GB for all nodes in the cluster (leave at 0 to use Image size)
+ ParameterType = Integer
+ Config.Plugin = pico.form.NumberTextBox
+ Config.MinValue = 0
+ Config.MaxValue = 32,000
+ Config.IntegerOnly = true
+ Config.Increment = 64
+ DefaultValue = 0
+
+ [[parameters Slurm Settings ]]
+
+ Order = 5
+
+ [[[parameter slurm_version_warning]]]
+ HideLabel = true
+ Config.Plugin = pico.widget.HtmlTemplateWidget
+ Config.Template := "| Note: For SLES HPC, we can only install the version supported by SLES HPC's zypper repos. At the time of this release, that is 23.02.7 |
"
+
+
+ [[[parameter configuration_slurm_version]]]
+ Required = True
+ Label = Slurm Version
+ Description = Version of Slurm to install on the cluster
+ ParameterType = StringList
+ Config.Plugin = pico.form.Dropdown
+ Config.FreeForm = true
+ Config.Entries := {[Value="23.11.9-1"]}
+ DefaultValue = 23.11.9-1
+
+
+ [[[parameter configuration_slurm_shutdown_policy]]]
+ Label = Shutdown Policy
+ description = By default, autostop will Delete stopped VMS for lowest cost. Optionally, Stop/Deallocate the VMs for faster restart instead.
+ DefaultValue = Terminate
+ config.plugin = pico.control.AutoCompleteDropdown
+ [[[[list Config.Entries]]]]
+ Name = Terminate
+ Label = Terminate
+ [[[[list Config.Entries]]]]
+ Name = Deallocate
+ Label = Deallocate
+
+ [[[parameter EnableTerminateNotification]]]
+ Label = Enable Termination notifications
+ DefaultValue = False
+
+
+ [[parameters Software]]
+ Description = "Specify the scheduling software, and base OS installed on all nodes, and optionally the cluster-init and chef versions from your locker."
+ Order = 10
+
+ [[[parameter NodeNameIsHostname]]]
+ Label = Name As Hostname
+ Description = Should the hostname match the nodename for execute nodes?
+ ParameterType = Boolean
+ DefaultValue = true
+
+ [[[parameter NodeNamePrefix]]]
+ Label = Node Prefix
+ Description = Prefix for generated node names, i.e. "prefix-" generates prefix-nodearray-1. Use 'Cluster Prefix' to get $ClusterName-nodearray-1
+ ParameterType = StringList
+ Config.Plugin = pico.form.Dropdown
+ Config.FreeForm = true
+ DefaultValue = "Cluster Prefix"
+ Config.Entries := {[Value=""], [Value="Cluster Prefix"]}
+ Conditions.Hidden := NodeNameIsHostname != true
+
+
+ [[[parameter HPCImageName]]]
+ Label = HPC OS
+ ParameterType = Cloud.Image
+ Config.OS = linux
+ DefaultValue = almalinux8
+ Config.Filter := Package in {"cycle.image.ubuntu22", "almalinux8"}
+
+ [[[parameter HTCImageName]]]
+ Label = HTC OS
+ ParameterType = Cloud.Image
+ Config.OS = linux
+ DefaultValue = almalinux8
+ Config.Filter := Package in {"cycle.image.ubuntu22", "almalinux8"}
+
+
+ [[[parameter HTCClusterInitSpecs]]]
+ Label = HTC Cluster-Init
+ DefaultValue = =undefined
+ Description = Cluster init specs to apply to HTC execute nodes
+ ParameterType = Cloud.ClusterInitSpecs
+
+ [[[parameter HPCClusterInitSpecs]]]
+ Label = HPC Cluster-Init
+ DefaultValue = =undefined
+ Description = Cluster init specs to apply to HPC execute nodes
+ ParameterType = Cloud.ClusterInitSpecs
+
+
+ [[[parameter configuration_slurm_disable_pmc]]]
+ Label = Disable PMC
+ Description = Disable packages from packages.microsoft.com
+ ParameterType = Boolean
+ DefaultValue = true
+
+
+ [[parameters Advanced Networking]]
+
+ [[[parameter ReturnProxy]]]
+ Label = Return Proxy
+ DefaultValue = false
+ ParameterType = Boolean
+ Config.Label = Use SSH tunnel to connect to CycleCloud (required if direct access is blocked)
+
+ [[[parameter UsePublicNetwork]]]
+ Label = Public Head Node
+ DefaultValue = false
+ ParameterType = Boolean
+ Config.Label = Access scheduler node from the Internet
+
+ [[[parameter ExecuteNodesPublic]]]
+ Label = Public Execute
+ DefaultValue = false
+ ParameterType = Boolean
+ Config.Label = Access execute nodes from the Internet
+
+
+ [[parameters Node Health Checks]]
+ Description = "Section for configuring Node Health Checks"
+ Order = 12
+
+ [[[parameter EnableNodeHealthChecks]]]
+ Label = Enable NHC tests
+ DefaultValue = false
+ Widget.Plugin = pico.form.BooleanCheckBox
+ Widget.Label = Run Node Health Checks on startup
diff --git a/cloud_bursting/slurm-23.11.9-1/scheduler/cyclecloud-integrator.sh b/cloud_bursting/slurm-23.11.9-1/scheduler/cyclecloud-integrator.sh
new file mode 100644
index 00000000..921aa219
--- /dev/null
+++ b/cloud_bursting/slurm-23.11.9-1/scheduler/cyclecloud-integrator.sh
@@ -0,0 +1,115 @@
+#!/bin/bash
+# -----------------------------------------------------------------------------
+# Script: Install CycleCloud Autoscaler and Integrate with Slurm Scheduler
+#
+# This script automates the installation of the CycleCloud Autoscaler package,
+# a key component used to dynamically scale compute resources in a cluster managed
+# by the CycleCloud environment. It integrates with the Slurm scheduler to ensure
+# efficient scaling based on workload demands.
+#
+# Key Features:
+# - Installs the CycleCloud Autoscaler package.
+# - Configures integration with the Slurm workload manager for automated scaling.
+# - Ensures that the compute resources in the cluster can scale up or down based
+# on the job queue and resource usage, optimizing both performance and cost.
+#
+# Prerequisites:
+# - Root or sudo privileges are required to execute the installation steps.
+# - Slurm scheduler should already be set up in the environment.
+#
+# Usage:
+# sh cyclecloud-integrator.sh
+# -----------------------------------------------------------------------------
+set -e
+if [ $(whoami) != root ]; then
+ echo "Please run as root"
+ exit 1
+fi
+
+
+# Prompt user to enter CycleCloud details for Slurm scheduler integration
+echo "Please enter the CycleCloud details to integrate with the Slurm scheduler"
+echo " "
+# Prompt for Cluster Name
+read -p "Enter Cluster Name: " cluster_name
+
+# Prompt for Username
+read -p "Enter CycleCloud Username: " username
+
+# Prompt for Password (masked input)
+echo -n "Enter CycleCloud password: "
+stty -echo # Turn off echo
+read password
+stty echo # Turn echo back on
+echo
+echo "Password entered."
+# Prompt for URL
+read -p "Enter CycleCloud IP (e.g.,10.222.1.19): " ip
+url="https://$ip"
+
+# Display summary of entered details
+echo "------------------------------------------------------------------------------------------------------------------------------"
+echo " "
+echo "Summary of entered details:"
+echo "Cluster Name: $cluster_name"
+echo "CycleCloud Username: $username"
+echo "CycleCloud URL: $url"
+echo " "
+echo "------------------------------------------------------------------------------------------------------------------------------"
+
+# Define variables
+
+slurm_autoscale_pkg_version="3.0.9"
+slurm_autoscale_pkg="azure-slurm-pkg-$slurm_autoscale_pkg_version.tar.gz"
+slurm_script_dir="/opt/azurehpc/slurm"
+config_dir="/sched/$cluster_name"
+
+# Create necessary directories
+mkdir -p "$slurm_script_dir"
+
+# Activate Python virtual environment for Slurm integration
+echo "------------------------------------------------------------------------------------------------------------------------------"
+echo "Configuring virtual enviornment and Activating Python virtual environment"
+echo "------------------------------------------------------------------------------------------------------------------------------"
+python3 -m venv "$slurm_script_dir/venv"
+. "$slurm_script_dir/venv/bin/activate"
+
+# Download and install CycleCloud Slurm integration package
+echo "------------------------------------------------------------------------------------------------------------------------------"
+echo "Downloading and installing CycleCloud Slurm integration package"
+echo "------------------------------------------------------------------------------------------------------------------------------"
+
+wget https://github.com/Azure/cyclecloud-slurm/releases/download/$slurm_autoscale_pkg_version/$slurm_autoscale_pkg -P "$slurm_script_dir"
+tar -xvf "$slurm_script_dir/$slurm_autoscale_pkg" -C "$slurm_script_dir"
+cd "$slurm_script_dir/azure-slurm"
+head -n -30 install.sh > integrate-cc.sh
+chmod +x integrate-cc.sh
+./integrate-cc.sh
+#cleanup
+rm -rf azure-slurm*
+
+# Initialize autoscaler configuration
+echo "------------------------------------------------------------------------------------------------------------------------------"
+echo "Initializing autoscaler configuration"
+echo "------------------------------------------------------------------------------------------------------------------------------"
+
+azslurm initconfig --username "$username" --password "$password" --url "$url" --cluster-name "$cluster_name" --config-dir "$config_dir" --default-resource '{"select": {}, "name": "slurm_gpus", "value": "node.gpu_count"}' > "$slurm_script_dir/autoscale.json"
+chown slurm:slurm "$slurm_script_dir/autoscale.json"
+chown -R slurm:slurm "$slurm_script_dir"
+# Connect and scale
+echo "------------------------------------------------------------------------------------------------------------------------------"
+echo "Connecting to CycleCloud and scaling resources"
+echo "------------------------------------------------------------------------------------------------------------------------------"
+
+azslurm connect
+azslurm scale --no-restart
+chown -R slurm:slurm "$slurm_script_dir"/logs/*.log
+
+systemctl restart munge
+systemctl restart slurmctld
+echo " "
+echo "------------------------------------------------------------------------------------------------------------------------------"
+echo "Slurm scheduler integration with CycleCloud completed successfully"
+echo " Create User and Group for job submission. Make sure that GID and UID is consistent across all nodes and home directory is shared"
+echo "------------------------------------------------------------------------------------------------------------------------------"
+echo " "
\ No newline at end of file
diff --git a/cloud_bursting/slurm-23.11.9-1/scheduler/slurm-scheduler-builder.sh b/cloud_bursting/slurm-23.11.9-1/scheduler/slurm-scheduler-builder.sh
new file mode 100644
index 00000000..15bedfbc
--- /dev/null
+++ b/cloud_bursting/slurm-23.11.9-1/scheduler/slurm-scheduler-builder.sh
@@ -0,0 +1,387 @@
+#!/bin/sh
+# -----------------------------------------------------------------------------
+# Script: Install and Configure Slurm Scheduler
+#
+# This script automates the installation and configuration of the Slurm scheduler
+# on your VM or machine. It sets up the Slurm software to manage and schedule
+# workloads efficiently across the available resources in your environment.
+#
+# Key Features:
+# - Installs and configures Slurm software on your VM or machine.
+# - Sets up the Slurm configuration to manage compute resources.
+#
+# Prerequisites:
+# - Root or sudo privileges are required to run the script.
+#
+# Usage:
+# # sh slurm-scheduler-builder.sh
+# -----------------------------------------------------------------------------
+
+
+set -e
+if [ $(whoami) != root ]; then
+ echo "Please run as root"
+ exit 1
+fi
+
+# Check if the script is running on a supported OS with the required version of almaLinux 8.7 or Ubuntu 22.04
+
+# Check if /etc/os-release exists
+if [ ! -e /etc/os-release ]; then
+ echo "This script only supports AlmaLinux 8.7 or Ubuntu 22.04"
+ exit 1
+fi
+
+# Source /etc/os-release to get OS information
+. /etc/os-release
+
+# Check OS name and version
+if { [ "$ID" = "almalinux" ] && [ "$VERSION_ID" = "8.7" ]; } || \
+ { [ "$ID" = "ubuntu" ] && [ "$VERSION_ID" = "22.04" ]; }; then
+ echo "OS version is supported."
+else
+ echo "This script only supports AlmaLinux 8.7 or Ubuntu 22.04"
+ exit 1
+fi
+
+echo "------------------------------------------------------------------------------------------------------------------------------"
+echo "Building Slurm scheduler for cloud bursting with Azure CycleCloud"
+echo "------------------------------------------------------------------------------------------------------------------------------"
+echo " "
+# Prompt for Cluster Name
+read -p "Enter Cluster Name: " cluster_name
+
+ip_address=$(hostname -I | awk '{print $1}')
+echo "------------------------------------------------------------------------------------------------------------------------------"
+echo " "
+echo "Summary of entered details:"
+echo "Cluster Name: $cluster_name"
+echo "Scheduler Hostname: $(hostname)"
+echo "NFSServer IP Address: $ip_address"
+echo " "
+echo "------------------------------------------------------------------------------------------------------------------------------"
+
+sched_dir="/sched/$cluster_name"
+slurm_conf="$sched_dir/slurm.conf"
+munge_key="/etc/munge/munge.key"
+slurm_script_dir="/opt/azurehpc/slurm"
+OS_ID=$(cat /etc/os-release | grep ^ID= | cut -d= -f2 | cut -d\" -f2 | cut -d. -f1)
+OS_VERSION=$(cat /etc/os-release | grep VERSION_ID | cut -d= -f2 | cut -d\" -f2)
+SLURM_VERSION="23.11.9-1"
+
+# Create directories
+mkdir -p "$sched_dir"
+
+# Create Munge and Slurm users
+echo "------------------------------------------------------------------------------------------------------------------------------"
+echo "Creating Munge and Slurm users"
+echo "------------------------------------------------------------------------------------------------------------------------------"
+
+#check if the users already exist
+#uid 11100 is used for slurm and 11101 is used for munge in cyclecloud
+
+# Function to check and create a user and group
+create_user_and_group() {
+ username=$1
+ uid=$2
+ gid=$3
+
+ if id "$username" >/dev/null 2>&1; then
+ echo "$username user already exists"
+ else
+ echo "Creating $username user and group..."
+ groupadd -g "$gid" "$username"
+ useradd -u "$uid" -g "$gid" -s /bin/false -M "$username"
+ echo "$username user and group created"
+ fi
+}
+
+# Check and create 'munge' user and group if necessary
+create_user_and_group "munge" 11101 11101
+
+# Check and create 'slurm' user and group if necessary
+create_user_and_group "slurm" 11100 11100
+
+# Set up NFS server
+echo "------------------------------------------------------------------------------------------------------------------------------"
+echo "Setting up NFS server"
+echo "------------------------------------------------------------------------------------------------------------------------------"
+if [ "$OS_ID" = "almalinux" ]; then
+ dnf install -y nfs-utils
+elif [ "$OS_ID" = "ubuntu" ]; then
+ apt-get install -y nfs-kernel-server
+fi
+mkdir -p /sched /shared
+echo "/sched *(rw,sync,no_root_squash)" >> /etc/exports
+echo "/shared *(rw,sync,no_root_squash)" >> /etc/exports
+systemctl restart nfs-server.service
+systemctl enable nfs-server.service
+echo "NFS server setup complete"
+showmount -e localhost
+
+# setting up Microsoft repo
+# Set up Microsoft repository based on the OS
+echo "Setting up Microsoft repo"
+
+# Check if OS is AlmaLinux
+if [ "$OS_ID" = "almalinux" ]; then
+ echo "Detected AlmaLinux"
+ if [ ! -e /etc/yum.repos.d/microsoft-prod.repo ]; then
+ echo "Downloading and installing Microsoft repo for AlmaLinux..."
+ curl -sSL -O https://packages.microsoft.com/config/rhel/$(echo "$OS_VERSION" | cut -d. -f1)/packages-microsoft-prod.rpm
+ rpm -i packages-microsoft-prod.rpm
+ rm -f packages-microsoft-prod.rpm
+ echo "Microsoft repo setup complete for AlmaLinux"
+ else
+ echo "Microsoft repo already exists on AlmaLinux"
+ fi
+
+# Check if OS is Ubuntu
+elif [ "$OS_ID" = "ubuntu" ]; then
+ echo "Detected Ubuntu"
+ if [ ! -e /etc/apt/sources.list.d/microsoft-prod.list ]; then
+ echo "Downloading and installing Microsoft repo for Ubuntu..."
+ curl -sSL -O https://packages.microsoft.com/config/ubuntu/$OS_VERSION/packages-microsoft-prod.deb
+ dpkg -i packages-microsoft-prod.deb
+ rm -f packages-microsoft-prod.deb
+ echo "Microsoft repo setup complete for Ubuntu"
+ else
+ echo "Microsoft repo already exists on Ubuntu"
+ fi
+
+# If OS is neither AlmaLinux nor Ubuntu
+else
+ echo "Unsupported OS: $OS_ID"
+ exit 1
+fi
+
+# Install and configure Munge
+echo "------------------------------------------------------------------------------------------------------------------------------"
+echo "Installing and configuring Munge"
+echo "------------------------------------------------------------------------------------------------------------------------------"
+if [ "$OS_ID" = "almalinux" ]; then
+ dnf install -y epel-release
+ dnf install -y munge munge-libs
+elif [ "$OS_ID" = "ubuntu" ]; then
+ apt-get update
+ apt-get install -y munge
+else
+ echo "Unsupported OS: $OS_ID"
+ exit 1
+fi
+
+# Generate the munge key and set proper permissions
+dd if=/dev/urandom bs=1 count=1024 of="$munge_key"
+chown munge:munge "$munge_key"
+chmod 400 "$munge_key"
+
+# Start and enable the munge service
+systemctl start munge
+systemctl enable munge
+
+# Copy the munge key to the sched directory
+cp "$munge_key" "$sched_dir/munge.key"
+chown munge: "$sched_dir/munge.key"
+chmod 400 "$sched_dir/munge.key"
+
+echo "------------------------------------------------------------------------------------------------------------------------------"
+echo "Munge installed and configured"
+echo "------------------------------------------------------------------------------------------------------------------------------"
+
+# Install and configure Slurm
+echo "------------------------------------------------------------------------------------------------------------------------------"
+echo "Installing Slurm"
+echo "------------------------------------------------------------------------------------------------------------------------------"
+
+# Installing Slurm on AlmaLinux
+if [ "$OS_ID" = "almalinux" ]; then
+ echo "Installing Slurm on AlmaLinux"
+ echo "Setting up Slurm repository..."
+
+ # Create Slurm repository file for AlmaLinux
+ cat < /etc/yum.repos.d/slurm.repo
+[slurm]
+name=Slurm Workload Manager
+baseurl=https://packages.microsoft.com/yumrepos/slurm-el8-insiders
+enabled=1
+gpgcheck=1
+gpgkey=https://packages.microsoft.com/keys/microsoft.asc
+priority=10
+EOF
+
+ echo "Slurm repository setup complete."
+ echo "------------------------------------------------------------------------------------------------------------------------------"
+ echo "Installing Slurm packages"
+ echo "------------------------------------------------------------------------------------------------------------------------------"
+
+ # List of Slurm packages to install
+ slurm_packages="slurm slurm-slurmrestd slurm-libpmi slurm-devel slurm-pam_slurm slurm-perlapi slurm-torque slurm-openlava slurm-example-configs"
+ sched_packages="slurm-slurmctld slurm-slurmdbd"
+
+ # Install Slurm packages on AlmaLinux
+ OS_MAJOR_VERSION=$(echo "$OS_VERSION" | cut -d. -f1)
+ for pkg in $slurm_packages; do
+ yum -y install $pkg-${SLURM_VERSION}.el${OS_MAJOR_VERSION} --disableexcludes=slurm
+ done
+ for pkg in $sched_packages; do
+ yum -y install $pkg-${SLURM_VERSION}.el${OS_MAJOR_VERSION} --disableexcludes=slurm
+ done
+
+# Installing Slurm on Ubuntu
+elif [ "$OS_ID" = "ubuntu" ]; then
+ echo "Installing Slurm on Ubuntu"
+ REPO="slurm-ubuntu-jammy"
+
+ echo "Setting up Slurm repository for Ubuntu..."
+ # Add Slurm repository
+ echo "deb [arch=amd64] https://packages.microsoft.com/repos/$REPO/ insiders main" > /etc/apt/sources.list.d/slurm.list
+
+ # Set package pinning preferences
+ echo "\
+Package: slurm, slurm-*
+Pin: origin \"packages.microsoft.com\"
+Pin-Priority: 990
+
+Package: slurm, slurm-*
+Pin: origin *ubuntu.com*
+Pin-Priority: -1" > /etc/apt/preferences.d/slurm-repository-pin-990
+
+ echo "Slurm repository setup completed."
+ echo "------------------------------------------------------------------------------------------------------------------------------"
+ echo "Installing Slurm packages"
+ echo "------------------------------------------------------------------------------------------------------------------------------"
+
+ # Update package lists and install Slurm
+ # remove the need restart prompt for outdated libraries
+ grep -qxF "\$nrconf{restart} = 'a';" /etc/needrestart/conf.d/no-prompt.conf || echo "\$nrconf{restart} = 'a';" | sudo tee -a /etc/needrestart/conf.d/no-prompt.conf > /dev/null
+ apt-get update
+ apt install -y libhwloc15 libmysqlclient-dev libssl-dev jq python3-venv chrony
+ systemctl enable chrony
+ systemctl start chrony
+ slurm_packages="slurm-smd slurm-smd-client slurm-smd-dev slurm-smd-libnss-slurm slurm-smd-libpam-slurm-adopt slurm-smd-slurmrestd slurm-smd-sview slurm-smd-slurmctld slurm-smd-slurmdbd"
+ for pkg in $slurm_packages; do
+ apt-get update
+ DEBIAN_FRONTEND=noninteractive apt install -y $pkg=$SLURM_VERSION
+ DEBIAN_FRONTEND=noninteractive apt-mark hold $pkg
+ done
+
+ # Unsupported OS
+
+else
+ echo "Unsupported OS: $OS_ID"
+ exit 1
+fi
+
+echo "------------------------------------------------------------------------------------------------------------------------------"
+echo "Slurm installation completed."
+echo "------------------------------------------------------------------------------------------------------------------------------"
+
+# Configure Slurm
+echo "------------------------------------------------------------------------------------------------------------------------------"
+echo "Configuring Slurm"
+echo "------------------------------------------------------------------------------------------------------------------------------"
+
+cat < "$slurm_conf"
+MpiDefault=none
+ProctrackType=proctrack/cgroup
+ReturnToService=2
+PropagateResourceLimits=ALL
+SlurmctldPidFile=/var/run/slurmctld.pid
+SlurmdPidFile=/var/run/slurmd.pid
+SlurmdSpoolDir=/var/spool/slurmd
+SlurmUser=slurm
+StateSaveLocation=/var/spool/slurmctld
+SwitchType=switch/none
+TaskPlugin=task/affinity,task/cgroup
+SchedulerType=sched/backfill
+SelectType=select/cons_tres
+GresTypes=gpu
+SelectTypeParameters=CR_Core_Memory
+# We use a "safe" form of the CycleCloud cluster_name throughout slurm.
+# First we lowercase the cluster name, then replace anything
+# that is not letters, digits and '-' with a '-'
+# eg My Cluster == my-cluster
+ClusterName=$cluster_name
+JobAcctGatherType=jobacct_gather/none
+SlurmctldDebug=debug
+SlurmctldLogFile=/var/log/slurmctld/slurmctld.log
+SlurmctldParameters=idle_on_node_suspend
+SlurmdDebug=debug
+SlurmdLogFile=/var/log/slurmd/slurmd.log
+# TopologyPlugin=topology/tree
+# If you use the TopologyPlugin you likely also want to use our
+# job submit plugin so that your jobs run on a single switch
+# or just add --switches 1 to your submission scripts
+# JobSubmitPlugins=lua
+PrivateData=cloud
+PrologSlurmctld=/opt/azurehpc/slurm/prolog.sh
+TreeWidth=65533
+ResumeTimeout=1800
+SuspendTimeout=600
+SuspendTime=300
+ResumeProgram=/opt/azurehpc/slurm/resume_program.sh
+ResumeFailProgram=/opt/azurehpc/slurm/resume_fail_program.sh
+SuspendProgram=/opt/azurehpc/slurm/suspend_program.sh
+SchedulerParameters=max_switch_wait=24:00:00
+# Only used with dynamic node partitions.
+MaxNodeCount=10000
+# This as the partition definitions managed by azslurm partitions > /sched/azure.conf
+Include azure.conf
+# If slurm.accounting.enabled=true this will setup slurmdbd
+# otherwise it will just define accounting_storage/none as the plugin
+Include accounting.conf
+# SuspendExcNodes is managed in /etc/slurm/keep_alive.conf
+# see azslurm keep_alive for more information.
+# you can also remove this import to remove support for azslurm keep_alive
+Include keep_alive.conf
+EOF
+
+# Configure Hostname in slurmd.conf
+echo "SlurmctldHost=$(hostname -s)" >> "$slurm_conf"
+
+# Create cgroup.conf
+cat < "$sched_dir/cgroup.conf"
+CgroupAutomount=no
+ConstrainCores=yes
+ConstrainRamSpace=yes
+ConstrainDevices=yes
+EOF
+
+echo "# Do not edit this file. It is managed by azslurm" >> "$sched_dir/keep_alive.conf"
+
+# Set limits for Slurm
+cat < /etc/security/limits.d/slurm-limits.conf
+* soft memlock unlimited
+* hard memlock unlimited
+EOF
+
+# Add accounting configuration
+echo "AccountingStorageType=accounting_storage/none" >> "$sched_dir/accounting.conf"
+
+# Set permissions and create symlinks
+
+ln -s "$slurm_conf" /etc/slurm/slurm.conf
+ln -s "$sched_dir/keep_alive.conf" /etc/slurm/keep_alive.conf
+ln -s "$sched_dir/cgroup.conf" /etc/slurm/cgroup.conf
+ln -s "$sched_dir/accounting.conf" /etc/slurm/accounting.conf
+ln -s "$sched_dir/azure.conf" /etc/slurm/azure.conf
+ln -s "$sched_dir/gres.conf" /etc/slurm/gres.conf
+touch "$sched_dir"/gres.conf "$sched_dir"/azure.conf
+chown slurm:slurm "$sched_dir"/*.conf
+chmod 644 "$sched_dir"/*.conf
+chown slurm:slurm /etc/slurm/*.conf
+
+# Set up log and spool directories
+mkdir -p /var/spool/slurmd /var/spool/slurmctld /var/log/slurmd /var/log/slurmctld
+chown slurm:slurm /var/spool/slurmd /var/spool/slurmctld /var/log/slurmd /var/log/slurmctld
+echo " "
+echo "------------------------------------------------------------------------------------------------------------------------------"
+echo "Slurm configured"
+echo "------------------------------------------------------------------------------------------------------------------------------"
+echo " "
+echo "------------------------------------------------------------------------------------------------------------------------------"
+echo " Go to CycleCloud Portal and edit the $cluster_name cluster configuration to use the external scheduler and start the cluster."
+echo " Use $ip_address IP Address for File-system Mount for /sched and /shared in Network Attached Storage section in CycleCloud GUI "
+echo " Once the cluster is started, proceed to run cyclecloud-integrator.sh script to complete the integration with CycleCloud."
+echo "------------------------------------------------------------------------------------------------------------------------------"
+echo " "
\ No newline at end of file
diff --git a/cloud_bursting/slurm-23.11.9-1/scheduler/useradd_example.sh b/cloud_bursting/slurm-23.11.9-1/scheduler/useradd_example.sh
new file mode 100644
index 00000000..8d68c468
--- /dev/null
+++ b/cloud_bursting/slurm-23.11.9-1/scheduler/useradd_example.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+# -----------------------------------------------------------------------------
+# Script: Create Shared Home Directory for a Test User in Slurm Scheduler
+#
+# This script creates a new user in a Slurm scheduler environment, setting up a
+# shared home directory. The user is configured with a specific username, GID,
+# and UID. It is primarily designed for environments like CycleCloud where
+# consistent user IDs are important (starting with 20001 for the first user).
+#
+# CycleCloud Convention:
+# - For the first user, the UID and GID default to 20001 in CycleCloud. Modify
+# these values as needed for additional users.
+#
+# Prerequisites:
+# - Script must be run with root privileges.
+# - The desired UID, GID, and username should be set before execution.
+# -----------------------------------------------------------------------------
+
+set -e
+if [ $(whoami) != root ]; then
+ echo "Please run as root"
+ exit 1
+fi
+
+# test user details
+username="user1"
+gid=20001
+uid=20001
+
+mkdir -p /shared/home/$username
+chmod 755 /shared/home/
+
+# Create group if not exists
+if ! getent group $gid >/dev/null; then
+ groupadd -g $gid $username
+fi
+
+# Create user with specified uid, gid, home directory, and shell
+useradd -g $gid -u $uid -d /shared/home/$username -s /bin/bash $username
+chown -R $username:$username /shared/home/$username
+# Switch to user to perform directory and file operations
+su - $username -c "mkdir -p /shared/home/$username/.ssh"
+su - $username -c "ssh-keygen -t rsa -N '' -f /shared/home/$username/.ssh/id_rsa"
+su - $username -c "cat /shared/home/$username/.ssh/id_rsa.pub >> /shared/home/$username/.ssh/authorized_keys"
+su - $username -c "chmod 600 /shared/home/$username/.ssh/authorized_keys"
+su - $username -c "chmod 700 /shared/home/$username/.ssh"
\ No newline at end of file
From c4ea7013a36b6bd70e0b6aba8d1db28825cad176 Mon Sep 17 00:00:00 2001
From: Vinil Vadakkepurakkal <82436391+vinil-v@users.noreply.github.com>
Date: Mon, 7 Oct 2024 19:38:35 +0530
Subject: [PATCH 2/6] updating images for readme
---
cloud_bursting/images/NFSSettings.png | Bin 0 -> 92478 bytes
cloud_bursting/images/nodecreation.png | Bin 0 -> 92497 bytes
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 cloud_bursting/images/NFSSettings.png
create mode 100644 cloud_bursting/images/nodecreation.png
diff --git a/cloud_bursting/images/NFSSettings.png b/cloud_bursting/images/NFSSettings.png
new file mode 100644
index 0000000000000000000000000000000000000000..8d160546f6a27aecc75a80e71c07d3610bc51764
GIT binary patch
literal 92478
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