

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# AWS PCS 登录节点
<a name="working-with_login-nodes"></a>

 AWS PCS 集群通常需要至少 1 个登录节点来支持交互式访问和任务管理。实现这一目标的一种方法是使用为登录节点功能配置静态 AWS PCS 计算节点组。您也可以将独立的 EC2 实例配置为登录节点。

**Topics**
+ [使用 AWS PCS 计算节点组提供登录节点](working-with_login-nodes_compute-node-group-for-login.md)
+ [使用独立实例作为 AWS PCS 登录节点](working-with_login-nodes_standalone.md)
+ [将独立登录节点连接到 AWS PCS 中的多个集群](multi-cluster-login-script.md)

# 使用 AWS PCS 计算节点组提供登录节点
<a name="working-with_login-nodes_compute-node-group-for-login"></a>

 本主题概述了建议的配置选项，并介绍了在使用 AWS PCS 计算节点组为集群提供持久的交互式访问时应考虑的事项。

## 为登录节点创建 AWS PCS 计算节点组
<a name="working-with_login-nodes_compute-node-group-for-login_create"></a>

 从操作上讲，这与创建常规计算节点组没有太大区别。但是，可以做出一些关键的配置选择：
+  为计算节点组中至少一个 EC2 实例设置静态扩展配置。
+  选择按需购买选项，以避免回收您的实例。
+  为计算节点组选择一个信息性名称，例如登录。
+  如果您希望登录节点实例可在您的 VPC 之外访问，请考虑使用公有子网。
+  如果您打算允许 SSH 访问，则启动模板需要有一个安全组，用于向您选择的 IP 地址公开 SSH 端口。
+  IAM 实例配置文件应仅具有您希望最终用户拥有的 AWS 权限。有关详细信息，请参阅 [AWS 并行计算服务的 IAM 实例配置文件](security-instance-profiles.md)。
+  考虑允许 AWS Systems Manager 会话管理器来管理您的登录实例。
+  考虑仅限管理员用户访问实例 AWS 证书 
+  选择比普通计算节点组更便宜的实例类型，因为登录节点将持续运行。
+  使用与其他计算节点组相同的（或衍生的）AMI，以帮助确保所有实例都安装了相同的软件。有关自定义的更多信息 AMIs，请参阅 [适用于 AWS PCS 的亚马逊机器映像 (AMIs)](working-with_ami.md)
+  在登录节点上配置与计算实例相同的网络文件系统（Amazon FSx EFS、Amazon for Lustre 等）的挂载。有关更多信息，请参阅 [在 AWS PCS 上使用网络文件系统](working-with_file-systems.md)。

**访问您的登录节点**  
当您的新计算节点组变为 ACTIVE 状态后，您可以找到它创建的 EC2 实例并登录到这些实例中。有关更多信息，请参阅 [在 AWS PCS 中查找计算节点组实例](working-with_compute-instances.md)。

## 更新登录节点的 AWS PCS 计算节点组
<a name="working-with_login-nodes_compute-node-group-for-login_update"></a>

 您可以使用更新登录节点组 UpdateComputeNodeGroup。作为节点组更新过程的一部分，将替换正在运行的实例。请注意，这将中断实例上所有活跃的用户会话或进程。正在运行或排队的 Slurm 作业不会受到影响。有关更多信息，请参阅 [更新 AWS PCS 计算节点组](working-with_cng_update.md)。

 您也可以编辑计算节点组使用的启动模板。必须使用 UpdateComputeNodeGroup 将更新的启动模板应用于计算节点组。在计算节点组中启动的新 EC2 实例使用更新的启动模板。有关更多信息，请参阅 [在 AWS PCS 上使用亚马逊 EC2 启动模板](working-with_launch-templates.md)。

## 删除登录节点的 AWS PCS 计算节点组
<a name="working-with_login-nodes_compute-node-group-for-login_delete"></a>

 您可以使用 AWS PCS 中的**删除计算节点组机制更新登录节点组**。作为删除节点组的一部分，正在运行的实例将被终止。请注意，这将中断实例上所有活跃的用户会话或进程。正在运行或排队的 Slurm 作业不会受到影响。有关更多信息，请参阅 [删除 AWS PCS 中的计算节点组](working-with_cng_delete.md)。

# 使用独立实例作为 AWS PCS 登录节点
<a name="working-with_login-nodes_standalone"></a>

您可以设置独立的 EC2 实例来与 AWS PCS 集群的 Slurm 调度器进行交互。这对于创建登录节点、工作站或专用工作流管理主机非常有用，这些主机可以与 AWS PCS 集群配合使用，但在 AWS PCS 管理之外运行。为此，每个独立实例必须：

