blob: d018edbf5d358148b5c6b76662e567577ffd9442 [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 Karthick57fa9372017-05-24 12:47:03 -07007from CordContainer import Container
A.R Karthick4c4d0492017-05-26 19:23:05 -07008from OnosCtrl import OnosCtrl
A.R Karthick57fa9372017-05-24 12:47:03 -07009
10class VolthaService(object):
11 services = ('consul', 'kafka', 'zookeeper', 'registrator', 'fluentd')
12 compose_file = 'docker-compose-system-test.yml'
13 service_map = {}
14
15 def __init__(self, voltha_loc, controller, interface = 'eth0'):
16 if not os.access(voltha_loc, os.F_OK):
17 raise Exception('Voltha location %s not found' %voltha_loc)
18 compose_file_loc = os.path.join(voltha_loc, 'compose', self.compose_file)
19 if not os.access(compose_file_loc, os.F_OK):
20 raise Exception('Voltha compose file %s not found' %compose_file_loc)
21 self.voltha_loc = voltha_loc
22 self.controller = controller
23 self.interface = interface
24 self.compose_file_loc = compose_file_loc
25
26 def start(self):
27 start_cmd = 'docker-compose -f {} up -d {} {} {} {} {}'.format(self.compose_file_loc,
28 *self.services)
29 ret = os.system(start_cmd)
30 if ret != 0:
31 raise Exception('Failed to start voltha services. Failed with code %d' %ret)
32
33 for service in self.services:
34 name = 'compose_{}_1'.format(service)
35 network = 'compose_default'
36 cnt = Container(name, name)
37 ip = cnt.ip(network = network)
38 if not ip:
39 raise Exception('IP not found for container %s' %name)
40 print('IP %s for service %s' %(ip, service))
41 self.service_map[service] = dict(name = name, network = network, ip = ip)
42
43 #first start chameleon
44 chameleon_start_cmd = "cd {} && sh -c '. ./env.sh && \
45 nohup python chameleon/main.py -v --consul=localhost:8500 \
46 --fluentd={}:24224 --grpc-endpoint=localhost:50555 \
47 >/tmp/chameleon.log 2>&1 &'".format(self.voltha_loc,
48 self.service_map['fluentd']['ip'])
A.R Karthickc2697a12017-05-24 14:01:15 -070049 if not self.service_running('python chameleon/main.py'):
50 ret = os.system(chameleon_start_cmd)
51 if ret != 0:
52 raise Exception('VOLTHA chameleon service not started. Failed with return code %d' %ret)
A.R Karthick4c4d0492017-05-26 19:23:05 -070053 time.sleep(5)
A.R Karthickc2697a12017-05-24 14:01:15 -070054 else:
55 print('Chameleon voltha sevice is already running. Skipped start')
A.R Karthick57fa9372017-05-24 12:47:03 -070056
57 #now start voltha and ofagent
58 voltha_start_cmd = "cd {} && sh -c '. ./env.sh && \
59 nohup python voltha/main.py -v --consul=localhost:8500 --kafka={}:9092 -I {} \
60 --fluentd={}:24224 --rest-port=8880 --grpc-port=50555 \
61 >/tmp/voltha.log 2>&1 &'".format(self.voltha_loc,
62 self.service_map['kafka']['ip'],
63 self.interface,
64 self.service_map['fluentd']['ip'])
A.R Karthickc2697a12017-05-24 14:01:15 -070065 if not self.service_running('python voltha/main.py'):
66 ret = os.system(voltha_start_cmd)
67 if ret != 0:
68 raise Exception('Failed to start VOLTHA. Return code %d' %ret)
A.R Karthick4c4d0492017-05-26 19:23:05 -070069 time.sleep(5)
A.R Karthickc2697a12017-05-24 14:01:15 -070070 else:
71 print('VOLTHA core is already running. Skipped start')
A.R Karthick57fa9372017-05-24 12:47:03 -070072
73 ofagent_start_cmd = "cd {} && sh -c '. ./env.sh && \
74 nohup python ofagent/main.py -v --consul=localhost:8500 \
75 --fluentd={}:24224 --controller={}:6653 --grpc-endpoint=localhost:50555 \
76 >/tmp/ofagent.log 2>&1 &'".format(self.voltha_loc,
77 self.service_map['fluentd']['ip'],
78 self.controller)
A.R Karthickc2697a12017-05-24 14:01:15 -070079 if not self.service_running('python ofagent/main.py'):
80 ret = os.system(ofagent_start_cmd)
81 if ret != 0:
82 raise Exception('VOLTHA ofagent not started. Failed with return code %d' %ret)
A.R Karthick4c4d0492017-05-26 19:23:05 -070083 time.sleep(3)
A.R Karthickc2697a12017-05-24 14:01:15 -070084 else:
85 print('VOLTHA ofagent is already running. Skipped start')
86
A.R Karthick12e08c32017-05-30 17:09:26 -070087 ponsim_start_cmd = "cd {} && sh -c '. ./env.sh && \
88 nohup python ponsim/main.py -v >/tmp/ponsim.log 2>&1 &'".format(self.voltha_loc)
89 if not self.service_running('python ponsim/main.py'):
90 ret = os.system(ponsim_start_cmd)
91 if ret != 0:
92 raise Exception('PONSIM not started. Failed with return code %d' %ret)
93 time.sleep(3)
94 else:
95 print('PONSIM already running. Skipped start')
96
A.R Karthickc2697a12017-05-24 14:01:15 -070097 def service_running(self, pattern):
98 st, _ = getstatusoutput('pgrep -f "{}"'.format(pattern))
99 return True if st == 0 else False
A.R Karthick57fa9372017-05-24 12:47:03 -0700100
101 def kill_service(self, pattern):
102 st, output = getstatusoutput('pgrep -f "{}"'.format(pattern))
103 if st == 0 and output:
104 pids = output.strip().splitlines()
105 for pid in pids:
106 try:
107 os.kill(int(pid), signal.SIGKILL)
108 except:
109 pass
110
111 def stop(self):
112 self.kill_service('python voltha/main.py')
113 self.kill_service('python ofagent/main.py')
114 self.kill_service('python chameleon/main.py')
A.R Karthick12e08c32017-05-30 17:09:26 -0700115 self.kill_service('python ponsim/main.py')
A.R Karthick57fa9372017-05-24 12:47:03 -0700116 service_stop_cmd = 'docker-compose -f {} down'.format(self.compose_file_loc)
117 os.system(service_stop_cmd)
A R Karthick35495c32017-05-11 14:58:32 -0700118
119class VolthaCtrl(object):
120
A.R Karthick4c4d0492017-05-26 19:23:05 -0700121 UPLINK_VLAN_MAP = { 'of:0000000000000001' : '222' }
122
123 def __init__(self, host, rest_port = 8881, uplink_vlan_map = UPLINK_VLAN_MAP):
A R Karthick35495c32017-05-11 14:58:32 -0700124 self.host = host
125 self.rest_port = rest_port
126 self.rest_url = 'http://{}:{}/api/v1'.format(host, rest_port)
A.R Karthick4c4d0492017-05-26 19:23:05 -0700127 self.uplink_vlan_map = uplink_vlan_map
128 self.switches = []
129 self.switch_map = {}
130
131 def config(self, fake = False):
132 devices = OnosCtrl.get_devices()
133 if not devices:
134 return self.switch_map
135 voltha_devices = filter(lambda d: not d['mfr'].startswith('Nicira'), devices)
136 self.switches = voltha_devices
137 device_config = { 'devices' : { } }
138 device_id = None
139 for device in voltha_devices:
140 device_id = device['id']
141 ports = OnosCtrl.get_ports_device(device_id)
142 nni_ports = filter(lambda p: p['isEnabled'] and 'annotations' in p and p['annotations']['portName'].startswith('nni'), ports)
143 uni_ports = filter(lambda p: p['isEnabled'] and 'annotations' in p and p['annotations']['portName'].startswith('uni'), ports)
144 if device_id not in self.uplink_vlan_map:
145 log.info('Skipping voltha device %s as uplink vlan does not exist' %device_id)
146 continue
147 if not nni_ports:
148 log.info('Voltha device %s has no NNI ports' %device_id)
149 if fake is True:
150 log.info('Faking NNI port 0')
151 nni_ports = [ {'port': '0'} ]
152 else:
153 log.info('Skip configuring device %s' %device_id)
154 continue
155 if not uni_ports:
156 log.info('Voltha device %s has no UNI ports' %device_id)
157 if fake is True:
158 log.info('Faking UNI port 252')
159 uni_ports = [ {'port': '252'} ]
160 else:
161 log.info('Skip configuring device %s' %device_id)
162 continue
163 uplink_vlan = self.uplink_vlan_map[device_id]
164 onu_ports = map(lambda uni: uni['port'], uni_ports)
165 self.switch_map[device_id] = dict(uplink_vlan = uplink_vlan, ports = onu_ports)
166 device_config['devices'][device_id] = {}
167 device_config['devices'][device_id]['basic'] = dict(driver='pmc-olt')
168 device_config['devices'][device_id]['accessDevice'] = dict(uplink=nni_ports[0]['port'],
169 vlan = uplink_vlan,
170 defaultVlan='0'
171 )
172 if device_id:
173 #toggle drivers/openflow base before reconfiguring the driver and olt config data
174 OnosCtrl('org.onosproject.drivers').deactivate()
175 OnosCtrl('org.onosproject.openflow-base').deactivate()
176 OnosCtrl.config(device_config)
177 time.sleep(2)
178 OnosCtrl('org.onosproject.drivers').activate()
179 OnosCtrl('org.onosproject.openflow-base').activate()
180 time.sleep(5)
181
182 return self.switch_map
A R Karthick35495c32017-05-11 14:58:32 -0700183
184 def get_devices(self):
185 url = '{}/local/devices'.format(self.rest_url)
186 resp = requests.get(url)
187 if resp.ok is not True or resp.status_code != 200:
188 return None
189 return resp.json()
190
A.R Karthick8b9c5f12017-05-30 17:47:08 -0700191 def enable_device(self, olt_type, olt_mac = None, address = None):
A R Karthick35495c32017-05-11 14:58:32 -0700192 url = '{}/local/devices'.format(self.rest_url)
A.R Karthick8b9c5f12017-05-30 17:47:08 -0700193 if olt_mac is None and address is None:
194 log.error('Either olt mac or address needs to be specified')
A.R Karthick8a507cf2017-06-02 18:44:49 -0700195 return None, False
A.R Karthick8b9c5f12017-05-30 17:47:08 -0700196 if olt_mac is not None:
197 device_config = { 'type' : olt_type, 'mac_address' : olt_mac }
198 else:
199 device_config = { 'type' : olt_type, 'host_and_port' : address }
A R Karthick35495c32017-05-11 14:58:32 -0700200 #pre-provision
A.R Karthick8b9c5f12017-05-30 17:47:08 -0700201 if olt_mac is not None:
202 log.info('Pre-provisioning %s with mac %s' %(olt_type, olt_mac))
203 else:
204 log.info('Pre-provisioning %s with address %s' %(olt_type, address))
A R Karthick35495c32017-05-11 14:58:32 -0700205 resp = requests.post(url, data = json.dumps(device_config))
206 if resp.ok is not True or resp.status_code != 200:
A.R Karthick8a507cf2017-06-02 18:44:49 -0700207 return None, False
A R Karthick35495c32017-05-11 14:58:32 -0700208 device_id = resp.json()['id']
209 log.info('Enabling device %s' %(device_id))
210 enable_url = '{}/{}/enable'.format(url, device_id)
211 resp = requests.post(enable_url)
212 if resp.ok is not True or resp.status_code != 200:
A.R Karthick8a507cf2017-06-02 18:44:49 -0700213 return None, False
A R Karthick35495c32017-05-11 14:58:32 -0700214 #get operational status
215 time.sleep(5)
216 log.info('Checking operational status for device %s' %(device_id))
217 resp = requests.get('{}/{}'.format(url, device_id))
218 if resp.ok is not True or resp.status_code != 200:
A.R Karthick8a507cf2017-06-02 18:44:49 -0700219 return device_id, False
A R Karthick35495c32017-05-11 14:58:32 -0700220 device_info = resp.json()
221 if device_info['oper_status'] != 'ACTIVE' or \
222 device_info['admin_state'] != 'ENABLED' or \
223 device_info['connect_status'] != 'REACHABLE':
A.R Karthick8a507cf2017-06-02 18:44:49 -0700224 return device_id, False
A R Karthick35495c32017-05-11 14:58:32 -0700225
A.R Karthick8a507cf2017-06-02 18:44:49 -0700226 return device_id, True
227
228 def disable_device(self, device_id, delete = True):
229 log.info('Disabling device %s' %(device_id))
230 disable_url = '{}/local/devices/{}/disable'.format(self.rest_url, device_id)
231 resp = requests.post(disable_url)
232 if resp.ok is not True or resp.status_code != 200:
233 return False
234 if delete is True:
235 log.info('Deleting device %s' %(device_id))
236 delete_url = '{}/local/devices/{}/delete'.format(self.rest_url, device_id)
237 resp = requests.delete(delete_url)
238 if resp.status_code not in [204, 202, 200]:
239 return False
A R Karthick35495c32017-05-11 14:58:32 -0700240 return True
Chetan Gaonker3620a112017-05-23 06:10:15 +0000241
242 def get_operational_status(self, device_id):
243 url = '{}/local/devices'.format(self.rest_url)
244 log.info('Checking operational status for device %s' %(device_id))
245 resp = requests.get('{}/{}'.format(url, device_id))
246 if resp.ok is not True or resp.status_code != 200:
247 return False
248 device_info = resp.json()
249 if device_info['oper_status'] != 'ACTIVE' or \
250 device_info['admin_state'] != 'ENABLED' or \
251 device_info['connect_status'] != 'REACHABLE':
252 return False
253 return True
254
255 def check_preprovision_status(self, device_id):
256 url = '{}/local/devices'.format(self.rest_url)
257 log.info('Check if device %s is in Preprovisioning state'%(device_id))
258 resp = requests.get('{}/{}'.format(url, device_id))
259 if resp.ok is not True or resp.status_code != 200:
260 return False
261 device_info = resp.json()
262 if device_info['admin_status'] == 'PREPROVISIONED':
263 return True
264 return False