blob: fe2761cdc19ab26913b924bdf59053fd8f0025cf [file] [log] [blame]
A R Karthick35495c32017-05-11 14:58:32 -07001import requests
2import json
3import time
A.R Karthick57fa9372017-05-24 12:47:03 -07004import os
5import signal
A.R Karthick4c4d0492017-05-26 19:23:05 -07006from CordTestUtils import log_test as log, getstatusoutput, get_controller
A R Karthickbf1e4b02017-07-11 20:17:14 -07007from CordContainer import Container, Onos
A.R Karthick4c4d0492017-05-26 19:23:05 -07008from OnosCtrl import OnosCtrl
A.R Karthick4f583842017-06-09 17:15:47 -07009from OltConfig import OltConfig
A.R Karthick57fa9372017-05-24 12:47:03 -070010
11class VolthaService(object):
12 services = ('consul', 'kafka', 'zookeeper', 'registrator', 'fluentd')
13 compose_file = 'docker-compose-system-test.yml'
14 service_map = {}
15
A.R Karthick4f583842017-06-09 17:15:47 -070016 def __init__(self, voltha_loc, controller, interface = 'eth0', olt_config = None):
A.R Karthick57fa9372017-05-24 12:47:03 -070017 if not os.access(voltha_loc, os.F_OK):
18 raise Exception('Voltha location %s not found' %voltha_loc)
19 compose_file_loc = os.path.join(voltha_loc, 'compose', self.compose_file)
20 if not os.access(compose_file_loc, os.F_OK):
21 raise Exception('Voltha compose file %s not found' %compose_file_loc)
22 self.voltha_loc = voltha_loc
23 self.controller = controller
24 self.interface = interface
25 self.compose_file_loc = compose_file_loc
A.R Karthick4f583842017-06-09 17:15:47 -070026 num_onus = 1
27 if olt_config is not None:
28 port_map, _ = OltConfig(olt_config).olt_port_map()
29 if port_map['ponsim'] is True:
30 num_onus = max(1, len(port_map['ports']))
31 self.num_onus = num_onus
A.R Karthick57fa9372017-05-24 12:47:03 -070032
33 def start(self):
34 start_cmd = 'docker-compose -f {} up -d {} {} {} {} {}'.format(self.compose_file_loc,
35 *self.services)
36 ret = os.system(start_cmd)
37 if ret != 0:
38 raise Exception('Failed to start voltha services. Failed with code %d' %ret)
39
40 for service in self.services:
41 name = 'compose_{}_1'.format(service)
42 network = 'compose_default'
43 cnt = Container(name, name)
44 ip = cnt.ip(network = network)
45 if not ip:
46 raise Exception('IP not found for container %s' %name)
47 print('IP %s for service %s' %(ip, service))
48 self.service_map[service] = dict(name = name, network = network, ip = ip)
49
50 #first start chameleon
51 chameleon_start_cmd = "cd {} && sh -c '. ./env.sh && \
52 nohup python chameleon/main.py -v --consul=localhost:8500 \
53 --fluentd={}:24224 --grpc-endpoint=localhost:50555 \
54 >/tmp/chameleon.log 2>&1 &'".format(self.voltha_loc,
55 self.service_map['fluentd']['ip'])
A.R Karthickc2697a12017-05-24 14:01:15 -070056 if not self.service_running('python chameleon/main.py'):
57 ret = os.system(chameleon_start_cmd)
58 if ret != 0:
59 raise Exception('VOLTHA chameleon service not started. Failed with return code %d' %ret)
A R Karthickd69d5702017-07-25 11:31:47 -070060 time.sleep(10)
A.R Karthickc2697a12017-05-24 14:01:15 -070061 else:
62 print('Chameleon voltha sevice is already running. Skipped start')
A.R Karthick57fa9372017-05-24 12:47:03 -070063
64 #now start voltha and ofagent
A R Karthickd52ca8a2017-07-24 17:38:55 -070065 voltha_setup_cmd = "cd {} && sh -c '. ./env.sh && make rebuild-venv && make protos'".format(self.voltha_loc)
A.R Karthick57fa9372017-05-24 12:47:03 -070066 voltha_start_cmd = "cd {} && sh -c '. ./env.sh && \
67 nohup python voltha/main.py -v --consul=localhost:8500 --kafka={}:9092 -I {} \
68 --fluentd={}:24224 --rest-port=8880 --grpc-port=50555 \
69 >/tmp/voltha.log 2>&1 &'".format(self.voltha_loc,
70 self.service_map['kafka']['ip'],
71 self.interface,
72 self.service_map['fluentd']['ip'])
A R Karthickd52ca8a2017-07-24 17:38:55 -070073 pki_dir = '{}/pki'.format(self.voltha_loc)
A.R Karthickc2697a12017-05-24 14:01:15 -070074 if not self.service_running('python voltha/main.py'):
A R Karthickd52ca8a2017-07-24 17:38:55 -070075 voltha_pki_dir = '/voltha'
76 if os.access(pki_dir, os.F_OK):
77 pki_xfer_cmd = 'mkdir -p {} && cp -rv {}/pki {}'.format(voltha_pki_dir,
78 self.voltha_loc,
79 voltha_pki_dir)
80 os.system(pki_xfer_cmd)
81 #os.system(voltha_setup_cmd)
A.R Karthickc2697a12017-05-24 14:01:15 -070082 ret = os.system(voltha_start_cmd)
83 if ret != 0:
84 raise Exception('Failed to start VOLTHA. Return code %d' %ret)
A R Karthickd69d5702017-07-25 11:31:47 -070085 time.sleep(10)
A.R Karthickc2697a12017-05-24 14:01:15 -070086 else:
87 print('VOLTHA core is already running. Skipped start')
A.R Karthick57fa9372017-05-24 12:47:03 -070088
89 ofagent_start_cmd = "cd {} && sh -c '. ./env.sh && \
90 nohup python ofagent/main.py -v --consul=localhost:8500 \
91 --fluentd={}:24224 --controller={}:6653 --grpc-endpoint=localhost:50555 \
92 >/tmp/ofagent.log 2>&1 &'".format(self.voltha_loc,
93 self.service_map['fluentd']['ip'],
94 self.controller)
A.R Karthickc2697a12017-05-24 14:01:15 -070095 if not self.service_running('python ofagent/main.py'):
A R Karthickd52ca8a2017-07-24 17:38:55 -070096 ofagent_pki_dir = '/ofagent'
97 if os.access(pki_dir, os.F_OK):
98 pki_xfer_cmd = 'mkdir -p {} && cp -rv {}/pki {}'.format(ofagent_pki_dir,
99 self.voltha_loc,
100 ofagent_pki_dir)
101 os.system(pki_xfer_cmd)
A.R Karthickc2697a12017-05-24 14:01:15 -0700102 ret = os.system(ofagent_start_cmd)
103 if ret != 0:
104 raise Exception('VOLTHA ofagent not started. Failed with return code %d' %ret)
A R Karthickd69d5702017-07-25 11:31:47 -0700105 time.sleep(10)
A.R Karthickc2697a12017-05-24 14:01:15 -0700106 else:
107 print('VOLTHA ofagent is already running. Skipped start')
108
A.R Karthick12e08c32017-05-30 17:09:26 -0700109 ponsim_start_cmd = "cd {} && sh -c '. ./env.sh && \
A.R Karthick4f583842017-06-09 17:15:47 -0700110 nohup python ponsim/main.py -o {} -v >/tmp/ponsim.log 2>&1 &'".format(self.voltha_loc, self.num_onus)
A.R Karthick12e08c32017-05-30 17:09:26 -0700111 if not self.service_running('python ponsim/main.py'):
112 ret = os.system(ponsim_start_cmd)
113 if ret != 0:
114 raise Exception('PONSIM not started. Failed with return code %d' %ret)
115 time.sleep(3)
116 else:
117 print('PONSIM already running. Skipped start')
118
A.R Karthickc2697a12017-05-24 14:01:15 -0700119 def service_running(self, pattern):
120 st, _ = getstatusoutput('pgrep -f "{}"'.format(pattern))
121 return True if st == 0 else False
A.R Karthick57fa9372017-05-24 12:47:03 -0700122
123 def kill_service(self, pattern):
124 st, output = getstatusoutput('pgrep -f "{}"'.format(pattern))
125 if st == 0 and output:
126 pids = output.strip().splitlines()
127 for pid in pids:
128 try:
129 os.kill(int(pid), signal.SIGKILL)
130 except:
131 pass
132
133 def stop(self):
134 self.kill_service('python voltha/main.py')
135 self.kill_service('python ofagent/main.py')
136 self.kill_service('python chameleon/main.py')
A.R Karthick12e08c32017-05-30 17:09:26 -0700137 self.kill_service('python ponsim/main.py')
A.R Karthick57fa9372017-05-24 12:47:03 -0700138 service_stop_cmd = 'docker-compose -f {} down'.format(self.compose_file_loc)
139 os.system(service_stop_cmd)
A R Karthick35495c32017-05-11 14:58:32 -0700140
141class VolthaCtrl(object):
A R Karthick53442712017-07-27 12:23:30 -0700142 UPLINK_VLAN_START = 333
A.R Karthick4c4d0492017-05-26 19:23:05 -0700143 UPLINK_VLAN_MAP = { 'of:0000000000000001' : '222' }
A R Karthickbf1e4b02017-07-11 20:17:14 -0700144 REST_PORT = 8881
A R Karthick53442712017-07-27 12:23:30 -0700145 HOST = '172.17.0.1'
A.R Karthick4c4d0492017-05-26 19:23:05 -0700146
A R Karthick53442712017-07-27 12:23:30 -0700147 def __init__(self, host = HOST, rest_port = REST_PORT, uplink_vlan_map = UPLINK_VLAN_MAP, uplink_vlan_start = UPLINK_VLAN_START):
A R Karthick35495c32017-05-11 14:58:32 -0700148 self.host = host
149 self.rest_port = rest_port
150 self.rest_url = 'http://{}:{}/api/v1'.format(host, rest_port)
A.R Karthick4c4d0492017-05-26 19:23:05 -0700151 self.uplink_vlan_map = uplink_vlan_map
A R Karthick53442712017-07-27 12:23:30 -0700152 VolthaCtrl.UPLINK_VLAN_START = uplink_vlan_start
A.R Karthick4c4d0492017-05-26 19:23:05 -0700153 self.switches = []
154 self.switch_map = {}
155
156 def config(self, fake = False):
157 devices = OnosCtrl.get_devices()
158 if not devices:
159 return self.switch_map
160 voltha_devices = filter(lambda d: not d['mfr'].startswith('Nicira'), devices)
161 self.switches = voltha_devices
162 device_config = { 'devices' : { } }
163 device_id = None
164 for device in voltha_devices:
165 device_id = device['id']
166 ports = OnosCtrl.get_ports_device(device_id)
167 nni_ports = filter(lambda p: p['isEnabled'] and 'annotations' in p and p['annotations']['portName'].startswith('nni'), ports)
168 uni_ports = filter(lambda p: p['isEnabled'] and 'annotations' in p and p['annotations']['portName'].startswith('uni'), ports)
169 if device_id not in self.uplink_vlan_map:
A R Karthick53442712017-07-27 12:23:30 -0700170 uplink_vlan = VolthaCtrl.UPLINK_VLAN_START
171 VolthaCtrl.UPLINK_VLAN_START += 1
172 log.info('Voltha device %s not in map. Using uplink vlan %d' %(device_id, uplink_vlan))
173 else:
174 uplink_vlan = self.uplink_vlan_map[device_id]
A.R Karthick4c4d0492017-05-26 19:23:05 -0700175 if not nni_ports:
176 log.info('Voltha device %s has no NNI ports' %device_id)
177 if fake is True:
178 log.info('Faking NNI port 0')
179 nni_ports = [ {'port': '0'} ]
180 else:
181 log.info('Skip configuring device %s' %device_id)
182 continue
183 if not uni_ports:
184 log.info('Voltha device %s has no UNI ports' %device_id)
185 if fake is True:
186 log.info('Faking UNI port 252')
187 uni_ports = [ {'port': '252'} ]
188 else:
189 log.info('Skip configuring device %s' %device_id)
190 continue
A.R Karthick4c4d0492017-05-26 19:23:05 -0700191 onu_ports = map(lambda uni: uni['port'], uni_ports)
192 self.switch_map[device_id] = dict(uplink_vlan = uplink_vlan, ports = onu_ports)
193 device_config['devices'][device_id] = {}
194 device_config['devices'][device_id]['basic'] = dict(driver='pmc-olt')
195 device_config['devices'][device_id]['accessDevice'] = dict(uplink=nni_ports[0]['port'],
196 vlan = uplink_vlan,
197 defaultVlan='0'
198 )
199 if device_id:
200 #toggle drivers/openflow base before reconfiguring the driver and olt config data
201 OnosCtrl('org.onosproject.drivers').deactivate()
202 OnosCtrl('org.onosproject.openflow-base').deactivate()
203 OnosCtrl.config(device_config)
204 time.sleep(2)
205 OnosCtrl('org.onosproject.drivers').activate()
206 OnosCtrl('org.onosproject.openflow-base').activate()
207 time.sleep(5)
208
209 return self.switch_map
A R Karthick35495c32017-05-11 14:58:32 -0700210
211 def get_devices(self):
212 url = '{}/local/devices'.format(self.rest_url)
213 resp = requests.get(url)
214 if resp.ok is not True or resp.status_code != 200:
215 return None
216 return resp.json()
217
A.R Karthick8b9c5f12017-05-30 17:47:08 -0700218 def enable_device(self, olt_type, olt_mac = None, address = None):
A R Karthick35495c32017-05-11 14:58:32 -0700219 url = '{}/local/devices'.format(self.rest_url)
A.R Karthick8b9c5f12017-05-30 17:47:08 -0700220 if olt_mac is None and address is None:
221 log.error('Either olt mac or address needs to be specified')
A.R Karthick8a507cf2017-06-02 18:44:49 -0700222 return None, False
A.R Karthick8b9c5f12017-05-30 17:47:08 -0700223 if olt_mac is not None:
224 device_config = { 'type' : olt_type, 'mac_address' : olt_mac }
225 else:
226 device_config = { 'type' : olt_type, 'host_and_port' : address }
A R Karthick35495c32017-05-11 14:58:32 -0700227 #pre-provision
A.R Karthick8b9c5f12017-05-30 17:47:08 -0700228 if olt_mac is not None:
229 log.info('Pre-provisioning %s with mac %s' %(olt_type, olt_mac))
230 else:
231 log.info('Pre-provisioning %s with address %s' %(olt_type, address))
A R Karthick35495c32017-05-11 14:58:32 -0700232 resp = requests.post(url, data = json.dumps(device_config))
233 if resp.ok is not True or resp.status_code != 200:
A.R Karthick8a507cf2017-06-02 18:44:49 -0700234 return None, False
A R Karthick35495c32017-05-11 14:58:32 -0700235 device_id = resp.json()['id']
236 log.info('Enabling device %s' %(device_id))
237 enable_url = '{}/{}/enable'.format(url, device_id)
238 resp = requests.post(enable_url)
239 if resp.ok is not True or resp.status_code != 200:
A.R Karthick8a507cf2017-06-02 18:44:49 -0700240 return None, False
A R Karthick35495c32017-05-11 14:58:32 -0700241 #get operational status
A R Karthick090631b2017-07-25 16:05:05 -0700242 time.sleep(10)
A R Karthick35495c32017-05-11 14:58:32 -0700243 log.info('Checking operational status for device %s' %(device_id))
244 resp = requests.get('{}/{}'.format(url, device_id))
245 if resp.ok is not True or resp.status_code != 200:
A.R Karthick8a507cf2017-06-02 18:44:49 -0700246 return device_id, False
A R Karthick35495c32017-05-11 14:58:32 -0700247 device_info = resp.json()
248 if device_info['oper_status'] != 'ACTIVE' or \
249 device_info['admin_state'] != 'ENABLED' or \
250 device_info['connect_status'] != 'REACHABLE':
A.R Karthick8a507cf2017-06-02 18:44:49 -0700251 return device_id, False
A R Karthick35495c32017-05-11 14:58:32 -0700252
A.R Karthick8a507cf2017-06-02 18:44:49 -0700253 return device_id, True
254
255 def disable_device(self, device_id, delete = True):
256 log.info('Disabling device %s' %(device_id))
257 disable_url = '{}/local/devices/{}/disable'.format(self.rest_url, device_id)
258 resp = requests.post(disable_url)
259 if resp.ok is not True or resp.status_code != 200:
260 return False
261 if delete is True:
A R Karthickd69d5702017-07-25 11:31:47 -0700262 #rest for disable completion
263 time.sleep(10)
A.R Karthick8a507cf2017-06-02 18:44:49 -0700264 log.info('Deleting device %s' %(device_id))
265 delete_url = '{}/local/devices/{}/delete'.format(self.rest_url, device_id)
266 resp = requests.delete(delete_url)
267 if resp.status_code not in [204, 202, 200]:
268 return False
A R Karthick35495c32017-05-11 14:58:32 -0700269 return True
Chetan Gaonker3620a112017-05-23 06:10:15 +0000270
Thangavelu K Se6c77c72017-06-23 21:28:48 +0000271 def restart_device(self, device_id):
272 log.info('Restarting olt or onu device %s' %(device_id))
273 disable_url = '{}/local/devices/{}/restart'.format(self.rest_url, device_id)
274 resp = requests.post(disable_url)
275 if resp.ok is not True or resp.status_code != 200:
276 return False
277 return True
278
279 def pause_device(self, device_id):
280 log.info('Restarting olt or onu device %s' %(device_id))
281 disable_url = '{}/local/devices/{}/pause'.format(self.rest_url, device_id)
282 resp = requests.post(disable_url)
283 if resp.ok is not True or resp.status_code != 200:
284 return False
285 return True
286
Chetan Gaonker3620a112017-05-23 06:10:15 +0000287 def get_operational_status(self, device_id):
288 url = '{}/local/devices'.format(self.rest_url)
289 log.info('Checking operational status for device %s' %(device_id))
290 resp = requests.get('{}/{}'.format(url, device_id))
291 if resp.ok is not True or resp.status_code != 200:
292 return False
293 device_info = resp.json()
294 if device_info['oper_status'] != 'ACTIVE' or \
295 device_info['admin_state'] != 'ENABLED' or \
296 device_info['connect_status'] != 'REACHABLE':
297 return False
298 return True
299
300 def check_preprovision_status(self, device_id):
301 url = '{}/local/devices'.format(self.rest_url)
302 log.info('Check if device %s is in Preprovisioning state'%(device_id))
303 resp = requests.get('{}/{}'.format(url, device_id))
304 if resp.ok is not True or resp.status_code != 200:
305 return False
306 device_info = resp.json()
307 if device_info['admin_status'] == 'PREPROVISIONED':
308 return True
309 return False
A R Karthickbf1e4b02017-07-11 20:17:14 -0700310
311def get_olt_app():
312 our_path = os.path.dirname(os.path.realpath(__file__))
313 version = Onos.getVersion()
314 major = int(version.split('.')[0])
315 minor = int(version.split('.')[1])
316 olt_app_version = '1.2-SNAPSHOT'
317 if major > 1:
318 olt_app_version = '2.0-SNAPSHOT'
319 elif major == 1:
320 if minor > 10:
321 olt_app_version = '2.0-SNAPSHOT'
322 elif minor <= 8:
323 olt_app_version = '1.1-SNAPSHOT'
324 olt_app_file = os.path.join(our_path, '..', 'apps/olt-app-{}.oar'.format(olt_app_version))
325 return olt_app_file
326
327def voltha_setup(host = '172.17.0.1', rest_port = VolthaCtrl.REST_PORT,
A R Karthick9dc6e922017-07-12 14:40:16 -0700328 olt_type = 'ponsim_olt', olt_mac = '00:0c:e2:31:12:00',
A R Karthickbf1e4b02017-07-11 20:17:14 -0700329 uplink_vlan_map = VolthaCtrl.UPLINK_VLAN_MAP,
A R Karthick53442712017-07-27 12:23:30 -0700330 uplink_vlan_start = VolthaCtrl.UPLINK_VLAN_START,
A R Karthickbf1e4b02017-07-11 20:17:14 -0700331 config_fake = False, olt_app = None):
332
A R Karthick53442712017-07-27 12:23:30 -0700333 voltha = VolthaCtrl(host, rest_port = rest_port,
334 uplink_vlan_map = uplink_vlan_map,
335 uplink_vlan_start = uplink_vlan_start)
A R Karthickbf1e4b02017-07-11 20:17:14 -0700336 if olt_type.startswith('ponsim'):
337 ponsim_address = '{}:50060'.format(host)
338 log.info('Enabling ponsim olt')
339 device_id, status = voltha.enable_device(olt_type, address = ponsim_address)
340 else:
341 log.info('Enabling OLT instance for %s with mac %s' %(olt_type, olt_mac))
342 device_id, status = voltha.enable_device(olt_type, olt_mac)
343
344 if device_id is None or status is False:
A R Karthick9dc6e922017-07-12 14:40:16 -0700345 if device_id:
346 voltha.disable_device(device_id)
A R Karthickbf1e4b02017-07-11 20:17:14 -0700347 return None
348
349 switch_map = None
350 olt_installed = False
351 if olt_app is None:
352 olt_app = get_olt_app()
353 try:
A R Karthick090631b2017-07-25 16:05:05 -0700354 time.sleep(5)
A R Karthickbf1e4b02017-07-11 20:17:14 -0700355 switch_map = voltha.config(fake = config_fake)
356 if switch_map is None:
357 voltha.disable_device(device_id)
358 return None
359 log.info('Installing OLT app %s' %olt_app)
360 OnosCtrl.install_app(olt_app)
361 olt_installed = True
362 time.sleep(5)
363 return voltha, device_id, switch_map
364 except:
365 voltha.disable_device(device_id)
366 time.sleep(10)
367 if olt_installed is True:
368 log.info('Uninstalling OLT app %s' %olt_app)
369 OnosCtrl.uninstall_app(olt_app)
370
371 return None
372
373def voltha_teardown(voltha_ctrl, device_id, switch_map, olt_app = None):
374 voltha_ctrl.disable_device(device_id)
375 time.sleep(10)
376 if olt_app is None:
377 olt_app = get_olt_app()
A R Karthickdd064632017-07-12 13:02:17 -0700378 log.info('Uninstalling OLT app %s' %olt_app)
A R Karthickbf1e4b02017-07-11 20:17:14 -0700379 OnosCtrl.uninstall_app(olt_app)