blob: 9dd350b340f5aa0bf1f84409bd41866d0e53a28e [file] [log] [blame]
Zsolt Haraszti66862032016-11-28 14:28:39 -08001from time import time, sleep
2
3from google.protobuf.json_format import MessageToDict
4
5from voltha.core.flow_decomposer import *
6from voltha.protos.device_pb2 import Device
7from voltha.protos.common_pb2 import AdminState, OperStatus
8from voltha.protos import openflow_13_pb2 as ofp
9from tests.itests.voltha.rest_base import RestBase
khenaidoob96ee0a2017-06-28 15:39:16 -040010from common.utils.consulhelpers import get_endpoint_from_consul
Richard Jankowski9ac4bbd2018-03-21 11:31:02 -040011from structlog import get_logger
Richard Jankowski8f52afb2018-03-29 14:19:11 -040012from tests.itests.test_utils import get_pod_ip
Richard Jankowski9ac4bbd2018-03-21 11:31:02 -040013from testconfig import config
Zsolt Haraszti66862032016-11-28 14:28:39 -080014
khenaidoob96ee0a2017-06-28 15:39:16 -040015LOCAL_CONSUL = "localhost:8500"
Zsolt Haraszti66862032016-11-28 14:28:39 -080016
Richard Jankowski9ac4bbd2018-03-21 11:31:02 -040017log = get_logger()
18
19orch_env = 'docker-compose'
20if 'test_parameters' in config and 'orch_env' in config['test_parameters']:
21 orch_env = config['test_parameters']['orch_env']
22log.debug('orchestration-environment', orch_env=orch_env)
23
Zsolt Haraszti66862032016-11-28 14:28:39 -080024class TestColdActivationSequence(RestBase):
25
khenaidoob96ee0a2017-06-28 15:39:16 -040026 # Retrieve details of the REST entry point
Richard Jankowski9ac4bbd2018-03-21 11:31:02 -040027 if orch_env == 'k8s-single-node':
28 rest_endpoint = get_pod_ip('voltha') + ':8443'
29 elif orch_env == 'swarm-single-node':
30 rest_endpoint = 'localhost:8443'
31 else:
32 rest_endpoint = get_endpoint_from_consul(LOCAL_CONSUL, 'voltha-envoy-8443')
khenaidoob96ee0a2017-06-28 15:39:16 -040033
34 # Construct the base_url
ubuntuc5c83d72017-07-01 17:57:19 -070035 base_url = 'https://' + rest_endpoint
Richard Jankowski9ac4bbd2018-03-21 11:31:02 -040036 log.debug('cold-activation-test', base_url=base_url)
khenaidoob96ee0a2017-06-28 15:39:16 -040037
Zsolt Haraszti66862032016-11-28 14:28:39 -080038 def wait_till(self, msg, predicate, interval=0.1, timeout=5.0):
39 deadline = time() + timeout
40 while time() < deadline:
41 if predicate():
42 return
43 sleep(interval)
44 self.fail('Timed out while waiting for condition: {}'.format(msg))
45
46 def test_cold_activation_sequence(self):
47 """Complex test-case to cover device activation sequence"""
48
49 self.verify_prerequisites()
50 olt_id = self.add_olt_device()
51 self.verify_device_preprovisioned_state(olt_id)
52 self.activate_device(olt_id)
53 ldev_id = self.wait_for_logical_device(olt_id)
54 onu_ids = self.wait_for_onu_discovery(olt_id)
55 self.verify_logical_ports(ldev_id)
56 self.simulate_eapol_flow_install(ldev_id, olt_id, onu_ids)
57 self.verify_olt_eapol_flow(olt_id)
58 self.verify_onu_forwarding_flows(onu_ids)
59 self.simulate_eapol_start()
60 self.simulate_eapol_request_identity()
61 self.simulate_eapol_response_identity()
62 self.simulate_eapol_request()
63 self.simulate_eapol_response()
64 self.simulate_eapol_success()
65 self.install_and_verify_dhcp_flows()
66 self.install_and_verify_igmp_flows()
67 self.install_and_verifyunicast_flows()
68
69 def verify_prerequisites(self):
70 # all we care is that Voltha is available via REST using the base uri
71 self.get('/api/v1')
72
73 def add_olt_device(self):
74 device = Device(
75 type='simulated_olt',
76 mac_address='00:00:00:00:00:01'
77 )
78 device = self.post('/api/v1/devices', MessageToDict(device),
Stephane Barbariecd51f992017-09-07 16:37:02 -040079 expected_http_code=200)
Zsolt Haraszti66862032016-11-28 14:28:39 -080080 return device['id']
81
82 def verify_device_preprovisioned_state(self, olt_id):
83 # we also check that so far what we read back is same as what we get
84 # back on create
85 device = self.get('/api/v1/devices/{}'.format(olt_id))
86 self.assertNotEqual(device['id'], '')
87 self.assertEqual(device['adapter'], 'simulated_olt')
88 self.assertEqual(device['admin_state'], 'PREPROVISIONED')
89 self.assertEqual(device['oper_status'], 'UNKNOWN')
90
91 def activate_device(self, olt_id):
92 path = '/api/v1/devices/{}'.format(olt_id)
Stephane Barbariecd51f992017-09-07 16:37:02 -040093 self.post(path + '/enable', expected_http_code=200)
Zsolt Haraszti66862032016-11-28 14:28:39 -080094 device = self.get(path)
95 self.assertEqual(device['admin_state'], 'ENABLED')
96
97 self.wait_till(
98 'admin state moves to ACTIVATING or ACTIVE',
99 lambda: self.get(path)['oper_status'] in ('ACTIVATING', 'ACTIVE'),
100 timeout=0.5)
101
102 # eventually, it shall move to active state and by then we shall have
103 # device details filled, connect_state set, and device ports created
104 self.wait_till(
105 'admin state ACTIVE',
106 lambda: self.get(path)['oper_status'] == 'ACTIVE',
107 timeout=0.5)
108 device = self.get(path)
ggowdru236bd952017-06-20 20:32:55 -0700109 images = device['images']
110 image = images['image']
111 image_1 = image[0]
112 version = image_1['version']
113 self.assertNotEqual(version, '')
Zsolt Haraszti66862032016-11-28 14:28:39 -0800114 self.assertEqual(device['connect_status'], 'REACHABLE')
115
116 ports = self.get(path + '/ports')['items']
117 self.assertEqual(len(ports), 2)
118
119 def wait_for_logical_device(self, olt_id):
120 # we shall find the logical device id from the parent_id of the olt
121 # (root) device
122 device = self.get(
123 '/api/v1/devices/{}'.format(olt_id))
124 self.assertNotEqual(device['parent_id'], '')
125 logical_device = self.get(
126 '/api/v1/logical_devices/{}'.format(device['parent_id']))
127
128 # the logical device shall be linked back to the hard device,
129 # its ports too
130 self.assertEqual(logical_device['root_device_id'], device['id'])
131
132 logical_ports = self.get(
133 '/api/v1/logical_devices/{}/ports'.format(
134 logical_device['id'])
135 )['items']
136 self.assertGreaterEqual(len(logical_ports), 1)
137 logical_port = logical_ports[0]
138 self.assertEqual(logical_port['id'], 'nni')
139 self.assertEqual(logical_port['ofp_port']['name'], 'nni')
140 self.assertEqual(logical_port['ofp_port']['port_no'], 129)
141 self.assertEqual(logical_port['device_id'], device['id'])
142 self.assertEqual(logical_port['device_port_no'], 2)
143 return logical_device['id']
144
145 def wait_for_onu_discovery(self, olt_id):
146 # shortly after we shall see the discovery of four new onus, linked to
147 # the olt device
148 def find_our_onus():
149 devices = self.get('/api/v1/devices')['items']
150 return [
151 d for d in devices
152 if d['parent_id'] == olt_id
153 ]
154 self.wait_till(
khenaidoob96ee0a2017-06-28 15:39:16 -0400155 'find ONUs linked to the olt device',
156 lambda: len(find_our_onus()) >= 1,
Zsolt Haraszti66862032016-11-28 14:28:39 -0800157 2
158 )
159
160 # verify that they are properly set
161 onus = find_our_onus()
162 for onu in onus:
163 self.assertEqual(onu['admin_state'], 'ENABLED')
164 self.assertEqual(onu['oper_status'], 'ACTIVE')
165
166 return [onu['id'] for onu in onus]
167
168 def verify_logical_ports(self, ldev_id):
169
170 # at this point we shall see at least 5 logical ports on the
171 # logical device
172 logical_ports = self.get(
173 '/api/v1/logical_devices/{}/ports'.format(ldev_id)
174 )['items']
175 self.assertGreaterEqual(len(logical_ports), 5)
176
177 # verify that all logical ports are LIVE (state=4)
178 for lport in logical_ports:
179 self.assertEqual(lport['ofp_port']['state'], 4)
180
181 def simulate_eapol_flow_install(self, ldev_id, olt_id, onu_ids):
182
183 # emulate the flow mod requests that shall arrive from the SDN
184 # controller, one for each ONU
185 lports = self.get(
186 '/api/v1/logical_devices/{}/ports'.format(ldev_id)
187 )['items']
188
189 # device_id -> logical port map, which we will use to construct
190 # our flows
191 lport_map = dict((lp['device_id'], lp) for lp in lports)
192 for onu_id in onu_ids:
193 # if eth_type == 0x888e => send to controller
194 _in_port = lport_map[onu_id]['ofp_port']['port_no']
195 req = ofp.FlowTableUpdate(
Stephane Barbariecd51f992017-09-07 16:37:02 -0400196 id=ldev_id,
Zsolt Haraszti66862032016-11-28 14:28:39 -0800197 flow_mod=mk_simple_flow_mod(
198 match_fields=[
199 in_port(_in_port),
200 vlan_vid(ofp.OFPVID_PRESENT | 0),
201 eth_type(0x888e)],
202 actions=[
203 output(ofp.OFPP_CONTROLLER)
204 ],
205 priority=1000
206 )
207 )
208 res = self.post('/api/v1/logical_devices/{}/flows'.format(ldev_id),
209 MessageToDict(req,
210 preserving_proto_field_name=True),
Stephane Barbariecd51f992017-09-07 16:37:02 -0400211 expected_http_code=200)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800212
213 # for sanity, verify that flows are in flow table of logical device
214 flows = self.get(
215 '/api/v1/logical_devices/{}/flows'.format(ldev_id))['items']
216 self.assertGreaterEqual(len(flows), 4)
217
218 def verify_olt_eapol_flow(self, olt_id):
Zsolt Haraszti66862032016-11-28 14:28:39 -0800219 flows = self.get('/api/v1/devices/{}/flows'.format(olt_id))['items']
Richard Jankowski9ac4bbd2018-03-21 11:31:02 -0400220 self.assertEqual(len(flows), 8)
Zsolt Haraszti66862032016-11-28 14:28:39 -0800221 flow = flows[1]
222 self.assertEqual(flow['table_id'], 0)
223 self.assertEqual(flow['priority'], 1000)
224
225 # TODO refine this
226 # self.assertEqual(flow['match'], {})
227 # self.assertEqual(flow['instructions'], [])
228
229 def verify_onu_forwarding_flows(self, onu_ids):
230 pass
231
232 def simulate_eapol_start(self):
233 pass
234
235 def simulate_eapol_request_identity(self):
236 pass
237
238 def simulate_eapol_response_identity(self):
239 pass
240
241 def simulate_eapol_request(self):
242 pass
243
244 def simulate_eapol_response(self):
245 pass
246
247 def simulate_eapol_success(self):
248 pass
249
250 def install_and_verify_dhcp_flows(self):
251 pass
252
253 def install_and_verify_igmp_flows(self):
254 pass
255
256 def install_and_verifyunicast_flows(self):
257 pass
258