Cisco UCSのCisco Integrated Management Controller (CIMC)はWeb管理画面とssh接続によるCLI管理がある。
CIMCについているホスト名は基本的に「サーバ機種名-シリアル番号」となっている。
ホスト名を確認する操作をCLIから行うには、scope:cimc/network以下でdetailを表示する操作になる。
ホスト名# scope cimc/network
ホスト名 /cimc/network # show detail
Network Setting:
IPv4 Enabled: yes
IPv4 Address: xxx.xxx.xxx.xxx
IPv4 Netmask: 255.255.255.0
IPv4 Gateway: xxx.xxx.xxx.xxx
DHCP Enabled: no
DDNS Enabled: yes
DDNS Update Domain:
DDNS Refresh Interval(0-8736 Hr): 0
Obtain DNS Server by DHCP: no
Preferred DNS: xxx.xxx.xxx.xxx
Alternate DNS: 0.0.0.0
IPv6 Enabled: yes
IPv6 Address: ::
IPv6 Prefix: 64
IPv6 Gateway: ::
IPv6 Link Local: fe80::86b8:xxxx:xxxx:xxxx
IPv6 SLAAC Address: ::
IPV6 DHCP Enabled: yes
IPV6 Obtain DNS Server by DHCP: yes
IPV6 Preferred DNS: ::
IPV6 Alternate DNS: ::
VLAN Enabled: no
VLAN ID: 1
VLAN Priority: 0
Port Profile:
Hostname: ホスト名
MAC Address: XX:XX:XX:XX:XX:XX
NIC Mode: dedicated
NIC Redundancy: none
VIC Slot: riser1
Auto Negotiate: yes
Admin Network Speed: auto
Admin Duplex: auto
Operational Network Speed: 1Gbps
Operational Duplex: full
ホスト名 /cimc/network #
show detailだといろんな項目が表示されすぎるので、ホスト名だけを取り出すことができないか調べたところ「| grep キーワード」が使えた。
ホスト名 /cimc/network # show detail | grep Hostname
Hostname: ホスト名
ホスト名 /cimc/network #
ホスト名変更操作は scope:cimc/network にて set hostnameを実行したあと、commitで確定する。
ホスト名 /cimc/network # set hostname 新ホスト名
Create new certificate with CN as new hostname? [y|N] y
ホスト名 /cimc/network *# commit
Changes to the network settings will be applied immediately.
You may lose connectivity to the Cisco IMC and may have to log in again.
Do you wish to continue? [y/N] y
注意点として、ホスト名変更に伴い、Web管理GUIおよびssh接続で使用するSSL証明書で使用するCN(common name)が変更されるため証明書が作成されるということがある。
また、再作成に伴いCIMC自体も再起動されるため、commit後、再起動完了までの数分間CIMCに接続できなくなる。
このため、CIMCホスト名変更処理を行ったあとは、再起動待ちと証明書再発行にともなうssh接続時のキー変更に対応する処理を入れる必要がある。
ssh接続時のknown_hostsファイルから該当するエントリを削除したい場合は、 ssh-keygenコマンドの-Rオプションを使うことで行える。
osakanataro@ubuntu2004:~/imc$ ssh-keygen -R xxx.xxx.xxx.xxx
# Host xxx.xxx.xxx.xxx found: line 1
/home/osakanataro/.ssh/known_hosts updated.
Original contents retained as /home/osakanataro/.ssh/known_hosts.old
osakanataro@ubuntu2004:~/imc$
これで材料が揃ったので、スクリプトを作成する。
最初は Ciscoのcimc-ansible , cimcsdk を使用できないか検討したのですが、どちらもCIMCのホスト名変更に関する処理が実装されていないようだったので、expectコマンドによる処理を採用しました。
作成するにあたり下記を参考にしています。
・How to programmatically enable redfish on Cisco CIMC?
・Automate the UCS CLI with expect
今回作成したスクリプトは下記の様になりました。
#!/usr/bin/expect -f
# CIMCへの接続に時間がかかるようで
# 標準設定のtimeout値だとコマンド実行前にプロセスが進んでしまう
# -1 を設定すると応答があるまで待つが
# ホスト名変更処理後は再起動がかかり、-1だと再起動が終わるまで待つことになってしまい時間がかかるので20に設定
set timeout 20
set CIMCaddr "xxx.xxx.xxx.xxx"
set CIMCuser "admin"
set CIMCpass "パスワード"
set CIMChostname "新ホスト名"
spawn ssh -l $CIMCuser -t $CIMCaddr
expect_after eof {exit 1}
# ログイン処理
expect {
"*?assword:*" {
send -- "$CIMCpass\r"
}
"(yes/no*)*" {
send -- "yes\r"
expect "*?assword:*"
send -- "$CIMCpass\r"
}
# ホスト名変更時にssl証明書再作成が行われるため
# キーが変わることに対する対応
# リトライ処理が面倒だったので、古いキーを削除するところまでしか行わない
# 必要に応じて手動で再実行で対応
"WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED" {
system ssh-keygen -R $CIMCaddr
puts "\nplease re-exec this script\n"
exit 2
}
}
expect "# "
send -- "scope cimc/network\r"
expect "# "
# 現在のホスト名確認
send -- "show detail | grep Hostname \r"
expect -indices -re "Hostname: (.*)\r"
# 文字列検出に使った": "の2文字分を足す
set strst [string last ": " $expect_out(buffer)]
set strst [expr $strst + 2]
# 行の終わりの改行分を引く
set stred [string length $expect_out(buffer)]
set stred [expr $stred - 2]
set hostnamenow [string range $expect_out(buffer) $strst $stred]
puts "CIMChostname: $CIMChostname"
puts "hostname: $hostnamenow"
# ホスト名の変更が必要か?
if { "$CIMChostname" != "$hostnamenow" } {
puts "change hostname"
} else {
puts "no change"
expect "# "
send -- "top\r"
expect "# "
send -- "exit\r"
exit 0
}
# ホスト名変更
expect "# "
send -- "set hostname $CIMChostname\r"
expect "*new hostname?*"
send -- "y\r"
expect "# "
send -- "show detail | grep Hostname \r"
expect "# "
send -- "commit\r"
expect "*\[y/N] "
send -- "y\r"
# ホスト名確認
# ただし実際には再起動が掛かっているので実行できない
expect "# "
send -- "show detail | grep Hostname \r"
expect "# "
send -- "top\r"
expect "# "
send -- "exit\r"
exit 0