Python实现Linux主机自动创建互信

描述:大数据平台存在100+主机,需要给指定用户创建互信,实现集群内ssh免密码登录。

工具:python,paramiko,multiprocessing

原理:利用paramiko模拟ssh登录执行命令并获取返回结果,利用multiprocessing实现多进程,提高执行效率

运行流程:[检测主机存活]->[检测主机是否存在公钥]->[不存在公钥主机执行ssh-keygen命令]->[获取每台主机公钥]->[分发公钥至每台主机]

实现代码:

#!/usr/bin/env python
#-*- coding:utf-8 -*-
#auth:dWX278035
#update:2017/2/22 10:12 
#description:Flasky

import os,paramiko,sys,time,ConfigParser,subprocess
from multiprocessing import Process,Pool
import base64

''' 
描述:主机互信自动创建
使用方法:python linuxMutualTrust.py test.conf
参数描述:主机列表conf文件
注:
    (1)主机不存活不建立互信
    (2)主机存在公钥则不会重复生成,自动读取已有公钥
    (3)若存在互信,脚本不会清除authorized_keys,会追加公钥至authorized_keys文件
'''


''' 主机存活检测命令'''
pingCheck=['ping','-c','3','-i','0.2','-W','1']
''' ssh-keygen 命令 '''
keygenCmd='''ssh-keygen -q -t rsa -P '' -f ~/.ssh/id_rsa && echo yes || echo no'''
''' 读取pub文件 '''
readPubCmd='''test -f ~/.ssh/id_rsa.pub && cat ~/.ssh/id_rsa.pub || echo '''
''' 查看pub文件是否存在 '''
testExistsCmd='''test -f ~/.ssh/id_rsa.pub && echo yes || echo no'''
''' 追加公钥至authorized_keys中'''
addKeyCmd='''echo %s >> ~/.ssh/authorized_keys && echo yes || echo no'''
''' 消息返回分隔符,应尽量复杂'''
_mess_part='''|+|'''
''' 进程池大小 '''
PROCESSES=30

''' 初始化配置文件 '''
class InitConf:
    def __init__(self,conf_file):
        try:
            file_path = os.path.join(sys.path[0],conf_file)
            self.cf = ConfigParser.SafeConfigParser()
            self.cf.read(conf_file)
        except Exception as e:
            Log('RED','ConfigParserError:%s' % (str(e)))
            sys.exit(1)
    ''' 读取文件配置信息 '''
    def readConf(self):
        Log('GREEN','开始初始化配置信息...')
        hosts=[]
        try:
            opts = eval(self.cf.get('host','connList'))
            for opt in opts:
                host = []
                s = eval(self.cf.get('information',opt))
                host.append(s['ip'])
                host.append(s['user'])
                host.append(base64.b64decode(s['password']))
                host.append(s['port'])
                hosts.append(host)
        except Exception as e:
            Log('RED','ReadConfError:%s' % (str(e)))
            sys.exit(1)
        return hosts
        
        
'''检测主机存活 '''
def checkAloneHost(host_info):
    ip = host_info[0]
    _pingCheck = pingCheck
    _pingCheck.append(ip)
    try:
        child = subprocess.Popen(_pingCheck,stdout=subprocess.PIPE)
        _status = child.communicate()
        transmitted = _status[0].split('\n')[-3].split(',')[0].split()[0]
        received = _status[0].split('\n')[-3].split(',')[1].split()[0]
        if int(transmitted) != int(received) :
            Log('RED','[%s]:[%s] %s' % (ip,'ping',str(e)))
            return '%s%s%s' %(ip,_mess_part,'no')
        else:
            return '%s%s%s' %(ip,_mess_part,'yes')
    except Exception:
        return '%s%s%s' %(ip,_mess_part,'no')

''' 多进程检测主机存活状态'''        
def checkHostsAlive(server_list):
    Log('GREEN','开始检测主机是否存活...')
    result,_alive,_died=[],[],[]
    p = Pool(processes = PROCESSES)
    for h in server_list:
        result.append(p.apply_async(checkAloneHost,[h,]))
    p.close()
    p.join()
    for rs in result:
        if rs is None:
            break
        ip,status = rs.get().strip().split(_mess_part)
        if status == 'yes':
            _alive.append(ip)
        else:
            _died.append(ip)
    return _alive,_died

''' 初始化ssh服务 '''
def init_server():
    server = paramiko.SSHClient()
    server.load_system_host_keys()
    server.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    return server

''' 定义日志输出格式 '''
def Log(type,msg):
    date_detail = time.strftime('%Y-%m-%d %H:%M:%S')
    logText='[%s] %s' %(date_detail,msg)
    if type == 'NOMAL':
        print '\033[32;1m%s\033[0m' %(msg)
    elif type == 'GREEN':
        print '\033[32;1m[INFO ] %s\033[0m' %(logText)
    elif type == 'RED':
        print '\033[31;1m[ERROR] %s\033[0m' %(logText)
    elif type == 'YELLOW':
        print '\033[33;1m[WARN ] %s\033[0m' %(logText)

''' 命令执行函数 '''
def ssh_run(host_info,cmd,server):
    try:
        ip,username,password,port= host_info[0],host_info[1],host_info[2],host_info[3]
        server.connect(ip,int(port),username,password,timeout=5)
        stdin,stdout,stderr = server.exec_command(cmd)
        return '%s%s%s' %(ip,_mess_part,stdout.read().replace('\n',' '))
    except Exception as e:
        Log('RED','[%s]:[%s] %s' % (ip,cmd,str(e)))
        return '%s%s%s' %(ip,_mess_part,'error')

