From b1486d4aeb0e37e0cb8fd31110af1e52d9a155fe Mon Sep 17 00:00:00 2001 From: Ulas Kozat Date: Fri, 27 May 2016 23:26:54 -0700 Subject: refactored codes, added standalone CLI client, option of interactive vs. standalone CLI Change-Id: I262aaf4f5908c0d9b7eae87699c49ba385437589 Signed-off-by: Ulas Kozat --- DominoClient.py | 279 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 176 insertions(+), 103 deletions(-) (limited to 'DominoClient.py') diff --git a/DominoClient.py b/DominoClient.py index 51a765b..c0a3cf1 100755 --- a/DominoClient.py +++ b/DominoClient.py @@ -24,6 +24,10 @@ from dominoRPC import Communication from dominoRPC.ttypes import * from dominoRPC.constants import * +from dominoCLI import DominoClientCLI +from dominoCLI.ttypes import * +from dominoCLI.constants import * + from thrift import Thrift from thrift.transport import TSocket from thrift.transport import TTransport @@ -40,7 +44,6 @@ class CommunicationHandler: self.log = {} def __init__(self, dominoclient): - global DOMINO_SERVER_IP, DOMINO_SERVER_PORT self.log = {} self.dominoClient = dominoclient try: @@ -96,6 +99,24 @@ class CommunicationHandler: def closeconnection(): self.transport.close() + +class CLIHandler: + def __init__(self): + self.log = {} + + def __init__(self, dominoclient, CLIservice): + self.log = {} + self.dominoClient = dominoclient + self.CLIservice = CLIservice + + def d_CLI(self, msg): + logging.info('Received CLI %s', msg.CLI_input) + + self.CLIservice.process_input(msg.CLI_input) + + CLIrespmsg = CLIResponse() + CLIrespmsg.CLI_response = "Testing..." + return CLIrespmsg def read_templatefile(temp_filename): f = open(temp_filename, 'r') @@ -104,108 +125,79 @@ def read_templatefile(temp_filename): return lines class DominoClientCLIService(threading.Thread): - def __init__(self, dominoclient, communicationhandler): + def __init__(self, dominoclient, communicationhandler, interactive): threading.Thread.__init__(self) self.dominoclient = dominoclient self.communicationhandler = communicationhandler + self.interactive = interactive + + def process_input(self, args): + + try: + if args[0] == 'heartbeat': + self.dominoclient.heartbeat() + + elif args[0] == 'publish': + opts, args = getopt.getopt(args[1:],"t:",["tosca-file="]) + if len(opts) == 0: + print '\nUsage: publish -t ' + return + + for opt, arg in opts: + if opt in ('-t', '--tosca-file'): + toscafile = arg + + self.dominoclient.publish(toscafile) + + elif args[0] == 'subscribe': + labels = [] + templateTypes = [] + opts, args = getopt.getopt(args[1:],"l:t:",["labels=","ttype="]) + for opt, arg in opts: + if opt in ('-l', '--labels'): + labels = labels + arg.split(',') + elif opt in ('-t', '--ttype'): + templateTypes = templateTypes + arg.split(',') + + #check if labels or supported templates are nonempty + if labels != [] or templateTypes != []: + self.dominoclient.subscribe(labels, templateTypes) + + elif args[0] == 'register': + self.dominoclient.start() + + except getopt.GetoptError: + print 'Command is misentered or not supported!' + def run(self): global DEFAULT_TOSCA_PUBFILE - while True: - sys.stdout.write('>>') - input_string = raw_input() - args = input_string.split() - if len(args) == 0: - continue - - labels = [] - templateTypes = [] - - #process input arguments - try: + if self.interactive == "TRUE": + flag = True + else: + flag = False + + if flag: #interactive CLI, loop in while until killed + while True: + sys.stdout.write('>>') + input_string = raw_input() + args = input_string.split() + if len(args) == 0: + continue + sys.stdout.write('>>') - if args[0] == 'heartbeat': - logging.info('%d Sending heatbeat', self.dominoclient.UDID) - hbm = HeartBeatMessage() - hbm.domino_udid = self.dominoclient.UDID - hbm.seq_no = self.dominoclient.seqno - try: - hbm_r = self.communicationhandler.sender.d_heartbeat(hbm) - logging.info('heart beat received from: %d ,sequence number: %d' , hbm_r.domino_udid, hbm_r.seq_no) - except (Thrift.TException, TSocket.TTransportException) as tx: - logging.error('%s' , tx.message) - except (socket.timeout) as tx: - self.dominoclient.handle_RPC_timeout(hbm) - except: - logging.error('Unexpected error: %s', sys.exc_info()[0]) - self.dominoclient.seqno = self.dominoclient.seqno + 1 - - elif args[0] == 'publish': - opts, args = getopt.getopt(args[1:],"t:",["tosca-file="]) - if len(opts) == 0: - print '\nUsage: publish -t ' - continue - - #toscafile = DEFAULT_TOSCA_PUBFILE - for opt, arg in opts: - if opt in ('-t', '--tosca-file'): - toscafile = arg - - pub_msg = PublishMessage() - pub_msg.domino_udid = self.dominoclient.UDID - pub_msg.seq_no = self.dominoclient.seqno - pub_msg.template_type = 'tosca-nfv-v1.0' - try: - pub_msg.template = read_templatefile(toscafile) - except IOError as e: - logging.error('I/O error(%d): %s' , e.errno, e.strerror) - continue - logging.info('Publishing the template file: ' + toscafile) - try: - pub_msg_r = self.communicationhandler.sender.d_publish(pub_msg) - logging.info('Publish Response is received from: %d ,sequence number: %d', pub_msg_r.domino_udid, pub_msg_r.seq_no) - except (Thrift.TException, TSocket.TTransportException) as tx: - print '%s' % (tx.message) - except (socket.timeout) as tx: - self.dominoclient.handle_RPC_timeout(pub_msg) - - self.dominoclient.seqno = self.dominoclient.seqno + 1 - - elif args[0] == 'subscribe': - opts, args = getopt.getopt(args[1:],"l:t:",["labels=","ttype="]) - for opt, arg in opts: - if opt in ('-l', '--labels'): - labels = labels + arg.split(',') - elif opt in ('-t', '--ttype'): - templateTypes = templateTypes + arg.split(',') - - elif args[0] == 'register': - self.dominoclient.start() - - except getopt.GetoptError: - print 'Command is misentered or not supported!' - - - #check if labels or supported templates are nonempty - if labels != [] or templateTypes != []: - #send subscription message - sub_msg = SubscribeMessage() - sub_msg.domino_udid = self.dominoclient.UDID - sub_msg.seq_no = self.dominoclient.seqno - sub_msg.template_op = APPEND - sub_msg.supported_template_types = templateTypes - sub_msg.label_op = APPEND - sub_msg.labels = labels - logging.info('subscribing labels %s and templates %s', labels, templateTypes) - try: - sub_msg_r = self.communicationhandler.sender.d_subscribe(sub_msg) - logging.info('Subscribe Response is received from: %d ,sequence number: %d', sub_msg_r.domino_udid,sub_msg_r.seq_no) - except (Thrift.TException, TSocket.TTransportException) as tx: - logging.error('%s' , tx.message) - except (socket.timeout) as tx: - self.dominoclient.handle_RPC_timeout(sub_msg) - - self.dominoclient.seqno = self.dominoclient.seqno + 1 + #process input arguments + self.process_input(args) + else: #domino cli-client is used, listen for the CLI rpc calls + cliHandler = CLIHandler(self.dominoclient, self) + processor = DominoClientCLI.Processor(cliHandler) + transport = TSocket.TServerSocket(port=self.dominoclient.CLIport) + tfactory = TTransport.TBufferedTransportFactory() + pfactory = TBinaryProtocol.TBinaryProtocolFactory() + #Use TThreadedServer or TThreadPoolServer for a multithreaded server + CLIServer = TServer.TSimpleServer(processor, transport, tfactory, pfactory) + logging.debug('RPC service for CLI is starting...') + CLIServer.serve() class DominoClient: def __init__(self): @@ -216,11 +208,13 @@ class DominoClient: self.pfactory = None self.communicationServer = None - self.CLIservice = DominoClientCLIService(self, self.communicationHandler) + self.CLIservice = None self.serviceport = 9091 self.dominoserver_IP = 'localhost' + self.CLIport = DOMINO_CLI_PORT + #Start from UNREGISTERED STATE #TO BE DONE: initialize from a saved state self.state = 'UNREGISTERED' @@ -247,6 +241,7 @@ class DominoClient: def register(self): if self.state == 'UNREGISTERED': + logging.info('%d Sending Registration', self.UDID) #prepare registration message reg_msg = RegisterMessage() reg_msg.domino_udid_desired = UDID_DESIRED @@ -275,6 +270,75 @@ class DominoClient: logging.error('%s' , tx.message) self.seqno = self.seqno + 1 + def heartbeat(self): + if self.state == 'UNREGISTERED': + self.start() + + logging.info('%d Sending heartbeat', self.UDID) + hbm = HeartBeatMessage() + hbm.domino_udid = self.UDID + hbm.seq_no = self.seqno + + try: + hbm_r = self.sender().d_heartbeat(hbm) + logging.info('heart beat received from: %d ,sequence number: %d' , hbm_r.domino_udid, hbm_r.seq_no) + except (Thrift.TException, TSocket.TTransportException) as tx: + logging.error('%s' , tx.message) + except (socket.timeout) as tx: + self.handle_RPC_timeout(hbm) + except: + logging.error('Unexpected error: %s', sys.exc_info()[0]) + + self.seqno = self.seqno + 1 + + def publish(self, toscafile): + if self.state == 'UNREGISTERED': + self.start() + + logging.info('Publishing the template file: ' + toscafile) + pub_msg = PublishMessage() + pub_msg.domino_udid = self.UDID + pub_msg.seq_no = self.seqno + pub_msg.template_type = 'tosca-nfv-v1.0' + + try: + pub_msg.template = read_templatefile(toscafile) + except IOError as e: + logging.error('I/O error(%d): %s' , e.errno, e.strerror) + return + try: + pub_msg_r = self.sender().d_publish(pub_msg) + logging.info('Publish Response is received from: %d ,sequence number: %d', pub_msg_r.domino_udid, pub_msg_r.seq_no) + except (Thrift.TException, TSocket.TTransportException) as tx: + print '%s' % (tx.message) + except (socket.timeout) as tx: + self.handle_RPC_timeout(pub_msg) + + self.seqno = self.seqno + 1 + + def subscribe(self, labels, templateTypes): + if self.state == 'UNREGISTERED': + self.start() + + logging.info('subscribing labels %s and templates %s', labels, templateTypes) + #send subscription message + sub_msg = SubscribeMessage() + sub_msg.domino_udid = self.UDID + sub_msg.seq_no = self.seqno + sub_msg.template_op = APPEND + sub_msg.supported_template_types = templateTypes + sub_msg.label_op = APPEND + sub_msg.labels = labels + try: + sub_msg_r = self.sender().d_subscribe(sub_msg) + logging.info('Subscribe Response is received from: %d ,sequence number: %d', sub_msg_r.domino_udid,sub_msg_r.seq_no) + except (Thrift.TException, TSocket.TTransportException) as tx: + logging.error('%s' , tx.message) + except (socket.timeout) as tx: + self.handle_RPC_timeout(sub_msg) + + self.seqno = self.seqno + 1 + def stop(self): try: self.communicationHandler.closeconnection() @@ -284,7 +348,8 @@ class DominoClient: def sender(self): return self.communicationHandler.sender - def startCLI(self): + def startCLI(self, interactive): + self.CLIservice = DominoClientCLIService(self, self.communicationHandler, interactive) logging.info('CLI Service is starting') self.CLIservice.start() #to wait until CLI service is finished @@ -293,6 +358,9 @@ class DominoClient: def set_serviceport(self, port): self.serviceport = port + def set_CLIport(self, cliport): + self.CLIport = cliport + def set_dominoserver_ipaddr(self, ipaddr): self.dominoserver_IP = ipaddr @@ -312,15 +380,16 @@ class DominoClient: def main(argv): client = DominoClient() loglevel = 'WARNING' + interactive = "FALSE" #process input arguments try: - opts, args = getopt.getopt(argv,"hc:p:i:l:",["conf=","port=","ipaddr=","log="]) + opts, args = getopt.getopt(argv,"hc:p:i:l:",["conf=","port=","ipaddr=","log=","iac=","cliport="]) except getopt.GetoptError: - print 'DominoClient.py -c/--conf -p/--port -i/--ipaddr -l/--log ' + print 'DominoClient.py -c/--conf -p/--port -i/--ipaddr -l/--log --iac=true/false' sys.exit(2) for opt, arg in opts: if opt == '-h': - print 'DominoClient.py -c/--conf -p/--port -i/--ipaddr -l/--log ' + print 'DominoClient.py -c/--conf -p/--port -i/--ipaddr -l/--log --iac=true/false' sys.exit() elif opt in ("-c", "--conf"): configfile = arg @@ -328,8 +397,12 @@ def main(argv): client.set_serviceport(int(arg)) elif opt in ("-i", "--ipaddr"): client.set_dominoserver_ipaddr(arg) - elif opt in ("--log"): + elif opt in ("-l", "--log"): loglevel = arg + elif opt in ("--iac"): + interactive = arg.upper() + elif opt in ("--cliport"): + client.set_CLIport(int(arg)) #Set logging level numeric_level = getattr(logging, loglevel.upper(), None) @@ -344,7 +417,7 @@ def main(argv): #The client is starting logging.debug('Domino Client Starting...') client.start() - client.startCLI() + client.startCLI(interactive) client.start_communicationService() if __name__ == "__main__": -- cgit 1.2.3-korg