blob: a08c118429054d6d11f98e6a4bd6775816b480da [file] [log] [blame]
peusterm9c252b62016-01-06 16:59:53 +01001"""
2Distributed Cloud Emulator (dcemulator)
3(c) 2015 by Manuel Peuster <manuel.peuster@upb.de>
4"""
5
6import logging
7import threading
8import zerorpc
9
stevenvanrossem307aa1f2016-05-06 10:35:15 +020010import paramiko
11import ipaddress
stevenvanrossem461941c2016-05-10 11:41:29 +020012import time
13import gevent
stevenvanrossem307aa1f2016-05-06 10:35:15 +020014
peustermbd44f4a2016-01-13 14:53:30 +010015logging.basicConfig(level=logging.INFO)
peusterm9c252b62016-01-06 16:59:53 +010016
17
18class ZeroRpcApiEndpoint(object):
peusterme4e89d32016-01-07 09:14:54 +010019 """
20 Simple API endpoint that offers a zerorpc-based
21 interface. This interface will be used by the
22 default command line client.
23 It can be used as a reference to implement
24 REST interfaces providing the same semantics,
25 like e.g. OpenStack compute API.
26 """
peusterm9c252b62016-01-06 16:59:53 +010027
28 def __init__(self, listenip, port):
29 self.dcs = {}
30 self.ip = listenip
31 self.port = port
32 logging.debug("Created API endpoint %s(%s:%d)" % (
33 self.__class__.__name__, self.ip, self.port))
34
35 def connectDatacenter(self, dc):
peusterma47db032016-02-04 14:55:29 +010036 self.dcs[dc.label] = dc
peusterm9c252b62016-01-06 16:59:53 +010037 logging.info("Connected DC(%s) to API endpoint %s(%s:%d)" % (
peusterma47db032016-02-04 14:55:29 +010038 dc.label, self.__class__.__name__, self.ip, self.port))
peusterm9c252b62016-01-06 16:59:53 +010039
40 def start(self):
41 thread = threading.Thread(target=self._api_server_thread, args=())
42 thread.daemon = True
43 thread.start()
44 logging.debug("Started API endpoint %s(%s:%d)" % (
45 self.__class__.__name__, self.ip, self.port))
46
47 def _api_server_thread(self):
48 s = zerorpc.Server(MultiDatacenterApi(self.dcs))
49 s.bind("tcp://%s:%d" % (self.ip, self.port))
50 s.run()
51
52
53class MultiDatacenterApi(object):
peusterme4e89d32016-01-07 09:14:54 +010054 """
55 Just pass through the corresponding request to the
56 selected data center. Do not implement provisioning
57 logic here because will will have multiple API
58 endpoint implementations at the end.
59 """
peusterm9c252b62016-01-06 16:59:53 +010060
61 def __init__(self, dcs):
62 self.dcs = dcs
63
stevenvanrossem994245b2016-05-04 12:36:57 +020064 def compute_action_start(self, dc_label, compute_name, image, network, command):
peusterm7f8e8402016-02-28 18:38:10 +010065 """
stevenvanrossem994245b2016-05-04 12:36:57 +020066 Start a new compute instance: A docker container (note: zerorpc does not support keyword arguments)
peusterm7f8e8402016-02-28 18:38:10 +010067 :param dc_label: name of the DC
68 :param compute_name: compute container name
69 :param image: image name
70 :param command: command to execute
stevenvanrossem14c89052016-04-10 23:49:59 +020071 :param network: list of all interface of the vnf, with their parameters (id=id1,ip=x.x.x.x/x),...
72 :return: networks list({"id":"input","ip": "10.0.0.254/8"}, {"id":"output","ip": "11.0.0.254/24"})
peusterm7f8e8402016-02-28 18:38:10 +010073 """
peusterm4e98b632016-01-12 14:08:07 +010074 # TODO what to return UUID / given name / internal name ?
peusterm70baaf82016-01-06 17:14:40 +010075 logging.debug("RPC CALL: compute start")
peusterm7aae6852016-01-12 14:53:18 +010076 try:
peusterm53504942016-02-04 16:09:28 +010077 c = self.dcs.get(dc_label).startCompute(
stevenvanrossem8fbf9782016-02-17 11:40:23 +010078 compute_name, image=image, command=command, network=network)
stevenvanrosseme66ef122016-05-03 11:22:54 +020079 #return str(c.name)
80 # return docker inspect dict
81 return c.getStatus()
peusterm7aae6852016-01-12 14:53:18 +010082 except Exception as ex:
83 logging.exception("RPC error.")
84 return ex.message
peusterm9c252b62016-01-06 16:59:53 +010085
peusterm53504942016-02-04 16:09:28 +010086 def compute_action_stop(self, dc_label, compute_name):
peustermbd44f4a2016-01-13 14:53:30 +010087 logging.debug("RPC CALL: compute stop")
peusterm7aae6852016-01-12 14:53:18 +010088 try:
peusterm53504942016-02-04 16:09:28 +010089 return self.dcs.get(dc_label).stopCompute(compute_name)
peusterm7aae6852016-01-12 14:53:18 +010090 except Exception as ex:
91 logging.exception("RPC error.")
92 return ex.message
peusterm9c252b62016-01-06 16:59:53 +010093
peusterm53504942016-02-04 16:09:28 +010094 def compute_list(self, dc_label):
peustermbd44f4a2016-01-13 14:53:30 +010095 logging.debug("RPC CALL: compute list")
peusterm7aae6852016-01-12 14:53:18 +010096 try:
peusterm53504942016-02-04 16:09:28 +010097 if dc_label is None:
peusterm2ec74e12016-01-13 11:17:53 +010098 # return list with all compute nodes in all DCs
99 all_containers = []
100 for dc in self.dcs.itervalues():
101 all_containers += dc.listCompute()
102 return [(c.name, c.getStatus())
103 for c in all_containers]
104 else:
105 # return list of compute nodes for specified DC
106 return [(c.name, c.getStatus())
peusterm53504942016-02-04 16:09:28 +0100107 for c in self.dcs.get(dc_label).listCompute()]
peusterm7aae6852016-01-12 14:53:18 +0100108 except Exception as ex:
109 logging.exception("RPC error.")
110 return ex.message
peusterm4e98b632016-01-12 14:08:07 +0100111
peusterm53504942016-02-04 16:09:28 +0100112 def compute_status(self, dc_label, compute_name):
peustermbd44f4a2016-01-13 14:53:30 +0100113 logging.debug("RPC CALL: compute status")
peusterm7aae6852016-01-12 14:53:18 +0100114 try:
115 return self.dcs.get(
peusterm53504942016-02-04 16:09:28 +0100116 dc_label).containers.get(compute_name).getStatus()
peusterm7aae6852016-01-12 14:53:18 +0100117 except Exception as ex:
118 logging.exception("RPC error.")
119 return ex.message
peustermd313dc12016-02-04 15:36:02 +0100120
stevenvanrossem461941c2016-05-10 11:41:29 +0200121 @zerorpc.stream
stevenvanrossembb084ef2016-05-20 09:27:01 +0200122 def compute_profile(self, dc_label, compute_name, kwargs):
stevenvanrossem994245b2016-05-04 12:36:57 +0200123 # note: zerorpc does not support keyword arguments
124
stevenvanrossem5b376412016-05-04 15:34:49 +0200125 ## VIM/dummy gatekeeper's tasks:
stevenvanrossem994245b2016-05-04 12:36:57 +0200126 # start vnf
stevenvanrossembb084ef2016-05-20 09:27:01 +0200127 vnf_status = self.compute_action_start( dc_label, compute_name,
128 kwargs.get('image'),
stevenvanrossem994245b2016-05-04 12:36:57 +0200129 kwargs.get('network'),
130 kwargs.get('command'))
stevenvanrossem994245b2016-05-04 12:36:57 +0200131 # start traffic source (with fixed ip addres, no use for now...)
stevenvanrossem307aa1f2016-05-06 10:35:15 +0200132 psrc_status = self.compute_action_start( dc_label, 'psrc', 'profile_source', [{'id':'output'}], None)
stevenvanrossem461941c2016-05-10 11:41:29 +0200133 # start traffic sink (with fixed ip addres)
134 psink_status = self.compute_action_start(dc_label, 'psink', 'profile_sink', [{'id': 'input'}], None)
stevenvanrossem5b376412016-05-04 15:34:49 +0200135 # link vnf to traffic source
136 DCNetwork = self.dcs.get(dc_label).net
stevenvanrossemedcbeeb2016-05-04 17:28:08 +0200137 DCNetwork.setChain('psrc', compute_name,
138 vnf_src_interface='output',
139 vnf_dst_interface=kwargs.get('input'),
stevenvanrossem461941c2016-05-10 11:41:29 +0200140 cmd='add-flow', weight=None, bidirectional=True)
141 DCNetwork.setChain('psrc', compute_name,
142 vnf_src_interface='output',
143 vnf_dst_interface=kwargs.get('input'),
144 cmd='add-flow', weight=None,
145 match='dl_type=0x0800,nw_proto=17,udp_dst=5001',
146 cookie=10)
147 DCNetwork.setChain( compute_name, 'psink',
148 vnf_src_interface='output',
149 vnf_dst_interface=kwargs.get('input'),
150 cmd='add-flow', weight=None, bidirectional=True)
151 DCNetwork.setChain(compute_name, 'psink',
152 vnf_src_interface='output',
153 vnf_dst_interface=kwargs.get('input'),
154 cmd='add-flow', weight=None,
155 match='dl_type=0x0800,nw_proto=17,udp_dst=5001',
156 cookie=11)
stevenvanrossem5b376412016-05-04 15:34:49 +0200157
stevenvanrossemedcbeeb2016-05-04 17:28:08 +0200158 ## SSM/SP tasks:
stevenvanrossem307aa1f2016-05-06 10:35:15 +0200159 # start traffic generation
stevenvanrossem461941c2016-05-10 11:41:29 +0200160 '''
stevenvanrossem307aa1f2016-05-06 10:35:15 +0200161 for nw in psrc_status.get('network'):
162 if nw.get('intf_name') == 'output':
163 psrc_output_ip = unicode(nw['ip'])
164 break
165 dummy_iperf_server_ip = ipaddress.IPv4Address(psrc_output_ip) + 1
stevenvanrossem461941c2016-05-10 11:41:29 +0200166 '''
167 for nw in psink_status.get('network'):
168 if nw.get('intf_name') == 'input':
169 psink_input_ip = nw['ip']
170 break
stevenvanrossem307aa1f2016-05-06 10:35:15 +0200171
stevenvanrossem307aa1f2016-05-06 10:35:15 +0200172
stevenvanrossemedcbeeb2016-05-04 17:28:08 +0200173 # get monitor data and analyze
stevenvanrossem461941c2016-05-10 11:41:29 +0200174 vnf_uuid = vnf_status['id']
175 psrc_mgmt_ip = psrc_status['docker_network']
stevenvanrossem994245b2016-05-04 12:36:57 +0200176
stevenvanrossem461941c2016-05-10 11:41:29 +0200177 # query rate
stevenvanrossem994245b2016-05-04 12:36:57 +0200178
stevenvanrossem461941c2016-05-10 11:41:29 +0200179 #need to wait a bit before containers are fully up?
180 time.sleep(2)
stevenvanrossem994245b2016-05-04 12:36:57 +0200181
stevenvanrossem461941c2016-05-10 11:41:29 +0200182 def generate():
183 for rate in [0, 1, 2, 3]:
184 #logging.info('query:{0}'.format(query_cpu))
185
186 output_line = DCNetwork.monitor_agent.profile(psrc_mgmt_ip, rate, psink_input_ip, vnf_uuid)
187 gevent.sleep(0)
188 yield output_line
189
190 # query loss
191
192
193 # create table
194
195 ## VIM/dummy gatekeeper's tasks:
196 # remove vnfs and chain
197 DCNetwork.setChain('psrc', compute_name,
198 vnf_src_interface='output',
199 vnf_dst_interface=kwargs.get('input'),
200 cmd='del-flows', weight=None, bidirectional=True)
201 DCNetwork.setChain('psrc', compute_name,
202 vnf_src_interface='output',
203 vnf_dst_interface=kwargs.get('input'),
204 cmd='del-flows', weight=None,
205 match='dl_type=0x0800,nw_proto=17,udp_dst=5001',
206 cookie=10)
207 DCNetwork.setChain(compute_name, 'psink',
208 vnf_src_interface='output',
209 vnf_dst_interface=kwargs.get('input'),
210 cmd='del-flows', weight=None, bidirectional=True)
211 DCNetwork.setChain(compute_name, 'psink',
212 vnf_src_interface='output',
213 vnf_dst_interface=kwargs.get('input'),
214 cmd='del-flows', weight=None,
215 match='dl_type=0x0800,nw_proto=17,udp_dst=5001',
216 cookie=11)
217 self.compute_action_stop(dc_label, compute_name)
218 self.compute_action_stop(dc_label, 'psink')
219 self.compute_action_stop(dc_label, 'psrc')
220
221 return generate()
stevenvanrossem994245b2016-05-04 12:36:57 +0200222
peustermd313dc12016-02-04 15:36:02 +0100223 def datacenter_list(self):
224 logging.debug("RPC CALL: datacenter list")
225 try:
226 return [d.getStatus() for d in self.dcs.itervalues()]
227 except Exception as ex:
228 logging.exception("RPC error.")
229 return ex.message
peusterm53504942016-02-04 16:09:28 +0100230
231 def datacenter_status(self, dc_label):
232 logging.debug("RPC CALL: datacenter status")
233 try:
234 return self.dcs.get(dc_label).getStatus()
235 except Exception as ex:
236 logging.exception("RPC error.")
237 return ex.message
stevenvanrossem994245b2016-05-04 12:36:57 +0200238
stevenvanrossem994245b2016-05-04 12:36:57 +0200239