1. 安装兼容的 Slurm 软件版本。

1. 能够连接到 AWS PCS 集群的 Slurmctld 终端节点。

1. 使用 AWS PCS 集群的终端节点和密钥正确配置 Slurm Auth 和 Cred Kiosk Daemon (`sackd`)。有关更多信息，请参阅 [Slurm 文档中的 sackd](https://slurm.schedmd.com/sackd.html)。

 本教程帮助您配置连接到 AWS PCS 集群的独立实例。

**Contents**
+ [步骤 1-检索目标 AWS PCS 集群的地址和密码](working-with_login-nodes_standalone_get-addr.md)
+ [步骤 2-启动 EC2 实例](working-with_login-nodes_standalone_launch.md)
+ [步骤 3-在实例上安装 Slurm](working-with_login-nodes_standalone_install-slurm.md)
+ [步骤 4-检索和存储集群密钥](working-with_login-nodes_standalone_get-secret.md)
+ [步骤 5-配置与 AWS PCS 集群的连接](working-with_login-nodes_standalone_configure-connection.md)
+ [步骤 6-（可选）测试连接](working-with_login-nodes_standalone_test.md)

# 步骤 1-检索目标 AWS PCS 集群的地址和密码
<a name="working-with_login-nodes_standalone_get-addr"></a>

使用以下命令检索有关目标 AWS PCS 集群的详细信息。 AWS CLI 在运行命令之前，进行以下替换：
+ *region-code*替换为目标 AWS 区域 集群的运行位置。
+ *cluster-ident*替换为目标集群的名称或标识符

```
aws pcs get-cluster --region region-code --cluster-identifier cluster-ident
```

该命令将返回类似于此示例的输出。

```
{
    "cluster": {
        "name": "get-started",
        "id": "pcs_123456abcd",
        "arn": "arn:aws:pcs:us-east-1:111122223333:cluster/pcs_123456abcd",
        "status": "ACTIVE",
        "createdAt": "2024-12-17T21:03:52+00:00",
        "modifiedAt": "2024-12-17T21:03:52+00:00",
        "scheduler": {
            "type": "SLURM",
            "version": "25.05"
        },
        "size": "SMALL",
        "slurmConfiguration": {
            "authKey": {
                "secretArn": "arn:aws:secretsmanager:us-east-1:111122223333:secret:pcs!slurm-secret-pcs_123456abcd-a12ABC",
                "secretVersion": "ef232370-d3e7-434c-9a87-ec35c1987f75"
            }
        },
        "networking": {
            "subnetIds": [
                "subnet-0123456789abcdef0"
            ],
            "securityGroupIds": [
                "sg-0123456789abcdef0"
            ]
        },
        "endpoints": [
            {
                "type": "SLURMCTLD",
                "privateIpAddress": "10.3.149.220",
                "port": "6817"
            }
        ]
    }
}
```

在此示例中，集群 Slurm 控制器端点的 IP 地址为，`10.3.149.220`并且正在端口上运行。`6817``secretArn`将在后面的步骤中使用来检索集群密钥。IP 地址和端口将在后续步骤中用于配置`sackd`服务。

# 步骤 2-启动 EC2 实例
<a name="working-with_login-nodes_standalone_launch"></a>

**启动 EC2 实例**

1. 打开 [Amazon EC2 控制台](https://console.aws.amazon.com/ec2)。

1. 在导航窗格中，请选择 **Instances**（实例），然后选择 **Launch Instances**（启动实例）以打开新的启动实例向导。

1. （可选）在**名称和标签**部分中，提供实例的名称，例如`PCS-LoginNode`。名称作为资源标签（`Name=PCS-LoginNode`）分配给实例。

1. 在 “**应用程序和操作系统映像**” 部分，为 AWS PCS 支持的操作系统选择一个 AMI。有关更多信息，请参阅 [支持的操作系统](working-with_ami_installers.md#working-with_ami_installers_os)。

1. 在**实例类型**部分中，选择支持的实例类型。有关更多信息，请参阅 [支持的实例类型](working-with_ami_installers.md#working-wth_ami_installers_instance-types)。

1. 在**密钥对**部分，选择要用于实例的 SSH 密钥对。

1. 在**网络设置** 部分中：

   1. 选择**编辑**。

     1. 选择您的 PC AWS S 集群的 VPC。

     1. 对于**防火墙（安全组）**，请选择**选择现有安全组**。

        1. 选择一个允许在实例和目标 AWS PCS 集群的 Slurm 控制器之间进行流量的安全组。有关更多信息，请参阅 [安全组要求和注意事项](working-with_networking_sg.md#working-with_networking_sg-requirements)。

        1. （可选）选择允许对您的实例进行入站 SSH 访问的安全组。

1. 在 “**存储**” 部分，根据需要配置存储卷。确保配置足够的空间来安装应用程序和库，以启用您的用例。

1.  在 “**高级**” 下，选择允许访问集群密钥的 IAM 角色。有关更多信息，请参阅 [获取 Slurm 集群的秘密](working-with_clusters_secrets_get.md)。

1.  在**摘要**窗格中，选择**启动实例**。

# 步骤 3-在实例上安装 Slurm
<a name="working-with_login-nodes_standalone_install-slurm"></a>

当实例启动并变为活动状态时，请使用您的首选机制连接到该实例。使用提供的 Slurm 安装程序将 Slurm 安装 AWS 到实例上。有关更多信息，请参阅 [Slurm 安装程序](working-with_ami_installers.md#working-with_ami_installers_slurm)。

下载 Slurm 安装程序，将其解压缩，然后使用`installer.sh`脚本安装 Slurm。有关更多信息，请参阅 [第 3 步 — 安装 Slurm](working-with_ami_custom_install-slurm.md)。

# 步骤 4-检索和存储集群密钥
<a name="working-with_login-nodes_standalone_get-secret"></a>

这些说明需要 AWS CLI. 有关更多信息，请参阅[版本 2 AWS Command Line Interface 用户指南 AWS CLI中的安装或更新到最新](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)*版本的*。

使用以下命令存储集群密钥。
+ 为 Slurm 创建配置目录。

  ```
  sudo mkdir -p /etc/slurm
  ```
+ 检索、解码和存储集群密钥。在运行此命令之前，请*region-code*替换为运行目标集群的区域，并*secret-arn*替换为[步骤 1](working-with_login-nodes_standalone_get-addr.md) 中`secretArn`检索到的值。

  ```
  aws secretsmanager get-secret-value \
   --region region-code \
   --secret-id 'secret-arn' \
   --version-stage AWSCURRENT \
   --query 'SecretString' \
   --output text | base64 -d | sudo tee /etc/slurm/slurm.key
  ```
**警告**  
在多用户环境中，任何有权访问实例的用户只要能够访问实例元数据服务 (IMDS)，都可能能够获取集群密钥。反过来，这可能允许他们冒充其他用户。考虑仅限根用户或管理员用户访问 IMDS。或者，可以考虑使用另一种不依赖实例配置文件来获取和配置密钥的机制。
+ 设置 Slurm 密钥文件的所有权和权限。

  ```
  sudo chmod 0600 /etc/slurm/slurm.key
  sudo chown slurm:slurm /etc/slurm/slurm.key
  ```
**注意**  
Slurm 密钥必须归运行`sackd`服务的用户和群组所有。

# 步骤 5-配置与 AWS PCS 集群的连接
<a name="working-with_login-nodes_standalone_configure-connection"></a>

要建立与 AWS PCS 集群的连接，请按照以下步骤`sackd`作为系统服务启动。

**注意**  
 如果您使用 Slurm 25.05 或更高版本，则可以使用脚本将登录节点设置为连接到多个集群。有关更多信息，请参阅 [将独立登录节点连接到 AWS PCS 中的多个集群](multi-cluster-login-script.md)。

1. 使用以下命令为`sackd`服务设置环境文件。在运行命令之前，请将*ip-address*和*port*替换为[步骤 1](working-with_login-nodes_standalone_get-addr.md) 中从端点检索到的值。

   ```
   sudo echo "SACKD_OPTIONS='--conf-server=ip-address:port'" > /etc/sysconfig/sackd
   ```

1. 创建用于管理`sackd`流程的`systemd`服务文件。

   ```
   sudo cat << EOF > /etc/systemd/system/sackd.service
   [Unit]
   Description=Slurm auth and cred kiosk daemon
   After=network-online.target remote-fs.target
   Wants=network-online.target
   ConditionPathExists=/etc/sysconfig/sackd
   
   [Service]
   Type=notify
   EnvironmentFile=/etc/sysconfig/sackd
   User=slurm
   Group=slurm
   RuntimeDirectory=slurm
   RuntimeDirectoryMode=0755
   ExecStart=/opt/aws/pcs/scheduler/slurm-25.05/sbin/sackd --systemd \$SACKD_OPTIONS
   ExecReload=/bin/kill -HUP \$MAINPID
   KillMode=process
   LimitNOFILE=131072
   LimitMEMLOCK=infinity
   LimitSTACK=infinity
   
   [Install]
   WantedBy=multi-user.target
   EOF
   ```

1. 设置`sackd`服务文件的所有权。

   ```
   sudo chown root:root /etc/systemd/system/sackd.service && \
       sudo chmod 0644 /etc/systemd/system/sackd.service
   ```

1. 启用该`sackd`服务。

   ```
   sudo systemctl daemon-reload && sudo systemctl enable sackd
   ```

1. 启动 `sackd` 服务。

   ```
   sudo systemctl start sackd
   ```

# 步骤 6-（可选）测试连接
<a name="working-with_login-nodes_standalone_test"></a>

确认`sackd`服务正在运行。示例输出如下。如果有错误，它们通常会出现在这里。

```
[root@ip-10-3-27-112 ~]# systemctl status sackd
[x] sackd.service - Slurm auth and cred kiosk daemon
   Loaded: loaded (/etc/systemd/system/sackd.service; enabled; vendor preset: disabled)
   Active: active (running) since Tue 2024-12-17 16:34:55 UTC; 8s ago
 Main PID: 9985 (sackd)
   CGroup: /system.slice/sackd.service
           └─9985 /opt/aws/pcs/scheduler/slurm-25.05/sbin/sackd --systemd --conf-server=10.3.149.220:6817

Dec 17 16:34:55 ip-10-3-27-112.ec2.internal systemd[1]: Starting Slurm auth and cred kiosk daemon...
Dec 17 16:34:55 ip-10-3-27-112.ec2.internal systemd[1]: Started Slurm auth and cred kiosk daemon.
Dec 17 16:34:55 ip-10-3-27-112.ec2.internal sackd[9985]: sackd: running
```

使用 Slurm 客户端命令（例如`sinfo`和）确认与集群的连接是否正常运行。`squeue`以下是的输出示例`sinfo`。

```
[root@ip-10-3-27-112 ~]# /opt/aws/pcs/scheduler/slurm-25.05/bin/sinfo
PARTITION AVAIL TIMELIMIT NODES STATE NODELIST
all up infinite 4 idle~ compute-[1-4]
```

您还应该能够提交工作。例如，类似于此示例的命令将在集群中的 1 个节点上启动交互式作业。

```
/opt/aws/pcs/scheduler/slurm-25.05/bin/srun --nodes=1 -p all --pty bash -i
```

# 将独立登录节点连接到 AWS PCS 中的多个集群
<a name="multi-cluster-login-script"></a>

该`pcs-multi-cluster-login-configure.sh`脚本提供了一种在单个独立登录节点上配置多个 Slurm `sackd` 守护程序的自动方法。它使登录节点能够与多个集群通信。该脚本可自动执行以下操作：
+ 使用 AWS PCS API 操作来获取集群信息
+ 提示输入 base64 编码的 Slurm 身份验证密钥
+ 使用集群身份验证密钥创建 Slurm JWKS 文件
+ 使用集群终端节点和端口配置`sackd`服务
+ 为特定于集群`sackd`的守护程序创建`systemd`服务文件
+ 为集群环境设置生成激活脚本
+ 启用和启动`sackd`服务

**注意**  
此脚本需要 Slurm 版本 25.05 或更高版本。

Slurm 必须已经安装在实例上（相当于手动过程中的[步骤 3](working-with_login-nodes_standalone_install-slurm.md)）。该实例必须能够到达目标集群的终端节点。在手动配置过程中，该脚本执行的操作与[步骤 4](working-with_login-nodes_standalone_get-secret.md) [和步骤 5](working-with_login-nodes_standalone_configure-connection.md) 的操作相同。它会自动获取集群信息、配置服务、创建必要的`sackd``systemd`服务文件并创建激活脚本，用户可以使用该脚本配置其 shell 环境以进行集群交互。

**Topics**
+ [AWS PCS 多集群登录节点配置脚本的先决条件](multi-cluster-login-script-prerequisites.md)
+ [AWS PCS 多集群登录节点配置脚本代码](multi-cluster-login-script-code.md)
+ [使用 AWS PCS 多集群登录节点配置脚本](multi-cluster-login-script-usage.md)

# AWS PCS 多集群登录节点配置脚本的先决条件
<a name="multi-cluster-login-script-prerequisites"></a>

## 系统要求
<a name="system-requirements"></a>
+ `systemd`支持的 Linux 操作系统
+ 系统配置的 root 权限

## 必需的命令和软件包
<a name="required-commands"></a>
+ `bash`— 外壳解释器（版本 4.0\$1）
+ `curl`— 用于 AWS IMDS v2 元数据检索
+ `jq`— 用于解析 AWS API 响应的 JSON 处理器
+ `aws`— AWS CLI v2 用于运行 AWS PCS API 操作和访问 Secrets Manager
+ `systemctl`— `systemd` 服务管理
+ `find`— 文件系统搜索实用程序
+ `grep`— 文本模式匹配
+ `sed`— 用于文本操作的流编辑器
+ `sort`— 文本排序工具
+ `tail`— 显示文件的最后几行
+ `mkdir`— 目录创建
+ `chmod`— 更改文件权限
+ `chown`— 更改文件所有权
+ `ldconfig`— 动态链接器配置

## AWS 要求
<a name="aws-requirements"></a>
+ 运行 Slurm 版本 25.05 或更高版本的 AWS PCS 集群
+ AWS 配置的证书（通过 IAM 角色、证书文件或环境变量）
+ 以下各项的权限：
  + `pcs:GetCluster`
  + `secretsmanager:GetSecretValue`（如果您使用备用密钥）

## 系统用户和群组
<a name="system-users-groups"></a>
+ `slurm`用户和组必须存在于系统中

## Slurm 安装
<a name="slurm-installation"></a>
+ Slurm 必须与 AWS PCS Slurm 安装程序包安装在相同的位置：

  ```
  /opt/aws/pcs/scheduler/slurm-version
  ```

# AWS PCS 多集群登录节点配置脚本代码
<a name="multi-cluster-login-script-code"></a>

将以下源代码保存到具有以下名称的文件中：

```
pcs-multi-cluster-login-configure.sh
```

## 脚本源代码
<a name="multi-cluster-login-script-code-content"></a>

```
#!/bin/bash
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.

# AWS PCS Multi-Cluster Standalone Login Node Configuration Script
# 
# This script configures AWS Parallel Computing Service (PCS) multi-cluster stand alone login nodes
# by setting up the Slurm authentication and credential kiosk daemon (sackd)
# for connecting to remote PCS clusters.
#
# Prerequisites:
# - AWS CLI configured with appropriate permissions
# - Slurm version 25.05 or later
# - Root privileges for system configuration
# - Network connectivity to AWS PCS endpoints


set -eo pipefail

# Function to display usage
usage() {
    echo "Usage: $0 --cluster-identifier <cluster-identifier> [--endpoint-url <endpoint-url>]"
    echo "       $0 -h|--help"
}

# Function to display help
help() {
    echo "AWS PCS Multi-Cluster Standalone Login Node Configuration Script"
    echo "==============================================="
    echo
    echo "This script configures multi-cluster standalone login node for AWS Parallel Computing Service (PCS)"
    echo "by setting up the Slurm authentication and credential kiosk daemon (sackd)."
    echo
    usage
    echo
    echo "Options:"
    echo "  --cluster-identifier <id>    AWS PCS cluster identifier (required)"
    echo "  --endpoint-url <url>         Custom PCS endpoint URL (optional)"
    echo "  -h, --help                   Show this help message"
    echo
    echo "Examples:"
    echo "  $0 --cluster-identifier my-pcs-cluster"
    echo
    echo "Note: This script requires root privileges and Slurm version 25.05 or later."
}

# Function to retrieve authentication key
get_auth_key() {
    if [ "$ALTERNATE_SECRET_RETRIEVAL" = "true" ]; then
        echo "Retrieving authentication key from AWS Secrets Manager..." >&2
        local auth_key_arn=$(echo "$CLUSTER_INFO" | jq -r '.cluster.slurmConfiguration.authKey.secretArn')
        local auth_key_version=$(echo "$CLUSTER_INFO" | jq -r '.cluster.slurmConfiguration.authKey.secretVersion')
        
        if [ "$auth_key_arn" = "null" ] || [ "$auth_key_version" = "null" ]; then
            echo "Error: Auth key information not found in cluster configuration" >&2
            exit 1
        fi
        
        if ! aws secretsmanager get-secret-value --secret-id "$auth_key_arn" --version-id "$auth_key_version" --query SecretString --output text --region "$REGION" 2>/dev/null; then
            echo "Error: Failed to retrieve auth key from Secrets Manager" >&2
            exit 1
        fi
    else
        echo "Please enter the base64-encoded Slurm authentication key:" >&2
        echo -n "Base64 of the Slurm secret key: " >&2
        local key
        read -rs key
        echo >&2
        echo "$key"
    fi
}

# Function to get next available SACKD port
get_next_sackd_port() {
    local exclude_file="$1"
    local port=6918
    local used_ports=()
    
    # Get all currently used SACKD ports into an array
    while IFS= read -r line; do
        used_ports+=("$line")
    done < <(find /etc/sysconfig -name "sackd-pcs-*" ! -path "$exclude_file" \
             -exec grep SACKD_PORT= '{}' ';' 2>/dev/null | \
             sed 's/.*SACKD_PORT=//' | sort -n)
    
    # Loop through used ports to find first available port
    for used_port in "${used_ports[@]}"; do
        if [ "$port" -lt "$used_port" ]; then
            break
        elif [ "$port" -eq "$used_port" ]; then
            ((port++))
        fi
    done
    
    echo "$port"
}

# Function to configure cluster
configure_cluster() {
    mkdir -p /etc/slurm
    SLURM_JWKS_FILE="/etc/slurm/slurm-${CLUSTER_NAME}.jwks"
    echo '{"keys":[{"alg":"HS256","kty":"oct","kid":"key-'"${CLUSTER_ID}"'","k":"'"${BASE64_SLURM_KEY}"'"}]}' | jq -c '.' > "${SLURM_JWKS_FILE}"
    
    chmod 0600 "$SLURM_JWKS_FILE"
    chown slurm:slurm "$SLURM_JWKS_FILE"
    
    SLURM_INSTALL_PATH="/opt/aws/pcs/scheduler/slurm-${SLURM_VERSION}"
    
    SACKD_RUNTIME_DIRECTORY="/run/slurm-${CLUSTER_NAME}"
    mkdir -p "${SACKD_RUNTIME_DIRECTORY}"
    chown slurm:slurm "${SACKD_RUNTIME_DIRECTORY}"
    
    mkdir -p /etc/sysconfig
    SACKD_SERVICE_NAME="sackd-pcs-${CLUSTER_NAME}"
    SACKD_SERVICE_ENV="/etc/sysconfig/${SACKD_SERVICE_NAME}"
    SACKD_PORT=$(get_next_sackd_port "$SACKD_SERVICE_ENV")
    cat > "${SACKD_SERVICE_ENV}" << EOF
SACKD_OPTIONS='--conf-server=$ENDPOINTS'
SLURM_SACK_JWKS='$SLURM_JWKS_FILE'
RUNTIME_DIRECTORY='$SACKD_RUNTIME_DIRECTORY'
SACKD_PORT=$SACKD_PORT
EOF
    
    SACKD_SERVICE_PATH="/etc/systemd/system/${SACKD_SERVICE_NAME}.service"
    
    cat << EOF > "$SACKD_SERVICE_PATH"
[Unit]
Description=Slurm auth and cred kiosk daemon
After=network-online.target remote-fs.target
Wants=network-online.target
ConditionPathExists=${SACKD_SERVICE_ENV}

[Service]
Type=notify
EnvironmentFile=${SACKD_SERVICE_ENV}
User=slurm
Group=slurm
RuntimeDirectory=slurm-${CLUSTER_NAME}
RuntimeDirectoryMode=0755
ExecStart=${SLURM_INSTALL_PATH}/sbin/sackd --systemd \$SACKD_OPTIONS
ExecReload=/bin/kill -HUP \$MAINPID
KillMode=process
LimitNOFILE=131072
LimitMEMLOCK=infinity
LimitSTACK=infinity

[Install]
WantedBy=multi-user.target
EOF
    
    chown root:root "$SACKD_SERVICE_PATH"
    chmod 0644 "$SACKD_SERVICE_PATH"
    systemctl daemon-reload && systemctl enable "$SACKD_SERVICE_NAME"
    systemctl restart "$SACKD_SERVICE_NAME"
    
    ACTIVATE_SCRIPT="activate-pcs-${CLUSTER_NAME}"
    cat > "$ACTIVATE_SCRIPT" << EOF
# Activate script for Slurm cluster ${CLUSTER_NAME}

# Add Slurm paths
export PATH="${SLURM_INSTALL_PATH}/bin:\$PATH"
export MANPATH="${SLURM_INSTALL_PATH}/share/man:\$MANPATH"
export LD_LIBRARY_PATH="${SLURM_INSTALL_PATH}/lib:\$LD_LIBRARY_PATH"
ldconfig

# Set Slurm configuration
export SLURM_CONF="/run/slurm-${CLUSTER_NAME}/conf/slurm.conf"
export PCS_CLUSTER_NAME="${CLUSTER_NAME}"
export PCS_CLUSTER_IDENTIFIER="${CLUSTER_IDENTIFIER}"
export PCS_CLUSTER_ID="${CLUSTER_ID}"

echo "Activated PCS cluster environment: ${CLUSTER_NAME}"

# Deactivate function
function deactivate-pcs-${CLUSTER_NAME}() {
    export PATH="\$(echo "\$PATH" | sed -e "s|${SLURM_INSTALL_PATH}/bin:||g" -e "s|:${SLURM_INSTALL_PATH}/bin||g" -e "s|^${SLURM_INSTALL_PATH}/bin\$||")"
    export MANPATH="\$(echo "\$MANPATH" | sed -e "s|${SLURM_INSTALL_PATH}/share/man:||g" -e "s|:${SLURM_INSTALL_PATH}/share/man||g" -e "s|^${SLURM_INSTALL_PATH}/share/man\$||")"
    export LD_LIBRARY_PATH="\$(echo "\$LD_LIBRARY_PATH" | sed -e "s|${SLURM_INSTALL_PATH}/lib:||g" -e "s|:${SLURM_INSTALL_PATH}/lib||g" -e "s|^${SLURM_INSTALL_PATH}/lib\$||")"
    unset SLURM_CONF
    unset PCS_CLUSTER_NAME
    unset PCS_CLUSTER_IDENTIFIER
    unset PCS_CLUSTER_ID
    unset -f deactivate-pcs-${CLUSTER_NAME}
    ldconfig
    echo "Deactivated PCS cluster environment: ${CLUSTER_NAME}"
}

export -f deactivate-pcs-${CLUSTER_NAME}

EOF
}

# Main function
main() {
    # Parse arguments
    CLUSTER_IDENTIFIER=""
    PCS_ENDPOINT_URL=""
    
    while [ "$1" != "" ]; do
        case $1 in
            --cluster-identifier)
                shift
                CLUSTER_IDENTIFIER="$1"
                ;;
            --endpoint-url)
                shift
                PCS_ENDPOINT_URL="--endpoint-url $1"
                ;;
            -h|--help)
                help
                exit 0
                ;;
            *)
                echo "Invalid argument: $1" >&2
                usage >&2
                exit 1
                ;;
        esac
        shift
    done
    
    # Validate required arguments
    if [ -z "$CLUSTER_IDENTIFIER" ]; then
        echo "Error: --cluster-identifier is required" >&2
        usage >&2
        exit 1
    fi
    
    # Validate running as root
    if [ "$EUID" -ne 0 ]; then
        echo "Error: This script must be run as root" >&2
        exit 1
    fi
    
    # Validate required commands are available
    for cmd in aws jq curl; do
        if ! command -v "$cmd" &> /dev/null; then
            echo "Error: Required command '$cmd' not found" >&2
            exit 1
        fi
    done
    
    # Get the region name from IMDS v2 with error handling (try IPv6 first, fallback to IPv4)
    echo "Retrieving AWS region from instance metadata..."
    # Try IPv6 IMDS endpoint first (fd00:ec2::254) with fast timeout (1s connect, 2s total)
    # If IPv6 fails, fallback to IPv4 IMDS endpoint (169.254.169.254)
    IMDS_ENDPOINT="http://[fd00:ec2::254]"
    if ! TOKEN=$(curl -s -X PUT "${IMDS_ENDPOINT}/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" --connect-timeout 1 --max-time 2 2>/dev/null); then
        IMDS_ENDPOINT="http://169.254.169.254"
        if ! TOKEN=$(curl -s -X PUT "${IMDS_ENDPOINT}/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600" --max-time 5); then
            echo "Error: Failed to retrieve IMDS token. Ensure this script is running on an EC2 instance." >&2
            exit 1
        fi
    fi
    
    if ! REGION=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" "${IMDS_ENDPOINT}/latest/dynamic/instance-identity/document" --max-time 5 | jq -r '.region'); then
        echo "Error: Failed to retrieve AWS region from instance metadata" >&2
        exit 1
    fi
    
    echo "Detected AWS region: $REGION"
    
    # Retrieve cluster information from AWS PCS
    echo "Retrieving cluster information for: $CLUSTER_IDENTIFIER"
    # shellcheck disable=SC2086
    if ! CLUSTER_INFO=$(aws pcs get-cluster --region "$REGION" --cluster-identifier "$CLUSTER_IDENTIFIER" $PCS_ENDPOINT_URL 2>/dev/null); then
        echo "Error: Failed to retrieve cluster information. Check cluster identifier and AWS permissions." >&2
        exit 1
    fi
    
    CLUSTER_ID=$(echo "$CLUSTER_INFO" | jq -r '.cluster.id')
    CLUSTER_NAME="$(echo "$CLUSTER_INFO" | jq -r '.cluster.name')"
    SLURM_VERSION=$(echo "$CLUSTER_INFO" | jq -r '.cluster.scheduler.version')
    SLURM_VERSION=${SLURM_VERSION#Slurm_}
    
    # Check if Slurm version is >= 25.05
    # shellcheck disable=SC2072
    if [[ "$SLURM_VERSION" < "25.05" ]]; then
        echo "Error: This script requires Slurm version 25.05 or later. Found version: $SLURM_VERSION" >&2
        exit 1
    fi
    
    ENDPOINTS=$(echo "$CLUSTER_INFO" | jq -r '.cluster.endpoints[] | select(.type == "SLURMCTLD") | (if .privateIpAddress != "" then .privateIpAddress else "[" + .ipv6Address + "]" end) + ":" + .port' | tr '\n' ',' | sed 's/,$//')
    
    # Get BASE64_SLURM_KEY
    BASE64_SLURM_KEY=$(get_auth_key)
    
    if [ -z "$BASE64_SLURM_KEY" ]; then
        echo "Error: base64 Slurm key cannot be empty" >&2
        exit 1
    fi
    
    configure_cluster
    
    # Final configuration summary
    echo "========================================"
    echo "Configuration completed successfully!"
    echo "========================================"
    echo "Cluster Name: $CLUSTER_NAME"
    echo "Cluster ID: $CLUSTER_ID"
    echo "Slurm Version: $SLURM_VERSION"
    echo "Service Name: $SACKD_SERVICE_NAME"
    echo "SACKD Port: $SACKD_PORT"
    echo
    echo "To activate this cluster environment, run:"
    echo "  source ./$ACTIVATE_SCRIPT"
    echo
    echo "To deactivate this cluster environment, run:"
    echo "  deactivate-pcs-${CLUSTER_NAME}"
    echo
    echo "To check service status:"
    echo "  systemctl status $SACKD_SERVICE_NAME"
    echo
    echo "To view service logs:"
    echo "  journalctl -u $SACKD_SERVICE_NAME -f"
}

# Exit if being sourced for testing
[[ "${BASH_SOURCE[0]}" != "${0}" ]] && return

# Execute main function
main "$@"
```

# 使用 AWS PCS 多集群登录节点配置脚本
<a name="multi-cluster-login-script-usage"></a>

## 运行脚本
<a name="running-script"></a>

**运行配置脚本**

1. 将[脚本内容](multi-cluster-login-script-code.md#multi-cluster-login-script-code-content)保存在名为：的文件中

   ```
   pcs-multi-cluster-login-configure.sh
   ```

1. 使其可执行：

   ```
   chmod +x pcs-multi-cluster-login-configure.sh
   ```

1. 运行脚本：

   ```
   ./pcs-multi-cluster-login-configure.sh --cluster-identifier cluster-name
   ```

## 集群交互环境
<a name="activation-script-usage"></a>

成功配置后，该脚本将在当前目录中生成特定于群集的激活脚本。脚本有名字`activate-pcs-cluster-name`。激活脚本配置必要的环境变量和路径以与目标集群进行交互。

**激活群集环境**
+ 使用`source`命令运行激活脚本

  ```
  source ./activate-pcs-cluster-name
  ```  
**Example**  

  ```
  # Activate cluster environment for cluster 'my-cluster'
  source ./activate-pcs-my-cluster
  
  # Now you can use Slurm commands
  sinfo
  squeue
  sbatch my-job.sh
  ```

**激活脚本的作用**
+ 将`SLURM_CONF`环境变量设置为指向群集的配置。
+ 更新`PATH`以包含集群的 Slurm 二进制文件。
+ 配置其他必要的 Slurm 环境变量 (`MANPATH`,)。`LD_LIBRARY_PATH`
+ 设置 AWS PCS 集群标识变量。
+ 实现与目标 AWS PCS 集群的无缝交互。

**停用群集环境**
+ 运行停用命令。

  ```
  deactivate-pcs-cluster-name
  ```  
**Example**  

  ```
  # After activating a cluster
  source ./activate-pcs-my-cluster
  
  # Work with the cluster
  sinfo
  
  # Deactivate when done
  deactivate-pcs-my-cluster
  ```

**停用命令的作用**
+ 恢复原始`PATH`环境变量。
+ 取消设置特定于集群的 Slurm 环境变量。
+ 将 shell 环境恢复到其激活前的状态。

**注意**  
激活是特定于会话的，并且必须源自您要与集群交互的 shell 会话。