使用python脚本一个简单的搭建ansible集群

1.环境说明:

角色 主机名 ip地址
控制主机 server 192.168.174.150
受控主机/被管节点 client1 192.168.174.151
受控主机/被管节点 client2 192.168.174.152

2.安装python和pip包

yum install -y epel-release

yum install -y python python-pip

3.pip安装依赖库

pip install pexpect     # 此库用相当于linux中的expect命令

4.完整脚本:

# coding=UTF-8
import sys,os,pexpect,subprocess

host_controller="192.168.174.150"                            # 控制节点IP地址
host_addresses=["192.168.174.151","192.168.174.152"]           # 客户端们的IP地址
host_domains=["client1","client2"]                          # 客户端们的域名
host_username="root"                                         # ssh连接的用户,控制端的用户为root
host_passwd="123456"                                         # ssh连接的用户密码
ansible_hostGroup="clients"


# 本地创建ssh公钥
if os.path.exists("/root/.ssh/id_rsa.pub") == True:
	print("\033[32m"+"ssh公钥已创建"+"\033[0m")                # 输出绿色字体
else:
	print("\033[32m"+"ssh公钥未创建,开始创建"+"\033[0m")
	child = pexpect.spawn('ssh-keygen -t rsa -b 1024')
	child.expect('Enter file in which to save the key')
	child.sendline('')
	child.expect('Enter passphrase')
	child.sendline('')
	child.expect('Enter same passphrase again')
	child.sendline('')

	child.expect(pexpect.EOF)               # 用于等待子进程的结束
	print(child.before.decode())            # 等待命令执行完毕并打印输出信息
	print("\033[32m" + "ssh公钥已创建" + "\033[0m")
	print("\n")


# 向被控主机添加公钥的方法
def add_ssh_public_key_client(address,username,password):
	print("\033[32m"+"{}正在被添加公钥".format(address)+"\033[0m")
	# BatchMode=yes:表示使SSH在连接过程中不会提示输入密码,而直接尝试免密连接,-o ConnectTimeout=5:表示限制连接超时时间为5秒
	public_key_flag=os.system("ssh {}@{} -o BatchMode=yes -o ConnectTimeout=5 'exit'".format(username,address))
	if public_key_flag== 0:
		print("\033[32m" + "{}已经可以ssh连接".format(address) + "\033[0m")
		return
	child = pexpect.spawn('ssh-copy-id -i /root/.ssh/id_rsa.pub {}@{}'.format(username,address))
	try:
		child.expect('Are you sure you want to continue connecting')
	except pexpect.TIMEOUT:       # 如果try块中的咨询超时5秒没有出现就会出现异常pexpect.TIMEOUT
		print("\033[32m"+"{}已经不是首次ssh连接了".format(address)+"\033[0m")
	else:                         # 是否回答咨询yes
		child.sendline('yes')
	finally:
		child.expect('password')
		child.sendline(password)
	child.expect(pexpect.EOF)               # 用于等待子进程的结束
	print(child.before.decode())            # 等待命令执行完毕并打印输出信息
# 测试ssh连接的方法
def test_ssh_connection(all_flag,address,username):
	print("\033[32m" + "{}测试是否可以ssh连接".format(address) + "\033[0m")
	flag=os.system('ssh {}@{} -o ConnectTimeout=5 "exit"'.format(username,address))
	if flag==0:
		print("\033[32m" + "Success: {}可以ssh免密连接".format(address) + "\033[0m")
	else:
		print("\033[1;31m" + "Failed: {}ssh免密连接失败".format(address) + "\033[0m")     # 输出红色字体
		all_flag=1
	return all_flag

# 本地的密钥开始加入被控制主机
for i in range(0, len(host_addresses)):
	add_ssh_public_key_client(host_addresses[i],host_username,host_passwd)
	print("\n")
# 测试ssh连接
for i in range(0, len(host_addresses)):
	final_flag=test_ssh_connection(0,host_addresses[i],host_username)
