Newer
Older
# Copyright 2021-2023 H2020 TeraFlow (https://www.teraflow-h2020.eu/)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from common.proto.context_pb2 import Context, ContextId, DeviceId, Link, LinkId, Topology, Device, TopologyId
from common.proto.pathcomp_pb2 import PathCompRequest
from common.tools.grpc.Tools import grpc_message_to_json
from common.tools.object_factory.Constraint import (
json_constraint_custom, json_constraint_endpoint_location_region, json_constraint_endpoint_priority,
json_constraint_sla_availability)
from common.tools.object_factory.Device import json_device_id
from common.tools.object_factory.EndPoint import json_endpoint_id
from common.tools.object_factory.Service import json_service_l3nm_planned
from context.client.ContextClient import ContextClient
from device.client.DeviceClient import DeviceClient
from pathcomp.frontend.client.PathCompClient import PathCompClient
# Scenarios:
#from .Objects_A_B_C import CONTEXTS, DEVICES, LINKS, OBJECTS_PER_TOPOLOGY, SERVICES, TOPOLOGIES
#from .Objects_DC_CSGW_TN import CONTEXTS, DEVICES, LINKS, OBJECTS_PER_TOPOLOGY, SERVICES, TOPOLOGIES
from .Objects_DC_CSGW_TN_OLS import CONTEXTS, DEVICES, LINKS, OBJECTS_PER_TOPOLOGY, SERVICES, TOPOLOGIES
# configure backend environment variables before overwriting them with fixtures to use real backend pathcomp
DEFAULT_PATHCOMP_BACKEND_SCHEME = 'http'
DEFAULT_PATHCOMP_BACKEND_HOST = '127.0.0.1'
DEFAULT_PATHCOMP_BACKEND_PORT = '8081'
DEFAULT_PATHCOMP_BACKEND_BASEURL = '/pathComp/api/v1/compRoute'
os.environ['PATHCOMP_BACKEND_SCHEME'] = os.environ.get('PATHCOMP_BACKEND_SCHEME', DEFAULT_PATHCOMP_BACKEND_SCHEME)
os.environ['PATHCOMP_BACKEND_BASEURL'] = os.environ.get('PATHCOMP_BACKEND_BASEURL', DEFAULT_PATHCOMP_BACKEND_BASEURL)
# Find IP:port of backend container as follows:
# - first check env vars PATHCOMP_BACKEND_HOST & PATHCOMP_BACKEND_PORT
# - if not set, check env vars PATHCOMPSERVICE_SERVICE_HOST & PATHCOMPSERVICE_SERVICE_PORT_HTTP
# - if not set, use DEFAULT_PATHCOMP_BACKEND_HOST & DEFAULT_PATHCOMP_BACKEND_PORT
backend_host = DEFAULT_PATHCOMP_BACKEND_HOST
backend_host = os.environ.get('PATHCOMPSERVICE_SERVICE_HOST', backend_host)
os.environ['PATHCOMP_BACKEND_HOST'] = os.environ.get('PATHCOMP_BACKEND_HOST', backend_host)
backend_port = DEFAULT_PATHCOMP_BACKEND_PORT
backend_port = os.environ.get('PATHCOMPSERVICE_SERVICE_PORT_HTTP', backend_port)
os.environ['PATHCOMP_BACKEND_PORT'] = os.environ.get('PATHCOMP_BACKEND_PORT', backend_port)
from .PrepareTestScenario import ( # pylint: disable=unused-import
# be careful, order of symbols is important here!
mock_service, pathcomp_service, context_client, pathcomp_client)
LOGGER = logging.getLogger(__name__)
LOGGER.setLevel(logging.DEBUG)
context_client : ContextClient): # pylint: disable=redefined-outer-name
for context in CONTEXTS : context_client.SetContext (Context (**context ))
for topology in TOPOLOGIES: context_client.SetTopology(Topology(**topology))
for device in DEVICES : context_client.SetDevice (Device (**device ))
for link in LINKS : context_client.SetLink (Link (**link ))
for topology_id, device_ids, link_ids in OBJECTS_PER_TOPOLOGY:
topology = Topology()
topology.CopyFrom(context_client.GetTopology(TopologyId(**topology_id)))
device_ids_in_topology = {device_id.device_uuid.uuid for device_id in topology.device_ids}
func_device_id_not_added = lambda device_id: device_id['device_uuid']['uuid'] not in device_ids_in_topology
func_device_id_json_to_grpc = lambda device_id: DeviceId(**device_id)
device_ids_to_add = list(map(func_device_id_json_to_grpc, filter(func_device_id_not_added, device_ids)))
topology.device_ids.extend(device_ids_to_add)
link_ids_in_topology = {link_id.link_uuid.uuid for link_id in topology.link_ids}
func_link_id_not_added = lambda link_id: link_id['link_uuid']['uuid'] not in link_ids_in_topology
func_link_id_json_to_grpc = lambda link_id: LinkId(**link_id)
link_ids_to_add = list(map(func_link_id_json_to_grpc, filter(func_link_id_not_added, link_ids)))
topology.link_ids.extend(link_ids_to_add)
context_client.SetTopology(topology)
def test_request_service_shortestpath(
pathcomp_client : PathCompClient): # pylint: disable=redefined-outer-name
request_services = copy.deepcopy(SERVICES)
#request_services[0]['service_constraints'] = [
# json_constraint_custom('bandwidth[gbps]', 1000.0),
# json_constraint_custom('latency[ms]', 1200.0),
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
pathcomp_request = PathCompRequest(services=request_services)
pathcomp_request.shortest_path.Clear() # hack to select the shortest path algorithm that has no attributes
pathcomp_reply = pathcomp_client.Compute(pathcomp_request)
pathcomp_reply = grpc_message_to_json(pathcomp_reply)
reply_services = pathcomp_reply['services']
reply_connections = pathcomp_reply['connections']
assert len(request_services) <= len(reply_services)
request_service_ids = {
'{:s}/{:s}'.format(
svc['service_id']['context_id']['context_uuid']['uuid'],
svc['service_id']['service_uuid']['uuid']
)
for svc in request_services
}
reply_service_ids = {
'{:s}/{:s}'.format(
svc['service_id']['context_id']['context_uuid']['uuid'],
svc['service_id']['service_uuid']['uuid']
)
for svc in reply_services
}
# Assert all requested services have a reply
# It permits having other services not requested (i.e., sub-services)
assert len(request_service_ids.difference(reply_service_ids)) == 0
reply_connection_service_ids = {
'{:s}/{:s}'.format(
conn['service_id']['context_id']['context_uuid']['uuid'],
conn['service_id']['service_uuid']['uuid']
)
for conn in reply_connections
}
# Assert all requested services have a connection associated
# It permits having other connections not requested (i.e., connections for sub-services)
assert len(request_service_ids.difference(reply_connection_service_ids)) == 0
# TODO: implement other checks. examples:
# - request service and reply service endpoints match
# - request service and reply connection endpoints match
# - reply sub-service and reply sub-connection endpoints match
# - others?
#for json_service,json_connection in zip(json_services, json_connections):
def test_request_service_kshortestpath(
pathcomp_client : PathCompClient): # pylint: disable=redefined-outer-name
request_services = SERVICES
pathcomp_request = PathCompRequest(services=request_services)
pathcomp_request.k_shortest_path.k_inspection = 2 #pylint: disable=no-member
pathcomp_request.k_shortest_path.k_return = 2 #pylint: disable=no-member
pathcomp_reply = pathcomp_client.Compute(pathcomp_request)
pathcomp_reply = grpc_message_to_json(pathcomp_reply)
reply_services = pathcomp_reply['services']
reply_connections = pathcomp_reply['connections']
assert len(request_services) <= len(reply_services)
request_service_ids = {
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
'{:s}/{:s}'.format(
svc['service_id']['context_id']['context_uuid']['uuid'],
svc['service_id']['service_uuid']['uuid']
)
for svc in request_services
}
reply_service_ids = {
'{:s}/{:s}'.format(
svc['service_id']['context_id']['context_uuid']['uuid'],
svc['service_id']['service_uuid']['uuid']
)
for svc in reply_services
}
# Assert all requested services have a reply
# It permits having other services not requested (i.e., sub-services)
assert len(request_service_ids.difference(reply_service_ids)) == 0
reply_connection_service_ids = {
'{:s}/{:s}'.format(
conn['service_id']['context_id']['context_uuid']['uuid'],
conn['service_id']['service_uuid']['uuid']
)
for conn in reply_connections
}
# Assert all requested services have a connection associated
# It permits having other connections not requested (i.e., connections for sub-services)
assert len(request_service_ids.difference(reply_connection_service_ids)) == 0
# TODO: implement other checks. examples:
# - request service and reply service endpoints match
# - request service and reply connection endpoints match
# - reply sub-service and reply sub-connection endpoints match
# - others?
#for json_service,json_connection in zip(json_services, json_connections):
def test_request_service_kdisjointpath(
pathcomp_client : PathCompClient): # pylint: disable=redefined-outer-name
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
service_uuid = 'DC1-DC2'
raw_endpoints = [
('CS1-GW1', '10/1', 'DC1', 10),
('CS1-GW2', '10/1', 'DC1', 20),
('CS2-GW1', '10/1', 'DC2', 10),
('CS2-GW2', '10/1', 'DC2', 20),
]
endpoint_ids, constraints = [], [
json_constraint_custom('bandwidth[gbps]', 10.0),
json_constraint_custom('latency[ms]', 12.0),
json_constraint_sla_availability(2, True),
json_constraint_custom('diversity', {'end-to-end-diverse': 'all-other-accesses'}),
]
for device_uuid, endpoint_uuid, region, priority in raw_endpoints:
device_id = json_device_id(device_uuid)
endpoint_id = json_endpoint_id(device_id, endpoint_uuid)
endpoint_ids.append(endpoint_id)
constraints.extend([
json_constraint_endpoint_location_region(endpoint_id, region),
json_constraint_endpoint_priority(endpoint_id, priority),
])
service = json_service_l3nm_planned(service_uuid, endpoint_ids=endpoint_ids, constraints=constraints)
request_services = [service]
pathcomp_request = PathCompRequest(services=request_services)
pathcomp_request.k_disjoint_path.num_disjoint = 2 #pylint: disable=no-member
pathcomp_reply = pathcomp_client.Compute(pathcomp_request)
pathcomp_reply = grpc_message_to_json(pathcomp_reply)
reply_services = pathcomp_reply['services']
reply_connections = pathcomp_reply['connections']
assert len(request_services) <= len(reply_services)
request_service_ids = {
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
'{:s}/{:s}'.format(
svc['service_id']['context_id']['context_uuid']['uuid'],
svc['service_id']['service_uuid']['uuid']
)
for svc in request_services
}
reply_service_ids = {
'{:s}/{:s}'.format(
svc['service_id']['context_id']['context_uuid']['uuid'],
svc['service_id']['service_uuid']['uuid']
)
for svc in reply_services
}
# Assert all requested services have a reply
# It permits having other services not requested (i.e., sub-services)
assert len(request_service_ids.difference(reply_service_ids)) == 0
reply_connection_service_ids = {
'{:s}/{:s}'.format(
conn['service_id']['context_id']['context_uuid']['uuid'],
conn['service_id']['service_uuid']['uuid']
)
for conn in reply_connections
}
# Assert all requested services have a connection associated
# It permits having other connections not requested (i.e., connections for sub-services)
assert len(request_service_ids.difference(reply_connection_service_ids)) == 0
# TODO: implement other checks. examples:
# - request service and reply service endpoints match
# - request service and reply connection endpoints match
# - reply sub-service and reply sub-connection endpoints match
# - others?
#for json_service,json_connection in zip(json_services, json_connections):
def test_cleanup_environment(
context_client : ContextClient): # pylint: disable=redefined-outer-name
for link in LINKS : context_client.RemoveLink (LinkId (**link ['link_id' ]))
for device in DEVICES : context_client.RemoveDevice (DeviceId (**device ['device_id' ]))
for topology in TOPOLOGIES: context_client.RemoveTopology(TopologyId(**topology['topology_id']))
for context in CONTEXTS : context_client.RemoveContext (ContextId (**context ['context_id' ]))