Approximate idea:
The ideal effect is to achieve a small function similar to saltstack or ansible, such as entering Python3 automatic.py-g dsp-c ' W ' at the command line
Output:
B ' 18:24:20 up 3:44, 2 users, Load average:0.00, 0.00, 0.00\nuser TTY from [email protected] IDLE jcpu PCPU what\nroot PT s/0 192.168.0.101 17:26 4:11 0.02s 0.02s-bash\nroot pts/2 192.168.0.101 17:24 1.00s 0.51s 0.12s python3 automat\n '
Module used: Paramiko: For remote command execution, support for key and user password login
Optparse: Parsing the command line
Logging: Logging
Configparser: Parsing the configuration file
Multiprocessing: Enable multi-process mode
The directory structure is as follows:
Conf is the default profile, log is the default journal file, automatic main program, logger log Program
The source code is as follows: Automatic
#!/usr/bin/env python3#-*-coding:utf-8-*-import paramikofrom optparse import optionparserimport configparserimport os , Sysfrom multiprocessing Import poolimport logger #插入日志模块 ' default profile path and log file path ' Conf_path = Os.path.abspath ( Os.path.join (Os.path.dirname ('. '), ' conf ')) Log_path = Os.path.abspath (Os.path.join ('. '), ' LOG ')) ' ' Parse config file, set default sections and Options,pkey_file specify key file name, fork means 5 process ' Def configparser (group) is turned on by default: Config = Configparser. Configparser () config[' DEFAULT ' = {' user ': ' Root ', ' Port ': ' passwd ' ': ' 123456 ', ' pkey_file ': ', ' Host ': '} config[' default '] = {' Conf_pa Th ': Conf_path, ' Log_path ': log_path, ' fork ': 5} If not os.path.exists (CO Nf_path): #判断配置文件是否存在, does not exist create and write default configuration fp = open (Conf_path, ' W ') config.write (FP) fp.close () Else: Config.read (Conf_path) #读取配置文件, get to group optIons values try:section = config.sections () IP = config.get (group, ' host ') user = con Fig.get (group, ' user ') port = config.get (group, ' port ') passwd = Config.get (group, ' passwd ') Pkey_file = Config.get (group, ' pkey_file ') fork = config.get (' default ', ' fork ') Log_path = Config.get (' Default ', ' Log_path ') except Exception:print ("group is NOT exists") Else:return Section,ip,user,port,passwd,pkey_file,fork,log_pathdef Remote_cmd (ip,user,passwd,cmd,pkey_file=none): # Calling the SSH Client execution command returns the result ssh = Paramiko. Sshclient () Ssh.set_missing_host_key_policy (Paramiko. Autoaddpolicy ()) If Pkey_file: #如果传入了密钥文件, key mode is used to login key = Paramiko. Rsakey.from_private_key_file (Pkey_file) ssh.connect (Hostname=ip,username=user,pkey=key) ssh.connect (Hostname=ip, USERNAME=USER,PASSWORD=PASSWD) Stdin,stdout,stderr = Ssh.exec_command(cmd) If Stdout:result = Stdout.read () Else:result = Stderr.read () return result "call sftp to upload the downloaded file ' Class SFTP (object): Def __init__ (self,ip,port,user,passwd,src_file,dst_file,pkey_file=none): Self.ip = IP self.port = Int (port) self.user = User SELF.PASSWD = passwd self.src_file = Src_file self. Dst_file = Dst_file Self.pkey_file = Pkey_file def remote_transport (self): s = Paramiko. Transport ((self.ip,self.port)) if Self.pkey_file: #如果传入了密钥文件, key mode is used to login key = Paramiko. Rsakey.from_private_key_file (Self.pkey_file) s.connect (Username=self.user,password=none,pkey=key) s.conn ECT (username=self.user,password=self.passwd) sftp = Paramiko. Sftpclient.from_transport (s) return sftp def get (self): #下载文件 sftp = Self.remote_transport () s Ftp.get (Self.src_file,self.dst_file) def put (self): #上传文件 sftp = Self.remote_transport () sftp.Put (self.src_file,self.dst_file) "Parse the command line, using Optparse, I use the python3.6 version" Def opt (): parser = Optionparser ("Usage:%prog [-G GROUP] [-C COMMAND] ") parser.add_option ('-G ', '--group ', dest = ' group ', action = ' st Ore ', default = True, help= ' GROUP ') parser.add_option ('-C ', '--command ', dest = ' command ', action= ' store ', default = True, help= "command") Options,args = Parser.parse_args () return Options,args "" is based on the command followed by-C to determine whether the SSH Remote execution command or using SFTP upload Download the file operation and log, SRC is the source file, DST for the target file, F is to carry out get or put,get, put means upload "def multi_pool (Cmd,ip,user,port,passwd,pkey_file, Log_path): If Cmd.startswith (' get ') or Cmd.startswith (' put '): src = cmd.split () [1] dst = Cmd.split () [2] f = cmd.split () [0] sf = SFTP (ip,port,user,passwd,src,dst,pkey_file) if Hasattr (sf,f): #使用反射, reduce judgment Func = GetAttr (sf,f) func () Logger.loggs ("%s%s"% (Ip,cmd), log_path) Else:result = Remote_cmd (IP,USER,PASSW D,cmd,pkey_file) Logger.loggs ("%s%s"% (Ip,cmd), Log_path) print (result) ' main function, read command-line arguments and get configuration file values, turn on multi-process, make With Process Pool "def main (): Options,args = opt () groups = Options.group cmd = Options.command try:sec,ip,user,p Ort,passwd,pkey_file,fork,log_file = Configparser (groups) except Exception:print ("Configparser error") Else: p = Pool (int (fork)) If groups in Sec:for I in Ip.split (', '): P.apply_async (func= Multi_pool,args= (Cmd,i,user,port,passwd,pkey_file,log_file)) P.close () P.join () if __name__ = = ' __main __ ': Main ()
Logger Source:
#!/usr/bin/env Python3#-*-coding:utf-8-*-ImportLogging" "MSG is log information that needs to be logged, and F is the log path" "defLoggs (msg,f): Logger=Logging.getlogger () logger.setlevel (logging. DEBUG) FH=logging. Filehandler (f) fh.setlevel (logging. DEBUG) Formatter= Logging. Formatter ('% (asctime) s-% (name) s-% (levelname) s-% (message) s')#Log FormatFh.setformatter (Formatter) logger.addhandler (FH) logger.debug (msg)if __name__=='__main__': Msg="'F="'Loggs (msg,f)
The basic implementation of the expected function, due to time reason flowchart is not drawn, using the python3.6 version in the centos6.7 version of the successful run
Python Learning Path (ii) Development of bulk host management tools