blob: c94ec2d059abc082d1c489d53debcab36b21810a [file] [log] [blame]
khenaidoo08d48d22017-06-29 19:42:49 -04001from random import randint
2from time import time, sleep
3
Rachit Shrivastava8f4f9bf2017-07-20 11:59:30 -04004from google.protobuf.json_format import MessageToDict, ParseDict
Stephane Barbariecd51f992017-09-07 16:37:02 -04005from unittest import main, skip
khenaidoo08d48d22017-06-29 19:42:49 -04006from voltha.protos.device_pb2 import Device
7from tests.itests.voltha.rest_base import RestBase
khenaidood3c335e2017-07-05 16:36:59 -04008from common.utils.consulhelpers import get_endpoint_from_consul, \
9 get_all_instances_of_service
khenaidoo08d48d22017-06-29 19:42:49 -040010from common.utils.consulhelpers import verify_all_services_healthy
11from tests.itests.docutests.test_utils import \
12 run_command_to_completion_with_raw_stdout, \
13 run_command_to_completion_with_stdout_in_list
14from voltha.protos.voltha_pb2 import AlarmFilter
khenaidood3c335e2017-07-05 16:36:59 -040015from google.protobuf.empty_pb2 import Empty
16import grpc
17from voltha.protos import third_party
18from voltha.protos import voltha_pb2
19from voltha.core.flow_decomposer import *
20from voltha.protos.openflow_13_pb2 import FlowTableUpdate
Rachit Shrivastava8f4f9bf2017-07-20 11:59:30 -040021from voltha.protos import bbf_fiber_base_pb2 as fb
Rachit Shrivastavaa182e912017-07-28 15:18:34 -040022from tests.itests.voltha.test_voltha_xpon import scenario as xpon_scenario
khenaidoo08d48d22017-06-29 19:42:49 -040023
24LOCAL_CONSUL = "localhost:8500"
25DOCKER_COMPOSE_FILE = "compose/docker-compose-system-test.yml"
26
27command_defs = dict(
28 docker_ps="docker ps",
29 docker_compose_start_all="docker-compose -f {} up -d "
30 .format(DOCKER_COMPOSE_FILE),
31 docker_stop_and_remove_all_containers="docker-compose -f {} down"
32 .format(DOCKER_COMPOSE_FILE),
33 docker_compose_start_voltha="docker-compose -f {} up -d voltha "
34 .format(DOCKER_COMPOSE_FILE),
35 docker_compose_stop_voltha="docker-compose -f {} stop voltha"
36 .format(DOCKER_COMPOSE_FILE),
37 docker_compose_remove_voltha="docker-compose -f {} rm -f voltha"
38 .format(DOCKER_COMPOSE_FILE),
khenaidood3c335e2017-07-05 16:36:59 -040039 docker_compose_scale_voltha="docker-compose -f {} scale "
40 "voltha=".format(DOCKER_COMPOSE_FILE),
khenaidoo08d48d22017-06-29 19:42:49 -040041 kafka_topics="kafkacat -b {} -L",
42 kafka_alarms="kafkacat -o end -b {} -C -t voltha.alarms -c 2",
43 kafka_kpis="kafkacat -o end -b {} -C -t voltha.kpis -c 5"
44)
45
Rachit Shrivastavaa182e912017-07-28 15:18:34 -040046obj_type_config = {
47 'cg': {'type':'channel_groups',
48 'config':'channelgroup_config'},
49 'cpart': {'type':'channel_partitions',
50 'config':'channelpartition_config'},
51 'cpair': {'type':'channel_pairs',
52 'config':'channelpair_config'},
53 'cterm': {'type':'channel_terminations',
54 'config':'channeltermination_config'},
55 'vontani':{'type':'v_ont_anis',
56 'config':'v_ontani_config'},
57 'ontani': {'type':'ont_anis',
58 'config':'ontani_config'},
59 'venet': {'type':'v_enets',
60 'config':'v_enet_config'}
61}
Rachit Shrivastava8f4f9bf2017-07-20 11:59:30 -040062
khenaidood3c335e2017-07-05 16:36:59 -040063
khenaidoo08d48d22017-06-29 19:42:49 -040064class DispatcherTest(RestBase):
khenaidood3c335e2017-07-05 16:36:59 -040065 def setUp(self):
66 self.grpc_channels = dict()
khenaidoo08d48d22017-06-29 19:42:49 -040067
68 t0 = [time()]
69
70 def pt(self, msg=''):
71 t1 = time()
72 print '%20.8f ms - %s' % (1000 * (t1 - DispatcherTest.t0[0]),
73 msg)
74 DispatcherTest.t0[0] = t1
75
khenaidoo08d48d22017-06-29 19:42:49 -040076 def wait_till(self, msg, predicate, interval=0.1, timeout=5.0):
77 deadline = time() + timeout
78 while time() < deadline:
79 if predicate():
80 return
81 sleep(interval)
82 self.fail('Timed out while waiting for condition: {}'.format(msg))
83
khenaidood3c335e2017-07-05 16:36:59 -040084 def get_channel(self, voltha_grpc):
85 if voltha_grpc not in self.grpc_channels:
86 self.grpc_channels[voltha_grpc] = grpc.insecure_channel(
87 voltha_grpc)
88 return self.grpc_channels[voltha_grpc]
khenaidoo08d48d22017-06-29 19:42:49 -040089
90 def test_01_global_rest_apis(self):
91 # Start the voltha ensemble with a single voltha instance
92 self._stop_and_remove_all_containers()
93 sleep(5) # A small wait for the system to settle down
94 self.start_all_containers()
95 self.set_rest_endpoint()
96 self.set_kafka_endpoint()
97
Stephane Barbariecd51f992017-09-07 16:37:02 -040098 # self._get_root_rest()
khenaidood3c335e2017-07-05 16:36:59 -040099 self._get_schema_rest()
100 self._get_health_rest()
101 self._get_voltha_rest()
102 self._list_voltha_instances_rest()
103 self._get_voltha_instance_rest()
104 olt_id = self._add_olt_device_rest()
105 self._verify_device_preprovisioned_state_rest(olt_id)
106 self._activate_device_rest(olt_id)
107 ldev_id = self._wait_for_logical_device_rest(olt_id)
108 ldevices = self._list_logical_devices_rest()
khenaidoo08d48d22017-06-29 19:42:49 -0400109 logical_device_id = ldevices['items'][0]['id']
khenaidood3c335e2017-07-05 16:36:59 -0400110 self._get_logical_device_rest(logical_device_id)
111 self._list_logical_device_ports_rest(logical_device_id)
112 self._list_and_update_logical_device_flows_rest(logical_device_id)
113 self._list_and_update_logical_device_flow_groups_rest(
114 logical_device_id)
115 devices = self._list_devices_rest()
khenaidoo08d48d22017-06-29 19:42:49 -0400116 device_id = devices['items'][0]['id']
khenaidood3c335e2017-07-05 16:36:59 -0400117 self._get_device_rest(device_id)
118 self._list_device_ports_rest(device_id)
119 self._list_device_flows_rest(device_id)
120 self._list_device_flow_groups_rest(device_id)
121 self._get_images_rest(device_id)
122 self._self_test_rest(device_id)
123 dtypes = self._list_device_types_rest()
124 self._get_device_type_rest(dtypes['items'][0]['id'])
125 alarm_filter = self._create_device_filter_rest(olt_id)
126 self._remove_device_filter_rest(alarm_filter['id'])
Rachit Shrivastavaa182e912017-07-28 15:18:34 -0400127 #for xPON objects
128 for item in xpon_scenario:
129 for key,value in item.items():
Stephane Barbariecd51f992017-09-07 16:37:02 -0400130 try:
131 _device_id = None
132 _obj_action = [val for val in key.split('-')]
133 _type_config = obj_type_config[_obj_action[0]]
134 if _obj_action[0] == "cterm":
135 _device_id = olt_id
136 if _obj_action[1] == "mod":
137 continue
138 elif _obj_action[1] == "add":
139 _xpon_obj = self._create_xpon_object_rest(_type_config,
140 value,
141 _device_id)
142 elif _obj_action[1] == "del":
143 self._delete_xpon_object_rest(_type_config,
144 value,
145 _device_id)
146 except Exception, e:
147 print 'An error occurred', e
Rachit Shrivastavaa182e912017-07-28 15:18:34 -0400148 continue
Stephane Barbariecd51f992017-09-07 16:37:02 -0400149
khenaidoo08d48d22017-06-29 19:42:49 -0400150 # TODO: PM APIs test
151
Stephane Barbariecd51f992017-09-07 16:37:02 -0400152 @skip('Test fails due to environment configuration. Need to investigate. Refer to VOL-427')
khenaidoo08d48d22017-06-29 19:42:49 -0400153 def test_02_cross_instances_dispatch(self):
khenaidood3c335e2017-07-05 16:36:59 -0400154
155 def prompt(input_func, text):
156 val = input_func(text)
157 return val
158
159 def prompt_for_return(text):
160 return raw_input(text)
161
162 # Start the voltha ensemble with a single voltha instance
163 self._stop_and_remove_all_containers()
164 sleep(5) # A small wait for the system to settle down
165 self.start_all_containers()
166 self.set_rest_endpoint()
167 self.set_kafka_endpoint()
168
169 # Scale voltha to 3 instances and setup the voltha grpc assigments
170 self._scale_voltha(3)
171 sleep(10) # A small wait for the system to settle down
172 voltha_instances = get_all_instances_of_service(LOCAL_CONSUL,
173 'voltha-grpc')
174 self.assertEqual(len(voltha_instances), 3)
175 self.ponsim_voltha_stub_local = voltha_pb2.VolthaLocalServiceStub(
176 self.get_channel(self._get_grpc_address(voltha_instances[2])))
177 self.ponsim_voltha_stub_global = voltha_pb2.VolthaGlobalServiceStub(
178 self.get_channel(self._get_grpc_address(voltha_instances[2])))
179
180 self.simulated_voltha_stub_local = voltha_pb2.VolthaLocalServiceStub(
181 self.get_channel(self._get_grpc_address(voltha_instances[1])))
182 self.simulated_voltha_stub_global = voltha_pb2.VolthaGlobalServiceStub(
183 self.get_channel(self._get_grpc_address(voltha_instances[1])))
184
185 self.empty_voltha_stub_local = voltha_pb2.VolthaLocalServiceStub(
186 self.get_channel(self._get_grpc_address(voltha_instances[0])))
187 self.empty_voltha_stub_global = voltha_pb2.VolthaGlobalServiceStub(
188 self.get_channel(self._get_grpc_address(voltha_instances[0])))
189
190 # Prompt the user to start ponsim
191 # Get the user to start PONSIM as root
192 prompt(prompt_for_return,
193 '\nStart PONSIM as root in another window ...')
194
195 prompt(prompt_for_return,
196 '\nEnsure port forwarding is set on ponmgnt ...')
197
198 # Test 1:
khenaidoo997edbc2017-07-13 10:25:58 -0400199 # A. Get the list of adapters using a global stub
200 # B. Get the list of adapters using a local stub
201 # C. Verify that the two lists are the same
202 adapters_g = self._get_adapters_grpc(self.ponsim_voltha_stub_global)
203 adapters_l = self._get_adapters_grpc(self.empty_voltha_stub_local)
204 assert adapters_g == adapters_l
205
206 # Test 2:
khenaidood3c335e2017-07-05 16:36:59 -0400207 # A. Provision a pomsim olt using the ponsim_voltha_stub
208 # B. Enable the posim olt using the simulated_voltha_stub
209 # C. Wait for onu discovery using the empty_voltha_stub
210 ponsim_olt = self._provision_ponsim_olt_grpc(
211 self.ponsim_voltha_stub_local)
212 ponsim_logical_device_id = self._enable_device_grpc(
213 self.simulated_voltha_stub_global,
214 ponsim_olt.id)
215 self._wait_for_onu_discovery_grpc(self.empty_voltha_stub_global,
216 ponsim_olt.id,
217 count=4)
khenaidoo997edbc2017-07-13 10:25:58 -0400218 # Test 3:
khenaidood3c335e2017-07-05 16:36:59 -0400219 # A. Provision a simulated olt using the simulated_voltha_stub
220 # B. Enable the simulated olt using the ponsim_voltha_stub
221 # C. Wait for onu discovery using the empty_voltha_stub
222 simulated_olt = self._provision_simulated_olt_grpc(
223 self.simulated_voltha_stub_local)
224 simulated_logical_device_id = self._enable_device_grpc(
225 self.ponsim_voltha_stub_global, simulated_olt.id)
226 self._wait_for_onu_discovery_grpc(self.empty_voltha_stub_global,
227 simulated_olt.id, count=4)
228
khenaidoo997edbc2017-07-13 10:25:58 -0400229 # Test 4:
khenaidood3c335e2017-07-05 16:36:59 -0400230 # Verify that we have at least 8 devices created using the global
231 # REST and also via direct grpc in the empty stub
232 devices_via_rest = self._list_devices_rest(8)['items']
233 devices_via_global_grpc = self._get_devices_grpc(
234 self.empty_voltha_stub_global)
235 assert len(devices_via_rest) == len(devices_via_global_grpc)
236
khenaidoo997edbc2017-07-13 10:25:58 -0400237 # Test 5:
khenaidood3c335e2017-07-05 16:36:59 -0400238 # A. Create 2 Alarms filters using REST
239 # B. Ensure it is present across all instances
240 # C. Ensure when requesting the alarm filters we do not get
241 # duplicate results
242 alarm_filter1 = self._create_device_filter_rest(ponsim_olt.id)
243 alarm_filter2 = self._create_device_filter_rest(simulated_olt.id)
244 global_filters = self._get_alarm_filters_rest()
245 filter = self._get_alarm_filters_grpc(self.simulated_voltha_stub_local)
246 assert global_filters == MessageToDict(filter)
247 filter = self._get_alarm_filters_grpc(self.ponsim_voltha_stub_local)
248 assert global_filters == MessageToDict(filter)
249 filter = self._get_alarm_filters_grpc(self.empty_voltha_stub_local)
250 assert global_filters == MessageToDict(filter)
251 filter = self._get_alarm_filters_grpc(self.empty_voltha_stub_global)
252 assert global_filters == MessageToDict(filter)
253
khenaidoo997edbc2017-07-13 10:25:58 -0400254 # Test 6:
khenaidood3c335e2017-07-05 16:36:59 -0400255 # A. Delete an alarm filter
256 # B. Ensure that filter is deleted from all instances
257 self._remove_device_filter_rest(alarm_filter1['id'])
258 previous_filters = global_filters
259 global_filters = self._get_alarm_filters_rest()
260 assert global_filters != previous_filters
261 filter = self._get_alarm_filters_grpc(self.simulated_voltha_stub_local)
262 assert global_filters == MessageToDict(filter)
263 filter = self._get_alarm_filters_grpc(self.ponsim_voltha_stub_local)
264 assert global_filters == MessageToDict(filter)
265 filter = self._get_alarm_filters_grpc(self.empty_voltha_stub_local)
266 assert global_filters == MessageToDict(filter)
267 filter = self._get_alarm_filters_grpc(self.empty_voltha_stub_global)
268 assert global_filters == MessageToDict(filter)
269
khenaidoo997edbc2017-07-13 10:25:58 -0400270 # Test 7:
khenaidood3c335e2017-07-05 16:36:59 -0400271 # A. Simulate EAPOL install on ponsim instance using grpc
272 # B. Validate the flows using global REST
273 # C. Retrieve the flows from global grpc using empty voltha instance
274 self._install_eapol_flow_grpc(self.ponsim_voltha_stub_local,
275 ponsim_logical_device_id)
276 self._verify_olt_eapol_flow_rest(ponsim_olt.id)
277 res = self._get_olt_flows_grpc(self.empty_voltha_stub_global,
278 ponsim_logical_device_id)
279
Rachit Shrivastava8f4f9bf2017-07-20 11:59:30 -0400280 # Test 8:
Rachit Shrivastavaa182e912017-07-28 15:18:34 -0400281 # A. Create xPON objects instance using REST
282 # B. Ensuring that Channeltermination is present on specific instances
283 # C. Ensuring that other xPON objects are present in all instances
284 for item in xpon_scenario:
285 for key,value in item.items():
286 _obj_action = [val for val in key.split('-')]
287 _type_config = obj_type_config[_obj_action[0]]
288 if _obj_action[1] == "mod":
289 continue
290 if _obj_action[0] == "cterm":
291 if _obj_action[1] == "add":
292 #Ponsim OLT
293 self._create_xpon_object_rest(_type_config,
294 value,
295 ponsim_olt.id)
296 self._verify_xpon_object_on_device(
297 _type_config,
298 self.ponsim_voltha_stub_global,
299 ponsim_olt.id)
300 self._delete_xpon_object_rest(_type_config,
301 value,
302 ponsim_olt.id)
303 #Simulated OLT
304 self._create_xpon_object_rest(_type_config,
305 value,
306 simulated_olt.id)
307 self._verify_xpon_object_on_device(
308 _type_config,
309 self.simulated_voltha_stub_global,
310 simulated_olt.id)
311 self._delete_xpon_object_rest(_type_config,
312 value,
313 simulated_olt.id)
314 elif _obj_action[1] == "del":
315 continue
316 else:
317 if _obj_action[1] == "add":
318 self._create_xpon_object_rest(_type_config, value)
319 #Checking with Ponsim OLT
320 self._verify_xpon_object_on_device(
321 _type_config,
322 self.ponsim_voltha_stub_global)
323 #Checking with empty instance
324 self._verify_xpon_object_on_device(
325 _type_config,
326 self.empty_voltha_stub_global)
327 #Checking with Simulated OLT
328 self._verify_xpon_object_on_device(
329 _type_config,
330 self.simulated_voltha_stub_global)
331 elif _obj_action[1] == "del":
332 self._delete_xpon_object_rest(_type_config, value)
Rachit Shrivastava8f4f9bf2017-07-20 11:59:30 -0400333
khenaidoo997edbc2017-07-13 10:25:58 -0400334 # TODO: More tests to be added as new features are added
khenaidood3c335e2017-07-05 16:36:59 -0400335
336
337 def _get_grpc_address(self, voltha_instance):
338 address = '{}:{}'.format(voltha_instance['ServiceAddress'],
339 voltha_instance['ServicePort'])
340 return address
khenaidoo08d48d22017-06-29 19:42:49 -0400341
342 def _stop_and_remove_all_containers(self):
343 # check if there are any running containers first
344 cmd = command_defs['docker_ps']
345 out, err, rc = run_command_to_completion_with_stdout_in_list(cmd)
346 self.assertEqual(rc, 0)
347 if len(out) > 1: # not counting docker ps header
348 cmd = command_defs['docker_stop_and_remove_all_containers']
349 out, err, rc = run_command_to_completion_with_raw_stdout(cmd)
350 self.assertEqual(rc, 0)
351
352 def start_all_containers(self):
353 t0 = time()
354
355 # start all the containers
356 self.pt("Starting all containers ...")
357 cmd = command_defs['docker_compose_start_all']
358 out, err, rc = run_command_to_completion_with_raw_stdout(cmd)
359 self.assertEqual(rc, 0)
360
361 self.pt("Waiting for voltha and chameleon containers to be ready ...")
362 self.wait_till('voltha services HEALTHY',
363 lambda: verify_all_services_healthy(
364 LOCAL_CONSUL, service_name='voltha-grpc') == True,
365 timeout=10)
366 self.wait_till('chameleon services HEALTHY',
367 lambda: verify_all_services_healthy(
khenaidood3c335e2017-07-05 16:36:59 -0400368 LOCAL_CONSUL,
369 service_name='chameleon-rest') == True,
khenaidoo08d48d22017-06-29 19:42:49 -0400370 timeout=10)
371
372 # Chameleon takes some time to compile the protos and make them
373 # available. So let's wait 10 seconds
374 sleep(10)
375
376 def set_rest_endpoint(self):
377 self.rest_endpoint = get_endpoint_from_consul(LOCAL_CONSUL,
Stephane Barbariecd51f992017-09-07 16:37:02 -0400378 'envoy-8443')
ubuntuc5c83d72017-07-01 17:57:19 -0700379 self.base_url = 'https://' + self.rest_endpoint
khenaidoo08d48d22017-06-29 19:42:49 -0400380
381 def set_kafka_endpoint(self):
382 self.kafka_endpoint = get_endpoint_from_consul(LOCAL_CONSUL, 'kafka')
383
khenaidood3c335e2017-07-05 16:36:59 -0400384 def _scale_voltha(self, scale=2):
385 self.pt("Scaling voltha ...")
386 cmd = command_defs['docker_compose_scale_voltha'] + str(scale)
387 out, err, rc = run_command_to_completion_with_raw_stdout(cmd)
388 self.assertEqual(rc, 0)
khenaidoo08d48d22017-06-29 19:42:49 -0400389
khenaidood3c335e2017-07-05 16:36:59 -0400390 def _get_root_rest(self):
khenaidoo08d48d22017-06-29 19:42:49 -0400391 res = self.get('/', expected_content_type='text/html')
392 self.assertGreaterEqual(res.find('swagger'), 0)
393
khenaidood3c335e2017-07-05 16:36:59 -0400394 def _get_schema_rest(self):
khenaidoo08d48d22017-06-29 19:42:49 -0400395 res = self.get('/schema')
khenaidood3c335e2017-07-05 16:36:59 -0400396 self.assertEqual(set(res.keys()),
397 {'protos', 'yang_from', 'swagger_from'})
khenaidoo08d48d22017-06-29 19:42:49 -0400398
khenaidood3c335e2017-07-05 16:36:59 -0400399 def _get_health_rest(self):
khenaidoo08d48d22017-06-29 19:42:49 -0400400 res = self.get('/health')
401 self.assertEqual(res['state'], 'HEALTHY')
402
403 # ~~~~~~~~~~~~~~~~~~~~~ TOP LEVEL VOLTHA OPERATIONS ~~~~~~~~~~~~~~~~~~~~~~~
404
khenaidood3c335e2017-07-05 16:36:59 -0400405 def _get_voltha_rest(self):
khenaidoo08d48d22017-06-29 19:42:49 -0400406 res = self.get('/api/v1')
407 self.assertEqual(res['version'], '0.9.0')
408
khenaidood3c335e2017-07-05 16:36:59 -0400409 def _list_voltha_instances_rest(self):
khenaidoo08d48d22017-06-29 19:42:49 -0400410 res = self.get('/api/v1/instances')
411 self.assertEqual(len(res['items']), 1)
412
khenaidood3c335e2017-07-05 16:36:59 -0400413 def _get_voltha_instance_rest(self):
khenaidoo08d48d22017-06-29 19:42:49 -0400414 res = self.get('/api/v1/instances')
khenaidood3c335e2017-07-05 16:36:59 -0400415 voltha_id = res['items'][0]
khenaidoo08d48d22017-06-29 19:42:49 -0400416 res = self.get('/api/v1/instances/{}'.format(voltha_id))
417 self.assertEqual(res['version'], '0.9.0')
418
khenaidood3c335e2017-07-05 16:36:59 -0400419 def _add_olt_device_rest(self, grpc=None):
khenaidoo08d48d22017-06-29 19:42:49 -0400420 device = Device(
421 type='simulated_olt',
422 mac_address='00:00:00:00:00:01'
423 )
424 device = self.post('/api/v1/devices', MessageToDict(device),
Stephane Barbariecd51f992017-09-07 16:37:02 -0400425 expected_http_code=200)
khenaidoo08d48d22017-06-29 19:42:49 -0400426 return device['id']
427
khenaidood3c335e2017-07-05 16:36:59 -0400428 def _provision_simulated_olt_grpc(self, stub):
429 device = Device(
430 type='simulated_olt',
431 mac_address='00:00:00:00:00:01'
432 )
433 device = stub.CreateDevice(device)
434 return device
435
436 def _provision_ponsim_olt_grpc(self, stub):
437 device = Device(
438 type='ponsim_olt',
439 host_and_port='172.17.0.1:50060'
440 )
441 device = stub.CreateDevice(device)
442 return device
443
444 def _enable_device_grpc(self, stub, device_id):
445 logical_device_id = None
446 try:
447 stub.EnableDevice(voltha_pb2.ID(id=device_id))
448 while True:
449 device = stub.GetDevice(voltha_pb2.ID(id=device_id))
450 # If this is an OLT then acquire logical device id
451 if device.oper_status == voltha_pb2.OperStatus.ACTIVE:
452 if device.type.endswith('_olt'):
453 assert device.parent_id
454 logical_device_id = device.parent_id
455 self.pt('success (logical device id = {})'.format(
456 logical_device_id))
457 else:
458 self.pt('success (device id = {})'.format(device.id))
459 break
460 self.pt('waiting for device to be enabled...')
461 sleep(.5)
462 except Exception, e:
463 self.pt('Error enabling {}. Error:{}'.format(device_id, e))
464 return logical_device_id
465
466 def _delete_device_grpc(self, stub, device_id):
467 try:
468 stub.DeleteDevice(voltha_pb2.ID(id=device_id))
469 while True:
470 device = stub.GetDevice(voltha_pb2.ID(id=device_id))
471 assert not device
472 except Exception, e:
473 self.pt('deleting device {}. Error:{}'.format(device_id, e))
474
475 def _get_devices_grpc(self, stub):
476 res = stub.ListDevices(Empty())
477 return res.items
478
khenaidoo997edbc2017-07-13 10:25:58 -0400479 def _get_adapters_grpc(self, stub):
480 res = stub.ListAdapters(Empty())
481 return res.items
482
khenaidood3c335e2017-07-05 16:36:59 -0400483 def _find_onus_grpc(self, stub, olt_id):
484 devices = self._get_devices_grpc(stub)
485 return [
486 d for d in devices
487 if d.parent_id == olt_id
488 ]
489
490 def _wait_for_onu_discovery_grpc(self, stub, olt_id, count=4):
491 # shortly after we shall see the discovery of four new onus, linked to
492 # the olt device
493 self.wait_till(
494 'find ONUs linked to the olt device',
495 lambda: len(self._find_onus_grpc(stub, olt_id)) >= count,
496 2
497 )
498 # verify that they are properly set
499 onus = self._find_onus_grpc(stub, olt_id)
500 for onu in onus:
501 self.assertEqual(onu.admin_state, 3) # ENABLED
502 self.assertEqual(onu.oper_status, 4) # ACTIVE
503
504 return [onu.id for onu in onus]
505
506 def _verify_device_preprovisioned_state_rest(self, olt_id):
khenaidoo08d48d22017-06-29 19:42:49 -0400507 # we also check that so far what we read back is same as what we get
508 # back on create
509 device = self.get('/api/v1/devices/{}'.format(olt_id))
510 self.assertNotEqual(device['id'], '')
511 self.assertEqual(device['adapter'], 'simulated_olt')
512 self.assertEqual(device['admin_state'], 'PREPROVISIONED')
513 self.assertEqual(device['oper_status'], 'UNKNOWN')
514
khenaidood3c335e2017-07-05 16:36:59 -0400515 def _activate_device_rest(self, olt_id):
khenaidoo08d48d22017-06-29 19:42:49 -0400516 path = '/api/v1/devices/{}'.format(olt_id)
Stephane Barbariecd51f992017-09-07 16:37:02 -0400517 self.post(path + '/enable', expected_http_code=200)
khenaidoo08d48d22017-06-29 19:42:49 -0400518 device = self.get(path)
519 self.assertEqual(device['admin_state'], 'ENABLED')
520
521 self.wait_till(
522 'admin state moves to ACTIVATING or ACTIVE',
523 lambda: self.get(path)['oper_status'] in ('ACTIVATING', 'ACTIVE'),
524 timeout=0.5)
525
526 # eventually, it shall move to active state and by then we shall have
527 # device details filled, connect_state set, and device ports created
528 self.wait_till(
529 'admin state ACTIVE',
530 lambda: self.get(path)['oper_status'] == 'ACTIVE',
531 timeout=0.5)
532 device = self.get(path)
533 images = device['images']
534 image = images['image']
535 image_1 = image[0]
536 version = image_1['version']
537 self.assertNotEqual(version, '')
538 self.assertEqual(device['connect_status'], 'REACHABLE')
539
540 ports = self.get(path + '/ports')['items']
541 self.assertEqual(len(ports), 2)
542
khenaidood3c335e2017-07-05 16:36:59 -0400543 def _wait_for_logical_device_rest(self, olt_id):
khenaidoo08d48d22017-06-29 19:42:49 -0400544 # we shall find the logical device id from the parent_id of the olt
545 # (root) device
546 device = self.get(
547 '/api/v1/devices/{}'.format(olt_id))
548 self.assertNotEqual(device['parent_id'], '')
549 logical_device = self.get(
550 '/api/v1/logical_devices/{}'.format(device['parent_id']))
551
552 # the logical device shall be linked back to the hard device,
553 # its ports too
554 self.assertEqual(logical_device['root_device_id'], device['id'])
555
556 logical_ports = self.get(
557 '/api/v1/logical_devices/{}/ports'.format(
558 logical_device['id'])
559 )['items']
560 self.assertGreaterEqual(len(logical_ports), 1)
561 logical_port = logical_ports[0]
562 self.assertEqual(logical_port['id'], 'nni')
563 self.assertEqual(logical_port['ofp_port']['name'], 'nni')
564 self.assertEqual(logical_port['ofp_port']['port_no'], 129)
565 self.assertEqual(logical_port['device_id'], device['id'])
566 self.assertEqual(logical_port['device_port_no'], 2)
567 return logical_device['id']
568
khenaidood3c335e2017-07-05 16:36:59 -0400569 def _list_logical_devices_rest(self):
khenaidoo08d48d22017-06-29 19:42:49 -0400570 res = self.get('/api/v1/logical_devices')
571 self.assertGreaterEqual(len(res['items']), 1)
572 return res
573
khenaidood3c335e2017-07-05 16:36:59 -0400574 def _get_logical_device_rest(self, id):
khenaidoo08d48d22017-06-29 19:42:49 -0400575 res = self.get('/api/v1/logical_devices/{}'.format(id))
576 self.assertIsNotNone(res['datapath_id'])
577
khenaidood3c335e2017-07-05 16:36:59 -0400578 def _list_logical_device_ports_rest(self, id):
khenaidoo08d48d22017-06-29 19:42:49 -0400579 res = self.get('/api/v1/logical_devices/{}/ports'.format(id))
580 self.assertGreaterEqual(len(res['items']), 1)
581
khenaidood3c335e2017-07-05 16:36:59 -0400582 def _list_and_update_logical_device_flows_rest(self, id):
khenaidoo08d48d22017-06-29 19:42:49 -0400583
584 # retrieve flow list
585 res = self.get('/api/v1/logical_devices/{}/flows'.format(id))
586 len_before = len(res['items'])
587
588 # add some flows
589 req = ofp.FlowTableUpdate(
590 id=id,
591 flow_mod=mk_simple_flow_mod(
592 cookie=randint(1, 10000000000),
593 priority=len_before,
594 match_fields=[
595 in_port(129)
596 ],
597 actions=[
598 output(1)
599 ]
600 )
601 )
602 res = self.post('/api/v1/logical_devices/{}/flows'.format(id),
603 MessageToDict(req, preserving_proto_field_name=True),
Stephane Barbariecd51f992017-09-07 16:37:02 -0400604 expected_http_code=200)
khenaidoo08d48d22017-06-29 19:42:49 -0400605 # TODO check some stuff on res
606
607 res = self.get('/api/v1/logical_devices/{}/flows'.format(id))
608 len_after = len(res['items'])
609 self.assertGreater(len_after, len_before)
610
khenaidood3c335e2017-07-05 16:36:59 -0400611 def _list_and_update_logical_device_flow_groups_rest(self, id):
khenaidoo08d48d22017-06-29 19:42:49 -0400612
613 # retrieve flow list
614 res = self.get('/api/v1/logical_devices/{}/flow_groups'.format(id))
615 len_before = len(res['items'])
616
617 # add some flows
618 req = ofp.FlowGroupTableUpdate(
619 id=id,
620 group_mod=ofp.ofp_group_mod(
621 command=ofp.OFPGC_ADD,
622 type=ofp.OFPGT_ALL,
623 group_id=len_before + 1,
624 buckets=[
625 ofp.ofp_bucket(
626 actions=[
627 ofp.ofp_action(
628 type=ofp.OFPAT_OUTPUT,
629 output=ofp.ofp_action_output(
630 port=1
631 )
632 )
633 ]
634 )
635 ]
636 )
637 )
638 res = self.post('/api/v1/logical_devices/{}/flow_groups'.format(id),
639 MessageToDict(req, preserving_proto_field_name=True),
Stephane Barbariecd51f992017-09-07 16:37:02 -0400640 expected_http_code=200)
khenaidoo08d48d22017-06-29 19:42:49 -0400641 # TODO check some stuff on res
642
643 res = self.get('/api/v1/logical_devices/{}/flow_groups'.format(id))
644 len_after = len(res['items'])
645 self.assertGreater(len_after, len_before)
646
khenaidood3c335e2017-07-05 16:36:59 -0400647 def _list_devices_rest(self, count=2):
khenaidoo08d48d22017-06-29 19:42:49 -0400648 res = self.get('/api/v1/devices')
khenaidood3c335e2017-07-05 16:36:59 -0400649 self.assertGreaterEqual(len(res['items']), count)
khenaidoo08d48d22017-06-29 19:42:49 -0400650 return res
651
khenaidood3c335e2017-07-05 16:36:59 -0400652 def _get_device_rest(self, id):
khenaidoo08d48d22017-06-29 19:42:49 -0400653 res = self.get('/api/v1/devices/{}'.format(id))
654 # TODO test result
655
khenaidood3c335e2017-07-05 16:36:59 -0400656 def _list_device_ports_rest(self, id, count=2):
khenaidoo08d48d22017-06-29 19:42:49 -0400657 res = self.get('/api/v1/devices/{}/ports'.format(id))
khenaidood3c335e2017-07-05 16:36:59 -0400658 self.assertGreaterEqual(len(res['items']), count)
khenaidoo08d48d22017-06-29 19:42:49 -0400659
khenaidood3c335e2017-07-05 16:36:59 -0400660 def _list_device_flows_rest(self, id, count=1):
khenaidoo08d48d22017-06-29 19:42:49 -0400661 # pump some flows into the logical device
662 res = self.get('/api/v1/devices/{}/flows'.format(id))
khenaidood3c335e2017-07-05 16:36:59 -0400663 self.assertGreaterEqual(len(res['items']), count)
khenaidoo08d48d22017-06-29 19:42:49 -0400664
khenaidood3c335e2017-07-05 16:36:59 -0400665 def _list_device_flow_groups_rest(self, id, count=0):
khenaidoo08d48d22017-06-29 19:42:49 -0400666 res = self.get('/api/v1/devices/{}/flow_groups'.format(id))
khenaidood3c335e2017-07-05 16:36:59 -0400667 self.assertGreaterEqual(len(res['items']), count)
khenaidoo08d48d22017-06-29 19:42:49 -0400668
khenaidood3c335e2017-07-05 16:36:59 -0400669 def _list_device_types_rest(self, count=2):
khenaidoo08d48d22017-06-29 19:42:49 -0400670 res = self.get('/api/v1/device_types')
khenaidood3c335e2017-07-05 16:36:59 -0400671 self.assertGreaterEqual(len(res['items']), count)
khenaidoo08d48d22017-06-29 19:42:49 -0400672 return res
673
khenaidood3c335e2017-07-05 16:36:59 -0400674 def _get_device_type_rest(self, dtype):
khenaidoo08d48d22017-06-29 19:42:49 -0400675 res = self.get('/api/v1/device_types/{}'.format(dtype))
676 self.assertIsNotNone(res)
677 # TODO test the result
678
679 def _list_device_groups(self):
680 pass
681 # res = self.get('/api/v1/device_groups')
682 # self.assertGreaterEqual(len(res['items']), 1)
683
684 def _get_device_group(self):
685 pass
686 # res = self.get('/api/v1/device_groups/1')
687 # # TODO test the result
688
khenaidood3c335e2017-07-05 16:36:59 -0400689 def _get_images_rest(self, id):
khenaidoo08d48d22017-06-29 19:42:49 -0400690 res = self.get('/api/v1/devices/{}/images'.format(id))
691 self.assertIsNotNone(res)
692
khenaidood3c335e2017-07-05 16:36:59 -0400693 def _self_test_rest(self, id):
khenaidoo08d48d22017-06-29 19:42:49 -0400694 res = self.post('/api/v1/devices/{}/self_test'.format(id),
Stephane Barbariecd51f992017-09-07 16:37:02 -0400695 expected_http_code=200)
khenaidoo08d48d22017-06-29 19:42:49 -0400696 self.assertIsNotNone(res)
697
khenaidood3c335e2017-07-05 16:36:59 -0400698 def _create_device_filter_rest(self, device_id):
khenaidoo08d48d22017-06-29 19:42:49 -0400699 rules = list()
700 rule = dict()
701
702 # Create a filter with a single rule
703 rule['key'] = 'device_id'
704 rule['value'] = device_id
705 rules.append(rule)
706
707 alarm_filter = AlarmFilter(rules=rules)
708 alarm_filter = self.post('/api/v1/alarm_filters',
709 MessageToDict(alarm_filter),
Stephane Barbariecd51f992017-09-07 16:37:02 -0400710 expected_http_code=200)
khenaidoo08d48d22017-06-29 19:42:49 -0400711 self.assertIsNotNone(alarm_filter)
712 return alarm_filter
713
khenaidood3c335e2017-07-05 16:36:59 -0400714 def _remove_device_filter_rest(self, alarm_filter_id):
khenaidoo08d48d22017-06-29 19:42:49 -0400715 path = '/api/v1/alarm_filters/{}'.format(alarm_filter_id)
Stephane Barbariecd51f992017-09-07 16:37:02 -0400716 self.delete(path, expected_http_code=200)
717 alarm_filter = self.get(path, expected_http_code=200, grpc_status=5)
khenaidoo08d48d22017-06-29 19:42:49 -0400718 self.assertIsNone(alarm_filter)
719
khenaidood3c335e2017-07-05 16:36:59 -0400720 def _get_alarm_filter_grpc(self, stub, alarm_filter_id):
721 res = stub.GetAlarmFilter(voltha_pb2.ID(id=alarm_filter_id))
722 return res
723
724 def _get_alarm_filters_grpc(self, stub):
725 res = stub.ListAlarmFilters(Empty())
726 return res
727
728 def _get_alarm_filters_rest(self):
729 res = self.get('/api/v1/alarm_filters')
730 return res
731
732 def _install_eapol_flow_grpc(self, stub, logical_device_id):
733 """
734 Install an EAPOL flow on the given logical device. If device is not
735 given, it will be applied to logical device of the last pre-provisioned
736 OLT device.
737 """
738
739 # gather NNI and UNI port IDs
740 nni_port_no, unis = self._get_logical_ports(stub, logical_device_id)
741
742 # construct and push flow rule
743 for uni_port_no, _ in unis:
744 update = FlowTableUpdate(
745 id=logical_device_id,
746 flow_mod=mk_simple_flow_mod(
747 priority=2000,
748 match_fields=[in_port(uni_port_no), eth_type(0x888e)],
749 actions=[
750 # push_vlan(0x8100),
751 # set_field(vlan_vid(4096 + 4000)),
752 output(ofp.OFPP_CONTROLLER)
753 ]
754 )
755 )
756 res = stub.UpdateLogicalDeviceFlowTable(update)
757 self.pt('success for uni {} ({})'.format(uni_port_no, res))
758
759 def _get_logical_ports(self, stub, logical_device_id):
760 """
761 Return the NNI port number and the first usable UNI port of logical
762 device, and the vlan associated with the latter.
763 """
764 ports = stub.ListLogicalDevicePorts(
765 voltha_pb2.ID(id=logical_device_id)).items
766 nni = None
767 unis = []
768 for port in ports:
769 if port.root_port:
770 assert nni is None, "There shall be only one root port"
771 nni = port.ofp_port.port_no
772 else:
773 uni = port.ofp_port.port_no
774 uni_device = self._get_device_grpc(stub, port.device_id)
775 vlan = uni_device.vlan
776 unis.append((uni, vlan))
777
778 assert nni is not None, "No NNI port found"
779 assert unis, "Not a single UNI?"
780
781 return nni, unis
782
783 def _get_device_grpc(self, stub, device_id, depth=0):
784 res = stub.GetDevice(voltha_pb2.ID(id=device_id),
785 metadata=(('get-depth', str(depth)),))
786 return res
787
788 def _verify_olt_eapol_flow_rest(self, logical_device_id):
789 flows = self.get('/api/v1/devices/{}/flows'.format(logical_device_id))[
790 'items']
791 self.assertEqual(len(flows), 2)
792 flow = flows[1]
793 self.assertEqual(flow['table_id'], 0)
794 self.assertEqual(flow['priority'], 2000)
795
796
797 def _get_olt_flows_grpc(self, stub, logical_device_id):
798 res = stub.ListLogicalDeviceFlows(voltha_pb2.ID(id=logical_device_id))
799 return res
800
Rachit Shrivastavaa182e912017-07-28 15:18:34 -0400801 #For xPON objects
802 def _get_path(self, type, name, operation, device_id=None):
803 if(type == 'channel_terminations'):
804 return '/api/v1/devices/{}/{}/{}{}'.format(device_id, type, name,
805 operation)
806 return '/api/v1/{}/{}{}'.format(type, name, operation)
807
808 def _get_xpon_object_rest(self, obj_type, device_id=None):
809 if obj_type["type"] == "channel_terminations":
810 res = self.get('/api/v1/devices/{}/{}'.format(device_id,
811 obj_type["type"]))
812 else:
813 res = self.get('/api/v1/{}'.format(obj_type["type"]))
Rachit Shrivastava8f4f9bf2017-07-20 11:59:30 -0400814 return res
815
Rachit Shrivastavaa182e912017-07-28 15:18:34 -0400816 def _get_xpon_object_grpc(self, stub, obj_type, device_id=None):
817 if obj_type["type"] == "channel_groups":
818 res = stub.GetAllChannelgroupConfig(Empty())
819 elif obj_type["type"] == "channel_partitions":
820 res = stub.GetAllChannelpartitionConfig(Empty())
821 elif obj_type["type"] == "channel_pairs":
822 res = stub.GetAllChannelpairConfig(Empty())
823 elif obj_type["type"] == "channel_terminations":
824 res = stub.GetAllChannelterminationConfig(
825 voltha_pb2.ID(id=device_id))
826 elif obj_type["type"] == "v_ont_anis":
827 res = stub.GetAllVOntaniConfig(Empty())
828 elif obj_type["type"] == "ont_anis":
829 res = stub.GetAllOntaniConfig(Empty())
830 elif obj_type["type"] == "v_enets":
831 res = stub.GetAllVEnetConfig(Empty())
Rachit Shrivastava8f4f9bf2017-07-20 11:59:30 -0400832 return res
833
Rachit Shrivastavaa182e912017-07-28 15:18:34 -0400834 def _create_xpon_object_rest(self, obj_type, value, device_id=None):
Rachit Shrivastava8f4f9bf2017-07-20 11:59:30 -0400835 ParseDict(value['rpc'], value['pb2'])
836 request = value['pb2']
Rachit Shrivastavaa182e912017-07-28 15:18:34 -0400837 self.post(self._get_path(obj_type["type"], value['rpc']['name'], "",
838 device_id),
Rachit Shrivastava8f4f9bf2017-07-20 11:59:30 -0400839 MessageToDict(request, preserving_proto_field_name = True),
Stephane Barbariecd51f992017-09-07 16:37:02 -0400840 expected_http_code = 200)
Rachit Shrivastava8f4f9bf2017-07-20 11:59:30 -0400841 return request
842
Rachit Shrivastavaa182e912017-07-28 15:18:34 -0400843 def _delete_xpon_object_rest(self, obj_type, value, device_id=None):
844 self.delete(self._get_path(obj_type["type"], value['rpc']['name'],
Stephane Barbariecd51f992017-09-07 16:37:02 -0400845 "/delete", device_id), expected_http_code = 200)
Rachit Shrivastavaa182e912017-07-28 15:18:34 -0400846
847 def _verify_xpon_object_on_device(self, type_config, stub, device_id=None):
848 global_xpon_obj = self._get_xpon_object_rest(type_config, device_id)
849 xpon_obj = self._get_xpon_object_grpc(stub, type_config, device_id)
850 assert global_xpon_obj == MessageToDict(xpon_obj,
851 including_default_value_fields = True,
852 preserving_proto_field_name = True)
khenaidoo08d48d22017-06-29 19:42:49 -0400853
854if __name__ == '__main__':
855 main()