Requirements:
Multiple commands can be executed asynchronously
For multiple machines
>>:run "Df-h"--hosts 192.168.3.55 10.4.3.4
Task id:45334
>>: Check_task 45334
>>:
Thinking:
1, decomposition of the functions that need to be implemented
(1) The command is sent to the remote host execution, the command placed in the queue, and then sent to the host processing, the host after the results are placed in the queue, the person who submits the command.
Requires 2 processes, one client, submit commands, fetch results, a server, process commands, put results
(2) When sending a command, Exchange decides which queue to put the message to, each server takes its own command, uses IP as the filter binding_key
(3) When the results are taken, the default exchange is used to put the reply_to directly into the queue.
Server Side
1 #rabbitmqserver= ' 10.21.147.189 '2Rabbitmqserver='localhost'3 4 ImportPika5 ImportOS6 ImportSocket7 8 classServer (object):9 def __init__(self):Tenself.connection=Pika. Blockingconnection (Pika. Connectionparameters (rabbitmqserver)) OneSelf.channel=Self.connection.channel () ASelf.channel.exchange_declare (exchange='cmd', exchange_type='Topic') -Self.queue_default = Self.channel.queue_declare (exclusive=True) -Self.quname =Self.queue_default.method.queue the #The format for getting the native IP as Binding_key,binding_key is a sequence of strings separated by the message that the client sends, Routing_key satisfies the server's Binding_key matching principle, You'll join the server-connected queue. -self.hostip=Socket.gethostbyname (Socket.gethostname ()) -self.binding_key='#.'+self.hostip+'.#' - Print("Binding_key:%s"%Self.binding_key) +Self.channel.queue_bind (Queue=self.quname, exchange='cmd', routing_key=Self.binding_key) -Self.channel.basic_qos (prefetch_count=1) + ASelf.channel.basic_consume (self.execcmd,queue=self.quname,no_ack=False) at self.channel.start_consuming () - return - - defExecCmd (self,ch,method,props,body): -Cmd=Bytes.decode (body) - Print("[*] Received%s"%cmd) inresult =os.popen (cmd). Read () - Print(Result) to Ch.basic_publish ( +Exchange="', -routing_key=props.reply_to, theproperties=Pika. Basicproperties ( *Correlation_id=props.correlation_id $ ),Panax Notoginsengbody=result - ) theCh.basic_ack (delivery_tag=Method.delivery_tag) + return A theSe=server ()
Client Side
1 ImportPika2 ImportUUID3 4 #rabbitmqserver= ' 10.21.147.189 '5Rabbitmqserver='localhost'6 7 classClient (object):8 def __init__(self):9Self.cmdid={}TenSelf.connection =Pika. Blockingconnection (Pika. Connectionparameters (rabbitmqserver)) OneSelf.channel =Self.connection.channel () ASelf.channel.exchange_declare (exchange='cmd', exchange_type='Topic') - - #write back the queue of result is generated by default, need to get name, exclusive True indicates that only this client consumes this queue theSelf.result=self.channel.queue_declare (exclusive=True) -Self.resultqueue=Self.result.method.queue - return - + defShowcmdid (self): - Print("The -----command is identified as follows:--------") + forId,hostsinchSelf.cmdid.items (): A Print("cmdid:%s run on hosts:%s"%(id,hosts)) at return - - defCallcmd (self,cmdinput): - #if the call command, the format is call+ "command" +--host + a string of IP addresses - #first judge the format right, at least 4 parameters -msglist=Cmdinput.split () inargnum=Len (msglist) - ifArgnum<4: to Print("wrong cmd. Input again.") + return - #Second, the command is the second argument, and the command is marked with double quotes, so strip themsg = Msglist[1].strip ("\"") * #then, the third one is--host, and the fourth one starts with Ip,ip as Routing_key. $Routing_key=msglist[3]Panax NotoginsengI=4 - whileI <argnum: therouting_key=routing_key+'.'+Msglist[i] +I+=1 A Print("Routing_key:%s"%Routing_key) the #then, generate a random number that takes him as a property parameter of the message +Self.corr_id=Str (UUID.UUID4 ()) -Self.cmdid[self.corr_id]=msglist[3:] $ Print("command ID:%s"%self.corr_id) $ #then, send the message to exchange,routing_key,corr_id as a parameter to publish - Self.channel.basic_publish ( -Exchange='cmd', therouting_key=Routing_key, -body=msg,Wuyiproperties=Pika. Basicproperties ( thereply_to=Self.resultqueue, -Correlation_id=self.corr_id Wu ) - ) About Print("[*] Send message%s"%msg) $ return - - defOn_response (self,ch,method,props,body): - ifself.targetcmdid==props.correlation_id: ASelf.response=Bytes.decode (body) + Print(Self.response) theCh.basic_ack (delivery_tag=Method.delivery_tag) - return $ the defgetres (self,cmdinput): theMsglist =Cmdinput.split () theSelf.targetcmdid=msglist[1] theSelf.response=None -Self.channel.basic_consume (self.on_response,queue=self.resultqueue) in whileSelf.response isNone: the self.connection.process_data_events () the return About theCl=Client () the whileTrue: theMsginput=input (">>:"). Strip () + ifMsginput.startswith ('Pager'): - cl.callcmd (msginput) the elifMsginput.startswith ('Get'):Bayi cl.getres (msginput) the elifMsginput.startswith ('Show'): the Cl.showcmdid () - elifMsginput.startswith ('Exit'): - cl.connection.close () the exit (0) the Else: the Print("wrong cmd. Input again.") the Continue
At present, there is no verification of remote login RABBITMQ server, it should be required to configure the user name password, cannot use the default guest/guest. However, the above functions are realized.
python--host management based on RABBITMQ RPC implementation