dsh-scnet 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env bash
2
+ # 在一台新的个人电脑(macOS / Linux)上配置到超算集群的 SSH 连接。
3
+ #
4
+ # ./setup-ssh.sh [--cluster <集群短名>] <私钥文件> [用户名]
5
+ #
6
+ # 集群参数从 clusters/<集群短名>.conf 读取。只有一个 profile 时可省略 --cluster。
7
+ # 幂等:重复运行只补齐缺失项,不覆盖已有的正确配置。
8
+
9
+ set -euo pipefail
10
+
11
+ . "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/_common.sh"
12
+
13
+ parse_cluster_arg "$@"
14
+ set -- "${REST[@]+${REST[@]}}"
15
+
16
+ KEY_SRC="${1:-}"
17
+ USER_NAME="${2:-}"
18
+
19
+ if [ -z "$KEY_SRC" ]; then
20
+ cat >&2 <<EOF
21
+ 用法: $0 [--cluster <集群短名>] <私钥文件> [用户名]
22
+
23
+ 私钥从超算平台控制台下载。
24
+
25
+ 可用的集群 profile:
26
+ $(list_clusters | sed 's/^/ /')
27
+ EOF
28
+ exit 1
29
+ fi
30
+
31
+ load_cluster "$CLUSTER"
32
+
33
+ [ -f "$KEY_SRC" ] || die "找不到私钥文件: $KEY_SRC"
34
+ grep -q "BEGIN.*PRIVATE KEY" "$KEY_SRC" \
35
+ || die "$KEY_SRC 看起来不是私钥(没有 'BEGIN ... PRIVATE KEY' 头)"
36
+
37
+ KEY_DST="$HOME/.ssh/id_rsa_${CLUSTER_ID}"
38
+ SSH_CONFIG="$HOME/.ssh/config"
39
+ SOCKET_DIR="$HOME/.ssh/sockets"
40
+
41
+ # 从文件名推断用户名,形如 <用户名>_<主机标识>_RsaKeyExpireTime_<日期>.txt
42
+ if [ -z "$USER_NAME" ] && [ -n "${KEY_NAME_MARKER:-}" ]; then
43
+ base=$(basename "$KEY_SRC")
44
+ case "$base" in
45
+ *"$KEY_NAME_MARKER"*) USER_NAME="${base%%"$KEY_NAME_MARKER"*}" ;;
46
+ esac
47
+ fi
48
+ [ -n "$USER_NAME" ] || die "无法从文件名推断用户名,请作为最后一个参数传入"
49
+
50
+ echo "==> 集群: ${CLUSTER_ID} (${CLUSTER_DESC:-$SSH_HOST})"
51
+ echo "==> 用户名: ${USER_NAME}"
52
+
53
+ # ---------------------------------------------------------------- 私钥
54
+ echo "==> 安装私钥"
55
+ mkdir -p "$HOME/.ssh"
56
+ chmod 700 "$HOME/.ssh"
57
+
58
+ if [ -f "$KEY_DST" ] && ! cmp -s "$KEY_SRC" "$KEY_DST"; then
59
+ backup="$KEY_DST.bak.$(date +%Y%m%d%H%M%S)"
60
+ cp "$KEY_DST" "$backup"
61
+ info "已存在不同的私钥,备份到 $(basename "$backup")"
62
+ fi
63
+
64
+ # 源和目标可能是同一个文件(重复运行时),cp 会报错
65
+ if [ "$(cd "$(dirname "$KEY_SRC")" && pwd)/$(basename "$KEY_SRC")" != "$KEY_DST" ]; then
66
+ cp "$KEY_SRC" "$KEY_DST"
67
+ fi
68
+ chmod 600 "$KEY_DST"
69
+
70
+ # macOS 的下载文件带隔离属性,会让某些工具拒绝读取
71
+ if [ "$(uname -s)" = "Darwin" ]; then
72
+ xattr -c "$KEY_DST" 2>/dev/null || true
73
+ fi
74
+ info "$KEY_DST (600)"
75
+
76
+ if ssh-keygen -y -f "$KEY_DST" > "$KEY_DST.pub" 2>/dev/null; then
77
+ chmod 644 "$KEY_DST.pub"
78
+ info "$(ssh-keygen -lf "$KEY_DST" 2>/dev/null | awk '{print $1, $2, $4}')"
79
+ else
80
+ rm -f "$KEY_DST.pub"
81
+ info "私钥有 passphrase,跳过公钥推导"
82
+ fi
83
+
84
+ # ---------------------------------------------------------------- config
85
+ echo "==> 配置 ~/.ssh/config"
86
+ mkdir -p "$SOCKET_DIR"
87
+ chmod 700 "$SOCKET_DIR"
88
+ touch "$SSH_CONFIG"
89
+ chmod 600 "$SSH_CONFIG"
90
+
91
+ # Host 行可能列多个别名("Host a b"),按词比对而不是用正则拼
92
+ if awk -v alias="$CLUSTER_ID" '
93
+ $1 == "Host" { for (i = 2; i <= NF; i++) if ($i == alias) { found = 1; exit } }
94
+ END { exit(found ? 0 : 1) }
95
+ ' "$SSH_CONFIG"; then
96
+ info "已存在 Host ${CLUSTER_ID},跳过(如需重配请先手工删除该段)"
97
+ else
98
+ # macOS 的 ssh-agent 能存进 Keychain;Linux 上这两个选项不被识别
99
+ keychain_opts=""
100
+ if [ "$(uname -s)" = "Darwin" ]; then
101
+ keychain_opts="
102
+ UseKeychain yes
103
+ AddKeysToAgent yes"
104
+ fi
105
+
106
+ hostkey_opt=""
107
+ if [ "${NEEDS_UPDATE_HOSTKEYS_NO:-no}" = "yes" ]; then
108
+ hostkey_opt="
109
+ # 该平台对主机密钥轮换扩展返回错误签名,关掉以消除告警噪音
110
+ # (首次记录的主机密钥仍在正常校验,不影响安全性)
111
+ UpdateHostKeys no"
112
+ fi
113
+
114
+ cat >> "$SSH_CONFIG" <<EOF
115
+
116
+ Host ${CLUSTER_ID} ${SSH_HOST}
117
+ HostName ${SSH_HOST}
118
+ User ${USER_NAME}
119
+ Port ${SSH_PORT}
120
+ IdentityFile ${KEY_DST}
121
+ IdentitiesOnly yes${keychain_opts}
122
+ # 长连接:复用同一条 TCP/认证通道,后续命令从 ~2s 降到 ~0.5s
123
+ ControlMaster auto
124
+ ControlPath ${SOCKET_DIR}/%r@%h-%p
125
+ ControlPersist 10m
126
+ # 保活:防止空闲会话被中间网关静默切断
127
+ ServerAliveInterval 60
128
+ ServerAliveCountMax 3
129
+ TCPKeepAlive yes${hostkey_opt}
130
+ EOF
131
+ info "已追加 Host ${CLUSTER_ID}"
132
+ fi
133
+
134
+ # ---------------------------------------------------------------- 验证
135
+ echo "==> 测试连接"
136
+ if out=$(ssh -o BatchMode=yes -o ConnectTimeout=20 \
137
+ -o StrictHostKeyChecking=accept-new \
138
+ "$CLUSTER_ID" 'echo OK; hostname; whoami' 2>&1); then
139
+ printf '%s\n' "$out" | sed 's/^/ /'
140
+ echo
141
+ echo "完成。用法:ssh ${CLUSTER_ID}"
142
+ else
143
+ printf '%s\n' "$out" | sed 's/^/ /'
144
+ echo
145
+ die "连接失败。检查:私钥是否过期、本机 IP 是否在平台白名单内、端口 ${SSH_PORT} 是否可达"
146
+ fi