Loading src/compute/service/rest_server/nbi_plugins/ietf_l2vpn/L2VPN_Service.py +26 −16 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ from common.Constants import DEFAULT_CONTEXT_UUID from common.proto.context_pb2 import ServiceId, ServiceStatusEnum, SliceStatusEnum from context.client.ContextClient import ContextClient from service.client.ServiceClient import ServiceClient from slice.client.SliceClient import SliceClient from .tools.Authentication import HTTP_AUTH from .tools.ContextMethods import get_service, get_slice from .tools.HttpStatusCodes import HTTP_GATEWAYTIMEOUT, HTTP_NOCONTENT, HTTP_OK, HTTP_SERVERERROR Loading @@ -32,11 +33,6 @@ class L2VPN_Service(Resource): LOGGER.debug('VPN_Id: {:s}'.format(str(vpn_id))) LOGGER.debug('Request: {:s}'.format(str(request))) # TODO: HACK ECOC'22, to be corrected response = jsonify({}) response.status_code = HTTP_OK return response try: context_client = ContextClient() Loading @@ -60,7 +56,7 @@ class L2VPN_Service(Resource): raise Exception('VPN({:s}) not found in database'.format(str(vpn_id))) except Exception as e: # pylint: disable=broad-except LOGGER.exception('Something went wrong Retrieving VPN({:s})'.format(str(request))) LOGGER.exception('Something went wrong Retrieving VPN({:s})'.format(str(vpn_id))) response = jsonify({'error': str(e)}) response.status_code = HTTP_SERVERERROR return response Loading @@ -70,18 +66,32 @@ class L2VPN_Service(Resource): LOGGER.debug('VPN_Id: {:s}'.format(str(vpn_id))) LOGGER.debug('Request: {:s}'.format(str(request))) # pylint: disable=no-member service_id_request = ServiceId() service_id_request.context_id.context_uuid.uuid = DEFAULT_CONTEXT_UUID service_id_request.service_uuid.uuid = vpn_id try: context_client = ContextClient() target = get_service(context_client, vpn_id) if target is not None: if target.service_id.service_uuid.uuid != vpn_id: # pylint: disable=no-member raise Exception('Service retrieval failed. Wrong Service Id was returned') service_client = ServiceClient() service_client.DeleteService(service_id_request) service_client.DeleteService(target.service_id) response = jsonify({}) response.status_code = HTTP_NOCONTENT return response target = get_slice(context_client, vpn_id) if target is not None: if target.slice_id.slice_uuid.uuid != vpn_id: # pylint: disable=no-member raise Exception('Slice retrieval failed. Wrong Slice Id was returned') slice_client = SliceClient() slice_client.DeleteSlice(target.slice_id) response = jsonify({}) response.status_code = HTTP_NOCONTENT return response raise Exception('VPN({:s}) not found in database'.format(str(vpn_id))) except Exception as e: # pylint: disable=broad-except LOGGER.exception('Something went wrong Deleting Service {:s}'.format(str(request))) LOGGER.exception('Something went wrong Deleting VPN({:s})'.format(str(vpn_id))) response = jsonify({'error': str(e)}) response.status_code = HTTP_SERVERERROR return response src/compute/service/rest_server/nbi_plugins/ietf_l2vpn/L2VPN_SiteNetworkAccesses.py +78 −159 Original line number Diff line number Diff line Loading @@ -12,16 +12,19 @@ # See the License for the specific language governing permissions and # limitations under the License. import time, random from ctypes import Union import json, logging from typing import Dict import logging, random, time from typing import Dict, Optional, Union from flask import request from flask.json import jsonify from flask.wrappers import Response from flask_restful import Resource from werkzeug.exceptions import UnsupportedMediaType from common.proto.context_pb2 import ConfigActionEnum, Service, Slice from common.proto.context_pb2 import Service, Slice from common.tools.grpc.ConfigRules import update_config_rule_custom from common.tools.grpc.Constraints import ( update_constraint_custom, update_constraint_endpoint_location, update_constraint_endpoint_priority, update_constraint_sla_availability) from common.tools.grpc.EndPointIds import update_endpoint_ids from common.tools.grpc.Tools import grpc_message_to_json_string from context.client.ContextClient import ContextClient from service.client.ServiceClient import ServiceClient Loading @@ -31,20 +34,32 @@ from .tools.Authentication import HTTP_AUTH from .tools.ContextMethods import get_service, get_slice from .tools.HttpStatusCodes import HTTP_NOCONTENT, HTTP_SERVERERROR from .tools.Validator import validate_message from .Constants import BEARER_MAPPINGS, DEFAULT_ADDRESS_FAMILIES, DEFAULT_BGP_AS, DEFAULT_BGP_ROUTE_TARGET, DEFAULT_MTU from .Constants import ( BEARER_MAPPINGS, DEFAULT_ADDRESS_FAMILIES, DEFAULT_BGP_AS, DEFAULT_BGP_ROUTE_TARGET, DEFAULT_MTU) LOGGER = logging.getLogger(__name__) def process_site_network_access(context_client : ContextClient, site_network_access : Dict) -> Service: def process_site_network_access(context_client : ContextClient, site_id : str, site_network_access : Dict) -> Service: vpn_id = site_network_access['vpn-attachment']['vpn-id'] cvlan_id = site_network_access['connection']['tagged-interface']['dot1q-vlan-tagged']['cvlan-id'] encapsulation_type = site_network_access['connection']['encapsulation-type'] cvlan_id = site_network_access['connection']['tagged-interface'][encapsulation_type]['cvlan-id'] bearer_reference = site_network_access['bearer']['bearer-reference'] access_priority = site_network_access.get('availability', {}).get('access-priority') single_active = site_network_access.get('availability', {}).get('single-active') all_active = site_network_access.get('availability', {}).get('all-active') access_priority : Optional[int] = site_network_access.get('availability', {}).get('access-priority') single_active : bool = len(site_network_access.get('availability', {}).get('single-active', [])) > 0 all_active : bool = len(site_network_access.get('availability', {}).get('all-active', [])) > 0 diversity_constraints = site_network_access.get('access-diversity', {}).get('constraints', {}).get('constraint', []) # TODO: manage targets of constraints, right now, only type of constraint is considered diversity_constraints = [constraint['constraint-type'] for constraint in diversity_constraints] raise_if_differs = True diversity_constraints = { constraint['constraint-type']:([ target[0] for target in constraint['target'].items() if len(target[1]) == 1 ][0], raise_if_differs) for constraint in diversity_constraints } mapping = BEARER_MAPPINGS.get(bearer_reference) if mapping is None: Loading @@ -57,157 +72,61 @@ def process_site_network_access(context_client : ContextClient, site_network_acc if target is None: target = get_slice (context_client, vpn_id) if target is None: raise Exception('VPN({:s}) not found in database'.format(str(vpn_id))) # pylint: disable=no-member endpoint_ids = target.service_endpoint_ids if isinstance(target, Service) else target.slice_endpoint_ids for endpoint_id in endpoint_ids: if endpoint_id.device_id.device_uuid.uuid != device_uuid: continue if endpoint_id.endpoint_uuid.uuid != endpoint_uuid: continue break # found, do nothing if isinstance(target, Service): endpoint_ids = target.service_endpoint_ids # pylint: disable=no-member config_rules = target.service_config.config_rules # pylint: disable=no-member constraints = target.service_constraints # pylint: disable=no-member elif isinstance(target, Slice): endpoint_ids = target.slice_endpoint_ids # pylint: disable=no-member config_rules = target.slice_config.config_rules # pylint: disable=no-member constraints = target.slice_constraints # pylint: disable=no-member else: # not found, add it endpoint_id = endpoint_ids.add() endpoint_id.device_id.device_uuid.uuid = device_uuid endpoint_id.endpoint_uuid.uuid = endpoint_uuid if isinstance(target, Slice): return target raise Exception('Target({:s}) not supported'.format(str(target.__class__.__name__))) for config_rule in target.service_config.config_rules: # pylint: disable=no-member if config_rule.WhichOneof('config_rule') != 'custom': continue if config_rule.custom.resource_key != '/settings': continue json_settings = json.loads(config_rule.custom.resource_value) endpoint_id = update_endpoint_ids(endpoint_ids, device_uuid, endpoint_uuid) if 'mtu' not in json_settings: # missing, add it json_settings['mtu'] = DEFAULT_MTU elif json_settings['mtu'] != DEFAULT_MTU: # differs, raise exception msg = 'Specified MTU({:s}) differs from Service MTU({:s})' raise Exception(msg.format(str(json_settings['mtu']), str(DEFAULT_MTU))) if 'address_families' not in json_settings: # missing, add it json_settings['address_families'] = DEFAULT_ADDRESS_FAMILIES elif json_settings['address_families'] != DEFAULT_ADDRESS_FAMILIES: # differs, raise exception msg = 'Specified AddressFamilies({:s}) differs from Service AddressFamilies({:s})' raise Exception(msg.format(str(json_settings['address_families']), str(DEFAULT_ADDRESS_FAMILIES))) if 'bgp_as' not in json_settings: # missing, add it json_settings['bgp_as'] = DEFAULT_BGP_AS elif json_settings['bgp_as'] != DEFAULT_BGP_AS: # differs, raise exception msg = 'Specified BgpAs({:s}) differs from Service BgpAs({:s})' raise Exception(msg.format(str(json_settings['bgp_as']), str(DEFAULT_BGP_AS))) if 'bgp_route_target' not in json_settings: # missing, add it json_settings['bgp_route_target'] = DEFAULT_BGP_ROUTE_TARGET elif json_settings['bgp_route_target'] != DEFAULT_BGP_ROUTE_TARGET: # differs, raise exception msg = 'Specified BgpRouteTarget({:s}) differs from Service BgpRouteTarget({:s})' raise Exception(msg.format(str(json_settings['bgp_route_target']), str(DEFAULT_BGP_ROUTE_TARGET))) config_rule.custom.resource_value = json.dumps(json_settings, sort_keys=True) break else: # not found, add it config_rule = target.service_config.config_rules.add() # pylint: disable=no-member config_rule.action = ConfigActionEnum.CONFIGACTION_SET config_rule.custom.resource_key = '/settings' config_rule.custom.resource_value = json.dumps({ 'mtu' : DEFAULT_MTU, 'address_families': DEFAULT_ADDRESS_FAMILIES, 'bgp_as' : DEFAULT_BGP_AS, 'bgp_route_target': DEFAULT_BGP_ROUTE_TARGET, }, sort_keys=True) service_settings_key = '/settings' update_config_rule_custom(config_rules, service_settings_key, { 'mtu' : (DEFAULT_MTU, True), 'address_families': (DEFAULT_ADDRESS_FAMILIES, True), 'bgp_as' : (DEFAULT_BGP_AS, True), 'bgp_route_target': (DEFAULT_BGP_ROUTE_TARGET, True), }) endpoint_settings_key = '/device[{:s}]/endpoint[{:s}]/settings'.format(device_uuid, endpoint_uuid) for config_rule in target.service_config.config_rules: # pylint: disable=no-member if config_rule.WhichOneof('config_rule') != 'custom': continue if config_rule.custom.resource_key != endpoint_settings_key: continue json_settings = json.loads(config_rule.custom.resource_value) if 'router_id' not in json_settings: # missing, add it json_settings['router_id'] = router_id elif json_settings['router_id'] != router_id: # differs, raise exception msg = 'Specified RouterId({:s}) differs from Service RouterId({:s})' raise Exception(msg.format(str(json_settings['router_id']), str(router_id))) if 'route_distinguisher' not in json_settings: # missing, add it json_settings['route_distinguisher'] = route_distinguisher elif json_settings['route_distinguisher'] != route_distinguisher: # differs, raise exception msg = 'Specified RouteDistinguisher({:s}) differs from Service RouteDistinguisher({:s})' raise Exception(msg.format(str(json_settings['route_distinguisher']), str(route_distinguisher))) if 'sub_interface_index' not in json_settings: # missing, add it json_settings['sub_interface_index'] = sub_if_index elif json_settings['sub_interface_index'] != sub_if_index: # differs, raise exception msg = 'Specified SubInterfaceIndex({:s}) differs from Service SubInterfaceIndex({:s})' raise Exception(msg.format( str(json_settings['sub_interface_index']), str(sub_if_index))) if 'vlan_id' not in json_settings: # missing, add it json_settings['vlan_id'] = cvlan_id elif json_settings['vlan_id'] != cvlan_id: # differs, raise exception msg = 'Specified VLANId({:s}) differs from Service VLANId({:s})' raise Exception(msg.format( str(json_settings['vlan_id']), str(cvlan_id))) if address_ip is not None: if 'address_ip' not in json_settings: # missing, add it json_settings['address_ip'] = address_ip elif json_settings['address_ip'] != address_ip: # differs, raise exception msg = 'Specified AddressIP({:s}) differs from Service AddressIP({:s})' raise Exception(msg.format( str(json_settings['address_ip']), str(address_ip))) if address_prefix is not None: if 'address_prefix' not in json_settings: # missing, add it json_settings['address_prefix'] = address_prefix elif json_settings['address_prefix'] != address_prefix: # differs, raise exception msg = 'Specified AddressPrefix({:s}) differs from Service AddressPrefix({:s})' raise Exception(msg.format( str(json_settings['address_prefix']), str(address_prefix))) if address_prefix is not None: if 'address_prefix' not in json_settings: # missing, add it json_settings['address_prefix'] = address_prefix elif json_settings['address_prefix'] != address_prefix: # differs, raise exception msg = 'Specified AddressPrefix({:s}) differs from Service AddressPrefix({:s})' raise Exception(msg.format( str(json_settings['address_prefix']), str(address_prefix))) config_rule.custom.resource_value = json.dumps(json_settings, sort_keys=True) break else: # not found, add it config_rule = target.service_config.config_rules.add() # pylint: disable=no-member config_rule.action = ConfigActionEnum.CONFIGACTION_SET resource_value = { 'router_id': router_id, 'route_distinguisher': route_distinguisher, 'sub_interface_index': sub_if_index, 'vlan_id': cvlan_id, 'address_ip': address_ip, 'address_prefix': address_prefix, field_updates = { 'router_id' : (router_id, True), 'route_distinguisher': (route_distinguisher, True), 'sub_interface_index': (sub_if_index, True), 'vlan_id' : (cvlan_id, True), } if access_priority is not None: resource_value['access_priority'] = access_priority if single_active is not None and len(single_active) > 0: resource_value['access_active'] = 'single' if all_active is not None and len(all_active) > 0: resource_value['access_active'] = 'all' config_rule.custom.resource_key = endpoint_settings_key config_rule.custom.resource_value = json.dumps(resource_value, sort_keys=True) if address_ip is not None: field_updates['address_ip' ] = (address_ip, True) if address_prefix is not None: field_updates['address_prefix' ] = (address_prefix, True) update_config_rule_custom(config_rules, endpoint_settings_key, field_updates) for constraint in target.service_constraints: # pylint: disable=no-member if constraint.constraint_type == 'diversity' and len(diversity_constraints) > 0: constraint_value = set(json.loads(constraint.constraint_value)) constraint_value.update(diversity_constraints) constraint.constraint_value = json.dumps(sorted(list(constraint_value)), sort_keys=True) break else: # not found, and there are diversity constraints, add them field_updates = {} if len(diversity_constraints) > 0: constraint = target.service_constraints.add() # pylint: disable=no-member constraint.constraint_type = 'diversity' constraint.constraint_value = json.dumps(sorted(list(diversity_constraints)), sort_keys=True) field_updates.update(diversity_constraints) update_constraint_custom(constraints, 'diversity', field_updates) update_constraint_endpoint_location(constraints, endpoint_id, region=site_id) if access_priority is not None: update_constraint_endpoint_priority(constraints, endpoint_id, access_priority) if single_active or all_active: # assume 1 disjoint path per endpoint/location included in service/slice location_endpoints = {} for constraint in constraints: if constraint.WhichOneof('constraint') != 'endpoint_location': continue str_endpoint_id = grpc_message_to_json_string(constraint.endpoint_location.endpoint_id) str_location_id = grpc_message_to_json_string(constraint.endpoint_location.location) location_endpoints.setdefault(str_location_id, set()).add(str_endpoint_id) num_endpoints_per_location = {len(endpoints) for endpoints in location_endpoints.values()} num_disjoint_paths = min(num_endpoints_per_location) update_constraint_sla_availability(constraints, num_disjoint_paths, all_active) return target def process_list_site_network_access( context_client : ContextClient, service_client : ServiceClient, slice_client : SliceClient, context_client : ContextClient, service_client : ServiceClient, slice_client : SliceClient, site_id : str, request_data : Dict ) -> Response: Loading @@ -216,7 +135,7 @@ def process_list_site_network_access( errors = [] for site_network_access in request_data['ietf-l2vpn-svc:site-network-access']: sna_request = process_site_network_access(context_client, site_network_access) sna_request = process_site_network_access(context_client, site_id, site_network_access) LOGGER.debug('sna_request = {:s}'.format(grpc_message_to_json_string(sna_request))) try: if isinstance(sna_request, Service): Loading @@ -230,7 +149,7 @@ def process_list_site_network_access( else: raise NotImplementedError('Support for Class({:s}) not implemented'.format(str(type(sna_request)))) except Exception as e: # pylint: disable=broad-except msg = 'Something went wrong Updating Service {:s}' msg = 'Something went wrong Updating VPN {:s}' LOGGER.exception(msg.format(grpc_message_to_json_string(sna_request))) errors.append({'error': str(e)}) time.sleep(random.random() / 10.0) Loading @@ -247,7 +166,7 @@ class L2VPN_SiteNetworkAccesses(Resource): context_client = ContextClient() service_client = ServiceClient() slice_client = SliceClient() return process_list_site_network_access(context_client, service_client, slice_client, request.json) return process_list_site_network_access(context_client, service_client, slice_client, site_id, request.json) @HTTP_AUTH.login_required def put(self, site_id : str): Loading @@ -256,4 +175,4 @@ class L2VPN_SiteNetworkAccesses(Resource): context_client = ContextClient() service_client = ServiceClient() slice_client = SliceClient() return process_list_site_network_access(context_client, service_client, slice_client, request.json) return process_list_site_network_access(context_client, service_client, slice_client, site_id, request.json) Loading
src/compute/service/rest_server/nbi_plugins/ietf_l2vpn/L2VPN_Service.py +26 −16 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ from common.Constants import DEFAULT_CONTEXT_UUID from common.proto.context_pb2 import ServiceId, ServiceStatusEnum, SliceStatusEnum from context.client.ContextClient import ContextClient from service.client.ServiceClient import ServiceClient from slice.client.SliceClient import SliceClient from .tools.Authentication import HTTP_AUTH from .tools.ContextMethods import get_service, get_slice from .tools.HttpStatusCodes import HTTP_GATEWAYTIMEOUT, HTTP_NOCONTENT, HTTP_OK, HTTP_SERVERERROR Loading @@ -32,11 +33,6 @@ class L2VPN_Service(Resource): LOGGER.debug('VPN_Id: {:s}'.format(str(vpn_id))) LOGGER.debug('Request: {:s}'.format(str(request))) # TODO: HACK ECOC'22, to be corrected response = jsonify({}) response.status_code = HTTP_OK return response try: context_client = ContextClient() Loading @@ -60,7 +56,7 @@ class L2VPN_Service(Resource): raise Exception('VPN({:s}) not found in database'.format(str(vpn_id))) except Exception as e: # pylint: disable=broad-except LOGGER.exception('Something went wrong Retrieving VPN({:s})'.format(str(request))) LOGGER.exception('Something went wrong Retrieving VPN({:s})'.format(str(vpn_id))) response = jsonify({'error': str(e)}) response.status_code = HTTP_SERVERERROR return response Loading @@ -70,18 +66,32 @@ class L2VPN_Service(Resource): LOGGER.debug('VPN_Id: {:s}'.format(str(vpn_id))) LOGGER.debug('Request: {:s}'.format(str(request))) # pylint: disable=no-member service_id_request = ServiceId() service_id_request.context_id.context_uuid.uuid = DEFAULT_CONTEXT_UUID service_id_request.service_uuid.uuid = vpn_id try: context_client = ContextClient() target = get_service(context_client, vpn_id) if target is not None: if target.service_id.service_uuid.uuid != vpn_id: # pylint: disable=no-member raise Exception('Service retrieval failed. Wrong Service Id was returned') service_client = ServiceClient() service_client.DeleteService(service_id_request) service_client.DeleteService(target.service_id) response = jsonify({}) response.status_code = HTTP_NOCONTENT return response target = get_slice(context_client, vpn_id) if target is not None: if target.slice_id.slice_uuid.uuid != vpn_id: # pylint: disable=no-member raise Exception('Slice retrieval failed. Wrong Slice Id was returned') slice_client = SliceClient() slice_client.DeleteSlice(target.slice_id) response = jsonify({}) response.status_code = HTTP_NOCONTENT return response raise Exception('VPN({:s}) not found in database'.format(str(vpn_id))) except Exception as e: # pylint: disable=broad-except LOGGER.exception('Something went wrong Deleting Service {:s}'.format(str(request))) LOGGER.exception('Something went wrong Deleting VPN({:s})'.format(str(vpn_id))) response = jsonify({'error': str(e)}) response.status_code = HTTP_SERVERERROR return response
src/compute/service/rest_server/nbi_plugins/ietf_l2vpn/L2VPN_SiteNetworkAccesses.py +78 −159 Original line number Diff line number Diff line Loading @@ -12,16 +12,19 @@ # See the License for the specific language governing permissions and # limitations under the License. import time, random from ctypes import Union import json, logging from typing import Dict import logging, random, time from typing import Dict, Optional, Union from flask import request from flask.json import jsonify from flask.wrappers import Response from flask_restful import Resource from werkzeug.exceptions import UnsupportedMediaType from common.proto.context_pb2 import ConfigActionEnum, Service, Slice from common.proto.context_pb2 import Service, Slice from common.tools.grpc.ConfigRules import update_config_rule_custom from common.tools.grpc.Constraints import ( update_constraint_custom, update_constraint_endpoint_location, update_constraint_endpoint_priority, update_constraint_sla_availability) from common.tools.grpc.EndPointIds import update_endpoint_ids from common.tools.grpc.Tools import grpc_message_to_json_string from context.client.ContextClient import ContextClient from service.client.ServiceClient import ServiceClient Loading @@ -31,20 +34,32 @@ from .tools.Authentication import HTTP_AUTH from .tools.ContextMethods import get_service, get_slice from .tools.HttpStatusCodes import HTTP_NOCONTENT, HTTP_SERVERERROR from .tools.Validator import validate_message from .Constants import BEARER_MAPPINGS, DEFAULT_ADDRESS_FAMILIES, DEFAULT_BGP_AS, DEFAULT_BGP_ROUTE_TARGET, DEFAULT_MTU from .Constants import ( BEARER_MAPPINGS, DEFAULT_ADDRESS_FAMILIES, DEFAULT_BGP_AS, DEFAULT_BGP_ROUTE_TARGET, DEFAULT_MTU) LOGGER = logging.getLogger(__name__) def process_site_network_access(context_client : ContextClient, site_network_access : Dict) -> Service: def process_site_network_access(context_client : ContextClient, site_id : str, site_network_access : Dict) -> Service: vpn_id = site_network_access['vpn-attachment']['vpn-id'] cvlan_id = site_network_access['connection']['tagged-interface']['dot1q-vlan-tagged']['cvlan-id'] encapsulation_type = site_network_access['connection']['encapsulation-type'] cvlan_id = site_network_access['connection']['tagged-interface'][encapsulation_type]['cvlan-id'] bearer_reference = site_network_access['bearer']['bearer-reference'] access_priority = site_network_access.get('availability', {}).get('access-priority') single_active = site_network_access.get('availability', {}).get('single-active') all_active = site_network_access.get('availability', {}).get('all-active') access_priority : Optional[int] = site_network_access.get('availability', {}).get('access-priority') single_active : bool = len(site_network_access.get('availability', {}).get('single-active', [])) > 0 all_active : bool = len(site_network_access.get('availability', {}).get('all-active', [])) > 0 diversity_constraints = site_network_access.get('access-diversity', {}).get('constraints', {}).get('constraint', []) # TODO: manage targets of constraints, right now, only type of constraint is considered diversity_constraints = [constraint['constraint-type'] for constraint in diversity_constraints] raise_if_differs = True diversity_constraints = { constraint['constraint-type']:([ target[0] for target in constraint['target'].items() if len(target[1]) == 1 ][0], raise_if_differs) for constraint in diversity_constraints } mapping = BEARER_MAPPINGS.get(bearer_reference) if mapping is None: Loading @@ -57,157 +72,61 @@ def process_site_network_access(context_client : ContextClient, site_network_acc if target is None: target = get_slice (context_client, vpn_id) if target is None: raise Exception('VPN({:s}) not found in database'.format(str(vpn_id))) # pylint: disable=no-member endpoint_ids = target.service_endpoint_ids if isinstance(target, Service) else target.slice_endpoint_ids for endpoint_id in endpoint_ids: if endpoint_id.device_id.device_uuid.uuid != device_uuid: continue if endpoint_id.endpoint_uuid.uuid != endpoint_uuid: continue break # found, do nothing if isinstance(target, Service): endpoint_ids = target.service_endpoint_ids # pylint: disable=no-member config_rules = target.service_config.config_rules # pylint: disable=no-member constraints = target.service_constraints # pylint: disable=no-member elif isinstance(target, Slice): endpoint_ids = target.slice_endpoint_ids # pylint: disable=no-member config_rules = target.slice_config.config_rules # pylint: disable=no-member constraints = target.slice_constraints # pylint: disable=no-member else: # not found, add it endpoint_id = endpoint_ids.add() endpoint_id.device_id.device_uuid.uuid = device_uuid endpoint_id.endpoint_uuid.uuid = endpoint_uuid if isinstance(target, Slice): return target raise Exception('Target({:s}) not supported'.format(str(target.__class__.__name__))) for config_rule in target.service_config.config_rules: # pylint: disable=no-member if config_rule.WhichOneof('config_rule') != 'custom': continue if config_rule.custom.resource_key != '/settings': continue json_settings = json.loads(config_rule.custom.resource_value) endpoint_id = update_endpoint_ids(endpoint_ids, device_uuid, endpoint_uuid) if 'mtu' not in json_settings: # missing, add it json_settings['mtu'] = DEFAULT_MTU elif json_settings['mtu'] != DEFAULT_MTU: # differs, raise exception msg = 'Specified MTU({:s}) differs from Service MTU({:s})' raise Exception(msg.format(str(json_settings['mtu']), str(DEFAULT_MTU))) if 'address_families' not in json_settings: # missing, add it json_settings['address_families'] = DEFAULT_ADDRESS_FAMILIES elif json_settings['address_families'] != DEFAULT_ADDRESS_FAMILIES: # differs, raise exception msg = 'Specified AddressFamilies({:s}) differs from Service AddressFamilies({:s})' raise Exception(msg.format(str(json_settings['address_families']), str(DEFAULT_ADDRESS_FAMILIES))) if 'bgp_as' not in json_settings: # missing, add it json_settings['bgp_as'] = DEFAULT_BGP_AS elif json_settings['bgp_as'] != DEFAULT_BGP_AS: # differs, raise exception msg = 'Specified BgpAs({:s}) differs from Service BgpAs({:s})' raise Exception(msg.format(str(json_settings['bgp_as']), str(DEFAULT_BGP_AS))) if 'bgp_route_target' not in json_settings: # missing, add it json_settings['bgp_route_target'] = DEFAULT_BGP_ROUTE_TARGET elif json_settings['bgp_route_target'] != DEFAULT_BGP_ROUTE_TARGET: # differs, raise exception msg = 'Specified BgpRouteTarget({:s}) differs from Service BgpRouteTarget({:s})' raise Exception(msg.format(str(json_settings['bgp_route_target']), str(DEFAULT_BGP_ROUTE_TARGET))) config_rule.custom.resource_value = json.dumps(json_settings, sort_keys=True) break else: # not found, add it config_rule = target.service_config.config_rules.add() # pylint: disable=no-member config_rule.action = ConfigActionEnum.CONFIGACTION_SET config_rule.custom.resource_key = '/settings' config_rule.custom.resource_value = json.dumps({ 'mtu' : DEFAULT_MTU, 'address_families': DEFAULT_ADDRESS_FAMILIES, 'bgp_as' : DEFAULT_BGP_AS, 'bgp_route_target': DEFAULT_BGP_ROUTE_TARGET, }, sort_keys=True) service_settings_key = '/settings' update_config_rule_custom(config_rules, service_settings_key, { 'mtu' : (DEFAULT_MTU, True), 'address_families': (DEFAULT_ADDRESS_FAMILIES, True), 'bgp_as' : (DEFAULT_BGP_AS, True), 'bgp_route_target': (DEFAULT_BGP_ROUTE_TARGET, True), }) endpoint_settings_key = '/device[{:s}]/endpoint[{:s}]/settings'.format(device_uuid, endpoint_uuid) for config_rule in target.service_config.config_rules: # pylint: disable=no-member if config_rule.WhichOneof('config_rule') != 'custom': continue if config_rule.custom.resource_key != endpoint_settings_key: continue json_settings = json.loads(config_rule.custom.resource_value) if 'router_id' not in json_settings: # missing, add it json_settings['router_id'] = router_id elif json_settings['router_id'] != router_id: # differs, raise exception msg = 'Specified RouterId({:s}) differs from Service RouterId({:s})' raise Exception(msg.format(str(json_settings['router_id']), str(router_id))) if 'route_distinguisher' not in json_settings: # missing, add it json_settings['route_distinguisher'] = route_distinguisher elif json_settings['route_distinguisher'] != route_distinguisher: # differs, raise exception msg = 'Specified RouteDistinguisher({:s}) differs from Service RouteDistinguisher({:s})' raise Exception(msg.format(str(json_settings['route_distinguisher']), str(route_distinguisher))) if 'sub_interface_index' not in json_settings: # missing, add it json_settings['sub_interface_index'] = sub_if_index elif json_settings['sub_interface_index'] != sub_if_index: # differs, raise exception msg = 'Specified SubInterfaceIndex({:s}) differs from Service SubInterfaceIndex({:s})' raise Exception(msg.format( str(json_settings['sub_interface_index']), str(sub_if_index))) if 'vlan_id' not in json_settings: # missing, add it json_settings['vlan_id'] = cvlan_id elif json_settings['vlan_id'] != cvlan_id: # differs, raise exception msg = 'Specified VLANId({:s}) differs from Service VLANId({:s})' raise Exception(msg.format( str(json_settings['vlan_id']), str(cvlan_id))) if address_ip is not None: if 'address_ip' not in json_settings: # missing, add it json_settings['address_ip'] = address_ip elif json_settings['address_ip'] != address_ip: # differs, raise exception msg = 'Specified AddressIP({:s}) differs from Service AddressIP({:s})' raise Exception(msg.format( str(json_settings['address_ip']), str(address_ip))) if address_prefix is not None: if 'address_prefix' not in json_settings: # missing, add it json_settings['address_prefix'] = address_prefix elif json_settings['address_prefix'] != address_prefix: # differs, raise exception msg = 'Specified AddressPrefix({:s}) differs from Service AddressPrefix({:s})' raise Exception(msg.format( str(json_settings['address_prefix']), str(address_prefix))) if address_prefix is not None: if 'address_prefix' not in json_settings: # missing, add it json_settings['address_prefix'] = address_prefix elif json_settings['address_prefix'] != address_prefix: # differs, raise exception msg = 'Specified AddressPrefix({:s}) differs from Service AddressPrefix({:s})' raise Exception(msg.format( str(json_settings['address_prefix']), str(address_prefix))) config_rule.custom.resource_value = json.dumps(json_settings, sort_keys=True) break else: # not found, add it config_rule = target.service_config.config_rules.add() # pylint: disable=no-member config_rule.action = ConfigActionEnum.CONFIGACTION_SET resource_value = { 'router_id': router_id, 'route_distinguisher': route_distinguisher, 'sub_interface_index': sub_if_index, 'vlan_id': cvlan_id, 'address_ip': address_ip, 'address_prefix': address_prefix, field_updates = { 'router_id' : (router_id, True), 'route_distinguisher': (route_distinguisher, True), 'sub_interface_index': (sub_if_index, True), 'vlan_id' : (cvlan_id, True), } if access_priority is not None: resource_value['access_priority'] = access_priority if single_active is not None and len(single_active) > 0: resource_value['access_active'] = 'single' if all_active is not None and len(all_active) > 0: resource_value['access_active'] = 'all' config_rule.custom.resource_key = endpoint_settings_key config_rule.custom.resource_value = json.dumps(resource_value, sort_keys=True) if address_ip is not None: field_updates['address_ip' ] = (address_ip, True) if address_prefix is not None: field_updates['address_prefix' ] = (address_prefix, True) update_config_rule_custom(config_rules, endpoint_settings_key, field_updates) for constraint in target.service_constraints: # pylint: disable=no-member if constraint.constraint_type == 'diversity' and len(diversity_constraints) > 0: constraint_value = set(json.loads(constraint.constraint_value)) constraint_value.update(diversity_constraints) constraint.constraint_value = json.dumps(sorted(list(constraint_value)), sort_keys=True) break else: # not found, and there are diversity constraints, add them field_updates = {} if len(diversity_constraints) > 0: constraint = target.service_constraints.add() # pylint: disable=no-member constraint.constraint_type = 'diversity' constraint.constraint_value = json.dumps(sorted(list(diversity_constraints)), sort_keys=True) field_updates.update(diversity_constraints) update_constraint_custom(constraints, 'diversity', field_updates) update_constraint_endpoint_location(constraints, endpoint_id, region=site_id) if access_priority is not None: update_constraint_endpoint_priority(constraints, endpoint_id, access_priority) if single_active or all_active: # assume 1 disjoint path per endpoint/location included in service/slice location_endpoints = {} for constraint in constraints: if constraint.WhichOneof('constraint') != 'endpoint_location': continue str_endpoint_id = grpc_message_to_json_string(constraint.endpoint_location.endpoint_id) str_location_id = grpc_message_to_json_string(constraint.endpoint_location.location) location_endpoints.setdefault(str_location_id, set()).add(str_endpoint_id) num_endpoints_per_location = {len(endpoints) for endpoints in location_endpoints.values()} num_disjoint_paths = min(num_endpoints_per_location) update_constraint_sla_availability(constraints, num_disjoint_paths, all_active) return target def process_list_site_network_access( context_client : ContextClient, service_client : ServiceClient, slice_client : SliceClient, context_client : ContextClient, service_client : ServiceClient, slice_client : SliceClient, site_id : str, request_data : Dict ) -> Response: Loading @@ -216,7 +135,7 @@ def process_list_site_network_access( errors = [] for site_network_access in request_data['ietf-l2vpn-svc:site-network-access']: sna_request = process_site_network_access(context_client, site_network_access) sna_request = process_site_network_access(context_client, site_id, site_network_access) LOGGER.debug('sna_request = {:s}'.format(grpc_message_to_json_string(sna_request))) try: if isinstance(sna_request, Service): Loading @@ -230,7 +149,7 @@ def process_list_site_network_access( else: raise NotImplementedError('Support for Class({:s}) not implemented'.format(str(type(sna_request)))) except Exception as e: # pylint: disable=broad-except msg = 'Something went wrong Updating Service {:s}' msg = 'Something went wrong Updating VPN {:s}' LOGGER.exception(msg.format(grpc_message_to_json_string(sna_request))) errors.append({'error': str(e)}) time.sleep(random.random() / 10.0) Loading @@ -247,7 +166,7 @@ class L2VPN_SiteNetworkAccesses(Resource): context_client = ContextClient() service_client = ServiceClient() slice_client = SliceClient() return process_list_site_network_access(context_client, service_client, slice_client, request.json) return process_list_site_network_access(context_client, service_client, slice_client, site_id, request.json) @HTTP_AUTH.login_required def put(self, site_id : str): Loading @@ -256,4 +175,4 @@ class L2VPN_SiteNetworkAccesses(Resource): context_client = ContextClient() service_client = ServiceClient() slice_client = SliceClient() return process_list_site_network_access(context_client, service_client, slice_client, request.json) return process_list_site_network_access(context_client, service_client, slice_client, site_id, request.json)