''' 执行命令 '''
def exec_pools_cmd(server_list,cargs):
    result=[]
    p = Pool(processes = PROCESSES)
    for h in server_list:
        result.append(p.apply_async(ssh_run,[h,] + cargs))
    p.close()
    p.join()
    return result
   
''' 判断当前用户.ssh目录下公钥是否存在 '''   
def checkExistsKey(server_list,server):
    _exists,_not_exists,_error=[],[],[]
    result = exec_pools_cmd(server_list,[testExistsCmd,server])
    for rs in result:
        ip,status = rs.get().strip().split(_mess_part)
        if status == 'yes':
            _exists.append(ip)
        elif status == 'no':
            _not_exists.append(ip)
        else:
            _error.append(ip)
    return _exists,_not_exists,_error

''' 读取当前用户.pub文件,并返回结果信息'''
def readPubInfo(server_list,server):
    Log('GREEN','开始读取主机id_rsa.pub文件...')
    _authorized_keys=[]
    result = exec_pools_cmd(server_list,[readPubCmd,server])
    for rs in result:
        ip,keys = rs.get().split(_mess_part)
        if keys != "":
            _authorized_keys.append(keys)
        else:
            Log('RED','[%s] %s' %(ip,'Read id_rsa.pub error!'))
    return _authorized_keys
    
''' 登录主机执行ssh-keygen命令 '''
def exec_ssh_keygen(server_list,server):
    Log('GREEN','开始执行ssh-keygen...')
    _success,_error=[],[]
    result = exec_pools_cmd(server_list,[keygenCmd,server])
    for rs in result:
        ip,status = rs.get().strip().split(_mess_part)
        if status == 'yes':
            _success.append(ip)
        else:
            _error.append(ip)
    return _success,_error
    
''' 检查主机是否存在公钥 '''
def checkStatus(server_list,server):
    _exists_hosts,_not_exists_hosts,_error_hosts = [],[],[]
    print('\n-------------检查结果----------------')
    _exists,_not_exists,_error = checkExistsKey(server_list,server)
    print('已存在:[%s]个' %(len(_exists)))
    if len(_not_exists_hosts) >0 :
        print('不存在:[%s]' %(len(_not_exists)))
    if len(_error) > 0 :
        print('执行命令错误主机:%s' %(_error))
    print('-------------------------------------\n')
    for se in server_list:
        if se[0] in _not_exists:
            _not_exists_hosts.append(se)
        elif se[0] in _exists:
            _exists_hosts.append(se)
        else:
            _error_hosts.append(se)
    return _exists_hosts,_not_exists_hosts,_error_hosts
    
''' 将公钥写入authorized_keys'''
def writeKeys(server_list,server,keys):
    Log('GREEN','开始写入authorized_keys...')
    add_cmd = addKeyCmd %(keys)
    result = exec_pools_cmd(server_list,[add_cmd,server])
    for rs in result:
        ip,status = rs.get().strip().split(_mess_part)
        if status != 'yes':
            Log('RED','[Write keys error] %s %s' %(ip,status))
    

''' 主函数 '''
def main(conf_name):
    p = InitConf(conf_name)
    server_list = p.readConf()
    server = init_server()
    alive_host = []
    
    _alive,_died = checkHostsAlive(server_list)
    Log('GREEN','存活主机: %s/%s ' %(len(_alive),len(server_list)))
    if len(_died) > 0:
        Log('RED','死亡主机列表: %s') %(str(_died))
        for _x in server_list:
            if _x[0] in _alive:
                alive_host.append(_x)
    else:
        alive_host = server_list
    Log('GREEN','执行前ssh-keygen检查...')
    chk_ok_hosts,chk_need_hosts,chk_error_hosts=checkStatus(alive_host,server)
    if len(chk_need_hosts) > 0:
        _exec_success,_exec_error = exec_ssh_keygen(chk_need_hosts,server)
        Log('GREEN','执行成功:[%s]个' %(len(_exec_success)))
        if len(_exec_error) > 0 :
            Log('RED','执行ssh-keygen失败列表:%s' %(_exec_errror))
        Log('GREEN','执行后ssh-keygen检查...')
        chk_ok_hosts,chk_need_hosts,chk_error_hosts=checkStatus(alive_host,server)
        if len(chk_error_hosts) > 0:
            Log('RED','互信失败列表:%s' %(chk_error_hosts))
    else:
        Log('YELLOW','所有主机均存在公钥!!!')
        
    _authorized_keys = readPubInfo(chk_ok_hosts,server)
    for keys in _authorized_keys:
        writeKeys(chk_ok_hosts,server,keys)
    
    

''' 程序入口 '''
if __name__ == '__main__':
    if len(sys.argv) < 2:
        Log('RED','Usage: python %s test.conf' %(sys.argv[0]))
        sys.exit(1)
    else:
        conf_name = sys.argv[1]
        main(conf_name)

注: (1)依赖的conf文件参考前两章中配置文件生成。 (2)代码在小集群中运行通过,可能存在BUG,如有发现请反馈,谢谢。

转载于:https://my.oschina.net/cdsc/blog/856813

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值