我对这些脚本很陌生,因此需要帮助来解决这个问题。
我们有大约 3000 台虚拟机和 450 台物理服务器,它们都是基于 Linux 的服务器(其中一些是从 9.x 开始的 ubuntu,一些是从 8.X 开始的 Susu,大多数是从 4.x 到 7.4 的 RHEL),我需要在所有这些服务器各自的 /etc/hosts 文件中添加一些带有 IP 详细信息的主机名条目。
我在每台服务器上都有不同的用户,他们拥有完整的 sudoers 访问权限,因此我创建了一个包含主机名、用户名和密码格式的 CSV 文件。其中包含登录所需的详细信息。文件名为“hostname_logins.csv”
我需要将一个文件(即 hostname_list)上传到每个服务器,然后在每个服务器的主机文件中更新相同的详细信息。
我将使用一台 RHEL 6 服务器运行此脚本。(所有其他主机都可以从此服务器解析并可访问,我已经确认了这一点。)
因此需要帮助来修复该脚本。
脚本不确定其中有什么问题,因为我对脚本还不熟悉:
#!/bin/bash
while read hostname_login user_name user_password
do
scp -p ./hostname_list $user_name:$user_password@$hostname_login:/tmp
ssh -eS $user_name:$user_password@$hostname_login [bash -c "echo rishee | sudo -S mv /tmp/hostname_list ./hostname_list && cp -p /etc/hosts /etc/hosts.bkp && cat ./hostname_list >> /etc/hosts && rm -f ./hostname_list"]
done < hostname_logins.csv
我需要将其作为可以在所有这些服务器上运行的单个脚本。提前致谢。
答案1
我还没有尝试在 shell 中读取 CSV,所以这将是一个不完整的回复。我通常使用 Perl 或 AWK 来做这样的事情。
第一个问题是 shell 使用空格来分隔行中的字段,因此您必须用“,”(逗号)分隔字段。因此
IFS=","
while read hostname_login....
然而,如果它是“真正的” CSV,那么它可能看起来像这样
"hostname_login",username,"userpass"
即,是否带有引号具有可变性。如果没有,您就没事了。
我不熟悉你的 ssh 中的 [bash -c] 语法,因此无法评论。我倾向于使用单引号 (')。
我认为您可以跳过将 /tmp/hostname_list 迁移到主目录的步骤。您只需执行
ssh -eS $user_name:$user_password@$hostname_login [echo rishee | sudo -S cp -p /etc/hosts /etc/hosts.bkp && cat /tmp/hostname_list >> /etc/hosts && rm -f /tmp/hostname_list"]
一旦我确定那个 [ ] 东西是否真实存在,我就会更新我的答案。我只在模式匹配上下文中使用过它,并且作为条件语句中 test 的别名。(即for filename in hostname[0-9]; do ...
或if [ -n "$var" ]; then...
)
ssh+sudo 也存在一些问题,即 ssh 无法分配 pty,而 sudo 会因此而发脾气。我不得不四处寻找,但我觉得我们通过调整 /etc/sudo.config 或其他方法解决了这个问题,但这并不是最佳选择。
如上所述,您只需对初始 mv /tmp/hostname ./hostname 执行 sudo。
就我个人而言,由于您的文件内容是静态的,我会通过预先写出您想要在另一端运行的内容并复制它来简化整个转义序列:
cat > hostname_list_script.sh
#/bin/bash
if ! cp -p /etc/hosts /etc/hosts.bkp; then
echo "Failed to backup /etc/hosts"
exit 1
fi
cat <<EOM >> /etc/hosts
^D
cat hostname_list >> hostname_list_script.sh
EOM
^D
您现在复制的文件顶部有少量文本,您希望附加的内容,底部有一些文本,即
[...]
fi
cat <<EOM >> /etc/hosts
10.90.70.5 hostname1
10.90.70.4 hostname2
10.90.70.6 hostname3
EOM
然后你的主脚本可以读取
#/bin/bash
IFS=","
while read hostname_login user_name user_password
do
scp -p ./hostname_list_script.sh $user_name:$user_password@$hostname_login:/tmp
echo sudo_password | ssh -t -eS $user_name:$user_password@$hostname_login '/usr/bin/sudo -S -s bash /tmp/hostname_list_script.sh'
done < hostname_logins.csv
实际上,我发现了另一个问题。我认为您需要根据登录信息更改传递给 sudo 的密码:
echo $user_password | ssh ....
我认为,当每台机器的登录密码不同时,sudo 是否会在所有机器上采用静态密码是值得怀疑的。
买家自慎:我还没有测试上述提到的 pty 可用性问题,以及是否不需要引用bash script
sudo 的参数。在我看来,这是可行的,但你可能需要调整一下引用才能正确。我不需要更新我的 /etc/hosts 文件,所以我没有测试它。
另外,正如 Spiderice 所提到的,在您的一台机器上安装 BIND(DNS 名称服务器)可能更容易,只需执行一个脚本将该机器的 IP 地址添加到 /etc/resolv.conf 而不是附加到 /etc/hosts。当我第一次开始阅读您的问题时,我想知道我们是否也必须参与删除主机和重复删除您的 /etc/hosts 条目。我想知道几个月后,当您今天添加的一些主机消失或重命名时,这是否可能是下一个问题。
我建议,要弄清楚如何让这样的事情发挥作用,可以分部分进行。因此,首先调试 while 循环:
#!/bin/bash
while read hostname_login user_name user_password
do
echo "$hostname_login / $user_name / $user_password"
done < hostname_logins.csv
然后从 hostname_logins.csv 文件中获取前 4 行并改进 while 循环的内容,首先在 while 循环中添加执行文件复制的操作。接下来从命令行执行 ssh 执行行,转到一个主机。完成所有操作后,您可以将改进后的行粘贴到脚本中的 while 循环中。再次在您的 4 台主机测试集上进行测试,一旦您确定已完成所有操作,请将其提供给它您的完整主机列表。