if final_flag ==1:
	sys.exit("ssh测试失败,请检查!")
else:
	print("\033[32m" + "Success: 全部可以ssh免密连接" + "\033[0m")
print("\n")


# 配置防火墙和selinux
os.system("systemctl stop firewalld;systemctl disable firewalld")
os.system("sed -i 's/SELINUX=.*/SELINUX=disabled/' /etc/selinux/config")
for i in range(0, len(host_addresses)):
	print("\033[32m" + "{}正在配置防火墙和selinux".format(host_addresses[i]) + "\033[0m")
	fir_flag=os.system('ssh {}@{} "systemctl stop firewalld;systemctl disable firewalld"'.format(host_username,host_addresses[i]))
	if fir_flag!=0:
		print("\033[1;31m" + "Failed: 防火墙修改失败" + "\033[0m")
		sys.exit("请检查!")
	sel_flag=os.system("ssh {}@{} 'sed -i 's/SELINUX=.*/SELINUX=disabled/' /etc/selinux/config'".format(host_username,host_addresses[i]))
	if sel_flag!=0:
		print("\033[1;31m" + "Failed: selinux修改失败" + "\033[0m")
		sys.exit("请检查!")
print("\n")


# 配置域名映射
print("\033[32m" + "本地开始配置域名映射" + "\033[0m")
with open("/etc/hosts","a") as f:
	for i in range(0, len(host_addresses)):
		f.write("{} {}\n".format(host_addresses[i],host_domains[i]))

# 使用域名首次ssh连接
# 首次域名ssh连接的方法
def first_domain_name_con(domain,username,password):
	print("\033[32m"+"{}首次ssh连接".format(domain)+"\033[0m")
	# BatchMode=yes:表示使SSH在连接过程中不会提示输入密码,而直接尝试免密连接,-o ConnectTimeout=5:表示限制连接超时时间为5秒
	os.system("ssh -o BatchMode=yes -o ConnectTimeout=5 {}@{} 'exit' &> /dev/null".format(username, domain))
	first_domain_flag = os.system("ssh -o BatchMode=yes -o ConnectTimeout=5 {}@{} 'exit'".format(username, domain))
	if first_domain_flag == 0:
		print("\033[32m" + "{}已经可以ssh连接".format(domain) + "\033[0m")
		return
	child = pexpect.spawn('ssh {}@{} "exit"'.format(username,domain))
	try:
		connecting_tuple = child.expect('Are you sure you want to continue connecting')
	except pexpect.TIMEOUT:
		print("\033[32m"+"{}已经不是首次ssh连接了".format(domain)+"\033[0m")
	else:
		child.sendline('yes')
	child.expect(pexpect.EOF)               # 用于等待子进程的结束
	print(child.before.decode())            # 等待命令执行完毕并打印输出信息

for i in range(0, len(host_addresses)):
	first_domain_name_con(host_domains[i],host_username,host_passwd)
	print("\n")


# 配置chrony服务器
print("\033[32m" + "本地配置chrony" + "\033[0m")
chrony_flag = result=os.system("yum install -y chrony")
if chrony_flag != 0:
	print("\033[1;31m" + "Failed: 本地chrony安装失败" + "\033[0m")
	sys.exit("请检查!")
