Simple mapper/scheduler/partitioner functions implemented
[domino.git] / DominoClient.py
1 #!/usr/bin/env python
2
3 #
4 # Licence statement goes here
5 #
6
7 import sys, glob, threading
8 import getopt
9
10 #sys.path.append('gen-py')
11 #sys.path.insert(0, glob.glob('./lib/py/build/lib.*')[0])
12 sys.path.insert(0, glob.glob('./lib')[0])
13
14 from dominoRPC import Communication
15 from dominoRPC.ttypes import *
16 from dominoRPC.constants import *
17
18 from thrift import Thrift
19 from thrift.transport import TSocket
20 from thrift.transport import TTransport
21 from thrift.protocol import TBinaryProtocol
22 from thrift.server import TServer
23
24 from util import *
25
26 CLIENT_UDID = 1
27 CLIENT_SEQNO = 0
28
29 DOMINO_SERVER_IP = 'localhost'
30 DOMINO_SERVER_PORT = 9090
31
32 UDID_DESIRED = 12467
33 LIST_SUPPORTED_TEMPLATES = ['tosca-nfv-v1.0']
34 #DEFAULT_TOSCA_PUBFILE = './tosca-templates/tosca_simpleVNF.yaml'
35 DEFAULT_TOSCA_PUBFILE = './tosca-templates/tosca_helloworld_nfv.yaml'
36
37 class CommunicationHandler:
38   def __init__(self):
39     self.log = {}
40
41   def __init__(self, dominoclient):
42     global DOMINO_SERVER_IP, DOMINO_SERVER_PORT
43     self.log = {}
44     self.dominoClient = dominoclient
45     try:
46       # Make socket
47       transport = TSocket.TSocket(DOMINO_SERVER_IP, DOMINO_SERVER_PORT)
48       # Add buffering to compensate for slow raw sockets
49       self.transport = TTransport.TBufferedTransport(transport)
50       # Wrap in a protocol
51       self.protocol = TBinaryProtocol.TBinaryProtocol(self.transport)
52       # Create a client to use the protocol encoder
53       self.sender = Communication.Client(self.protocol)
54     except Thrift.TException, tx: 
55       print '%s' % (tx.message)
56
57   # Template Push from Domino Server is received
58   # Actions:
59   #       - Depending on Controller Domain, call API
60   #       - Respond Back with Push Response
61   def d_push(self, push_msg):
62     print 'Received Template File'
63     # Retrieve the template file
64
65     ## End of retrieval
66  
67     # Any inspection code goes here
68
69     ## End of inspection
70
71     # Call NB API
72     # If heat client, call heat command
73     
74     # If ONOS client, run as shell script
75
76
77     ## End of NB API call
78
79     # Marshall the response message for the Domino Server Fill
80     push_r = PushResponseMessage()
81     # Fill response message fields
82     push_r.domino_udid = self.dominoClient.UDID    
83     push_r.seq_no = self.dominoClient.seqno
84     push_r.responseCode = SUCCESS    
85     ## End of filling
86
87     self.dominoClient.seqno = self.dominoClient.seqno + 1
88
89     return push_r
90
91   
92   def openconnection(self):
93     self.transport.open()
94
95   def closeconnection():
96     self.transport.close()
97  
98 def read_templatefile(temp_filename): 
99   f = open(temp_filename, 'r')
100   lines = f.read().splitlines()
101
102   return lines
103
104 class DominoClientCLIService(threading.Thread):
105   def __init__(self, dominoclient, communicationhandler):
106     threading.Thread.__init__(self)
107     self.dominoclient = dominoclient
108     self.communicationhandler = communicationhandler
109
110   def run(self):
111     global DEFAULT_TOSCA_PUBFILE
112     while True:
113        sys.stdout.write('>>')
114        input_string = raw_input()
115        args = input_string.split()
116        if len(args) == 0:
117          continue
118
119        labels = []       
120        templateTypes = []
121
122        #process input arguments
123        try:
124          sys.stdout.write('>>')
125          if args[0] == 'heartbeat':
126            print '\nSending heatbeat'
127            hbm = HeartBeatMessage()
128            hbm.domino_udid = self.dominoclient.UDID
129            hbm.seq_no = self.dominoclient.seqno
130            hbm_r = self.communicationhandler.sender.d_heartbeat(hbm)
131            print 'heart beat received from: %d ,sequence number: %d' % (hbm_r.domino_udid, hbm_r.seq_no)
132            self.dominoclient.seqno = self.dominoclient.seqno + 1
133          
134          elif args[0] == 'publish':
135            opts, args = getopt.getopt(args[1:],"t:",["tosca-file="])
136            if len(opts) == 0:
137              print '\nUsage: publish -t <toscafile>'
138              continue
139
140            #toscafile = DEFAULT_TOSCA_PUBFILE
141            for opt, arg in opts:
142              if opt in ('-t', '--tosca-file'):
143                toscafile = arg
144            
145            pub_msg = PublishMessage()
146            pub_msg.domino_udid = self.dominoclient.UDID
147            pub_msg.seq_no = self.dominoclient.seqno
148            pub_msg.template_type = 'tosca-nfv-v1.0'
149            try:
150              pub_msg.template = read_templatefile(toscafile)
151            except IOError as e:
152              print "I/O error({0}): {1}".format(e.errno, e.strerror)
153              continue
154            print '\nPublishing the template file: ' + toscafile
155            pub_msg_r = self.communicationhandler.sender.d_publish(pub_msg)
156            print 'Publish Response is received from: %d ,sequence number: %d' % (pub_msg_r.domino_udid, pub_msg_r.seq_no)
157            self.dominoclient.seqno = self.dominoclient.seqno + 1
158        
159          elif args[0] == 'subscribe':         
160            opts, args = getopt.getopt(args[1:],"l:t:",["labels=","ttype="])
161            for opt, arg in opts:
162               if opt in ('-l', '--labels'):
163                  labels = labels + arg.split(',')
164               elif opt in ('-t', '--ttype'):
165                  templateTypes = templateTypes + arg.split(',')
166  
167        except getopt.GetoptError:
168          print 'Command is misentered or not supported!'
169
170
171        #check if labels or supported templates are nonempty
172        if labels != [] or templateTypes != []:
173          #send subscription message
174          sub_msg = SubscribeMessage()
175          sub_msg.domino_udid = self.dominoclient.UDID
176          sub_msg.seq_no = self.dominoclient.seqno
177          sub_msg.template_op = APPEND
178          sub_msg.supported_template_types = templateTypes
179          sub_msg.label_op = APPEND
180          sub_msg.labels = labels
181          print 'subscribing labels %s and templates %s' % (labels,templateTypes)
182          sub_msg_r = self.communicationhandler.sender.d_subscribe(sub_msg) 
183          print 'Subscribe Response is received from: %d ,sequence number: %d' % (sub_msg_r.domino_udid,sub_msg_r.seq_no)
184          self.dominoclient.seqno = self.dominoclient.seqno + 1
185
186 class DominoClient:
187   def __init__(self):
188     self.log = {}
189     self.communicationHandler = CommunicationHandler(self)
190     self.processor = None
191     self.transport = None
192     self.tfactory = None
193     self.pfactory = None
194     self.communicationServer = None
195
196     self.CLIservice = DominoClientCLIService(self, self.communicationHandler)
197
198     self.serviceport = 9091
199     self.dominoserver_IP = 'localhost'
200
201     #Start from UNREGISTERED STATE
202     #TO BE DONE: initialize from a saved state
203     self.state = 'UNREGISTERED'
204     self.seqno = 0
205     self.UDID = 1
206
207   def start_communicationService(self):
208     self.processor = Communication.Processor(self.communicationHandler)
209     self.transport = TSocket.TServerSocket(port=int(self.serviceport))
210     self.tfactory = TTransport.TBufferedTransportFactory()
211     self.pfactory = TBinaryProtocol.TBinaryProtocolFactory()
212     #Use TThreadedServer or TThreadPoolServer for a multithreaded server
213     #self.communicationServer = TServer.TThreadedServer(self.processor, self.transport, self.tfactory, self.pfactory)
214     self.communicationServer = TServer.TThreadPoolServer(self.processor, self.transport, self.tfactory, self.pfactory)
215
216     self.communicationServer.serve()
217  
218   def start(self):
219     try:
220       self.communicationHandler.openconnection()
221     except Thrift.TException, tx:
222       print '%s' % (tx.message)
223     
224     if self.state == 'UNREGISTERED':
225       #prepare registration message
226       reg_msg = RegisterMessage()
227       reg_msg.domino_udid_desired = UDID_DESIRED
228       reg_msg.seq_no = self.seqno
229       reg_msg.ipaddr = netutil.get_ip()
230       reg_msg.tcpport = self.serviceport
231       reg_msg.supported_templates = LIST_SUPPORTED_TEMPLATES
232
233       reg_msg_r = self.sender().d_register(reg_msg)
234       print 'Registration Response:\n'
235       print 'Response Code: %d'  % (reg_msg_r.responseCode)
236       print 'Response Comments:'
237       if reg_msg_r.comments:
238         print reg_msg_r.comments
239
240       if reg_msg_r.responseCode == SUCCESS:
241         self.state = 'REGISTERED'
242         self.UDID = reg_msg_r.domino_udid_assigned
243       else:
244         #Handle registration failure here (possibly based on reponse comments)   
245         pass
246
247       self.seqno = self.seqno + 1
248
249   def stop(self):
250     try:
251       self.communicationHandler.closeconnection()
252     except Thrift.TException, tx:
253       print '%s' % (tx.message)
254     
255   def sender(self):
256     return self.communicationHandler.sender
257
258   def startCLI(self):
259     print 'CLI Service is starting'
260     self.CLIservice.start()
261     #to wait until CLI service is finished
262     #self.CLIservice.join()
263
264   def set_serviceport(self, port):
265     self.serviceport = port
266     print 'port: '
267     print self.serviceport
268
269   def set_dominoserver_ipaddr(self, ipaddr):
270     self.dominoserver_IP = ipaddr
271     print 'ip addr: '
272     print self.dominoserver_IP
273
274 def main(argv):
275   client = DominoClient()
276
277   #process input arguments
278   try:
279       opts, args = getopt.getopt(argv,"hc:p:i:",["conf=","port=","ipaddr="])
280   except getopt.GetoptError:
281       print 'DominoClient.py -c/--conf <configfile> -p/--port <socketport> -i/--ipaddr <IPaddr>'
282       sys.exit(2)
283   for opt, arg in opts:
284       if opt == '-h':
285          print 'DominoClient.py -c/--conf <configfile> -p/--port <socketport> -i/--ipaddr <IPaddr>'
286          sys.exit()
287       elif opt in ("-c", "--conf"):
288          configfile = arg
289       elif opt in ("-p", "--port"):
290          client.set_serviceport(int(arg))
291       elif opt in ("-i", "--ipaddr"):
292          client.set_dominoserver_ipaddr(arg)
293
294   #The client is starting
295   print 'Starting the client...'
296   client.start()
297   client.startCLI()
298   client.start_communicationService()
299
300 if __name__ == "__main__":
301    main(sys.argv[1:])
302