os.system("sed -i 's/#allow 192.168.0.0\/16/allow 192.168.174.0\/24/' /etc/chrony.conf")
os.system("sed -i 's/#local stratum 10/local stratum 10/' /etc/chrony.conf")
os.system("systemctl restart chronyd && systemctl enable chronyd &> /dev/null")
os.system("sleep 5")
os.system("timedatectl set-ntp true")
for i in range(0, len(host_addresses)):
	print("\033[32m" + "{}配置chrony".format(host_addresses[i]) + "\033[0m")
	chrony_flag = os.system("ssh {}@{} 'yum install -y chrony'".format(host_username,host_addresses[i]))
	if chrony_flag != 0:
		print("\033[1;31m" + "Failed: {}chrony安装失败".format(host_addresses[i]) + "\033[0m")
		sys.exit("请检查!")
	sed_chrony_delete = "sed -i '{}' /etc/chrony.conf".format('/^server/d')
	sed_chrony_add = "sed -i '{}' /etc/chrony.conf".format("2a\server {} iburst".format(host_controller))
	chrony_service="systemctl restart chronyd && systemctl enable chronyd &> /dev/null"
	chrony_time="chronyc sources -v | sed -n '{}'".format("/^\^\* {}/p".format(host_controller))
	os.system('ssh {}@{} "{}"'.format(host_username,host_addresses[i],sed_chrony_delete))
	os.system('ssh {}@{} "{}"'.format(host_username,host_addresses[i],sed_chrony_add))
	os.system('ssh {}@{} "{}"'.format(host_username,host_addresses[i],chrony_service))
	os.system('ssh {}@{} "timedatectl set-ntp true"'.format(host_username, host_addresses[i]))
	os.system("sleep 5")
	chrony_output = subprocess.check_output('ssh {}@{} "{}"'.format(host_username,host_addresses[i],chrony_time) ,shell=True)
	# 输出结果
	print(chrony_output)
	if chrony_output == "" or chrony_output is None:
		print("\033[1;31m" + "Failed: {}时间同步失败".format(host_addresses[i]) + "\033[0m")
		sys.exit("请检查!")
print("\n")


# 安装ansbile
print("\033[32m" + "本地安装ansible软件" + "\033[0m")
os.system("yum install -y epel-release && yum install -y ansible")
try:
	ansible_output = subprocess.check_output("ansible --version", shell=True)
except subprocess.CalledProcessError:
	print("\033[1;31m" + "Failed: 本地安装ansible失败" + "\033[0m")
	sys.exit("请检查!")
finally:
	print("\033[32m" + "安装的ansible软件版本如下: " + "\033[0m")
	print(ansible_output)

# /etc/ansible/hosts文件中添加主机租
print("\033[32m" + "修改配置文件/etc/ansible/hosts" + "\033[0m")
with open('/etc/ansible/hosts','a') as f:
	f.write("["+ansible_hostGroup+"]"+"\n")
	for i in range(0, len(host_domains)):
		f.write(host_domains[i] + "\n")



# 测试
print("\033[32m" + "测试ansible命令" + "\033[0m")
try:
	ansible_hoc_output = subprocess.check_output("ansible clients -a uptime", shell=True)
except subprocess.CalledProcessError:
	print("\033[1;31m" + "Failed: 测试失败无法使用ansible命令" + "\033[0m")
	sys.exit("请检查!")
finally:
	print("\033[32m" + "测试结果如下" + "\033[0m")
	print("\033[1;33;40m"+ansible_hoc_output+"\033[0m")
相关推荐
Auc247 分钟前
使用scrapy框架爬取微博热搜榜
开发语言·python
梦想画家24 分钟前
Python Polars快速入门指南:LazyFrames
python·数据分析·polars
程序猿000001号37 分钟前
使用Python的Seaborn库进行数据可视化
开发语言·python·信息可视化
API快乐传递者1 小时前
Python爬虫获取淘宝详情接口详细解析
开发语言·爬虫·python
公众号Codewar原创作者1 小时前
R数据分析:工具变量回归的做法和解释,实例解析
开发语言·人工智能·python
FL16238631291 小时前
python版本的Selenium的下载及chrome环境搭建和简单使用
chrome·python·selenium
巫师不要去魔法部乱说1 小时前
PyCharm专项训练5 最短路径算法
python·算法·pycharm
Chloe.Zz1 小时前
Python基础知识回顾
python
骑个小蜗牛1 小时前
Python 标准库:random——随机数
python
Trouvaille ~1 小时前
【机器学习】从流动到恒常,无穷中归一:积分的数学诗意
人工智能·python·机器学习·ai·数据分析·matplotlib·微积分