Пример #1
0
 def set_properties(self, **kwargs):
     """
     Set multiple properties of the service
     :param kwargs:
     :return:
     """
     service_sliver = NetworkServiceSliver()
     service_sliver.set_properties(**kwargs)
     # write into the graph
     prop_dict = self.topo.graph_model.network_service_sliver_to_graph_properties_dict(service_sliver)
     self.topo.graph_model.update_node_properties(node_id=self.node_id, props=prop_dict)
Пример #2
0
 def set_property(self, pname: str, pval: Any):
     """
     Set a service property or unset of pval is None
     :param pname:
     :param pval:
     :return:
     """
     if pval is None:
         self.unset_property(pname)
         return
     service_sliver = NetworkServiceSliver()
     service_sliver.set_property(prop_name=pname, prop_val=pval)
     # write into the graph
     prop_dict = self.topo.graph_model.network_service_sliver_to_graph_properties_dict(service_sliver)
     self.topo.graph_model.update_node_properties(node_id=self.node_id, props=prop_dict)
Пример #3
0
 def __fabnetv6_create_data(self, sliver: NetworkServiceSliver, service_name: str) -> dict:
     device_name = None
     interfaces = []
     data = {"name": service_name, "interface": interfaces}
     for interface_name in sliver.interface_info.interfaces:
         interface_sliver = sliver.interface_info.interfaces[interface_name]
         labs: Labels = interface_sliver.get_labels()
         caps: Capacities = interface_sliver.get_capacities()
         if labs.device_name is None:
             raise NetHandlerException(f'fabnetv6 - interface "{interface_name}" has no "device_name" label')
         if device_name is None:
             device_name = labs.device_name
             data['device'] = device_name
         elif device_name != labs.device_name:
             raise NetHandlerException(
                 f'fabnetv6 - has two different device_name "{device_name}" and "{labs.device_name}"')
         interface = {}
         if labs.local_name is None:
             raise NetHandlerException(f'fabnetv6 - interface "{interface_name}" has no "local_name" label')
         interface_type_id = re.findall(r'(\w+)(\d.+)', labs.local_name)
         if not interface_type_id or len(interface_type_id[0]) != 2:
             raise NetHandlerException(f'fabnetv6 - interface "{interface_name}" has malformed "local_name" label')
         interface['type'] = interface_type_id[0][0]
         interface['id'] = interface_type_id[0][1]
         if labs.vlan is None:
             interface['outervlan'] = 0
         else:
             interface['outervlan'] = labs.vlan
         if int(interface['outervlan']) > 0 and labs.inner_vlan is not None:
             interface['innervlan'] = labs.inner_vlan
         interfaces.append(interface)
     if not interfaces:
         raise NetHandlerException(f'fabnetv6 - none valid interface is defined in sliver')
     if sliver.get_gateway() is None:
         raise NetHandlerException(f'fabnetv6 - sliver missing gateway')
     gateway = sliver.get_gateway()
     if gateway.lab is None:
         raise NetHandlerException(f'fabnetv6 - sliver gateway missing labels')
     if gateway.lab.ipv6 is None:
         raise NetHandlerException(f'fabnetv6 - sliver gateway missing "ipv6" label')
     if gateway.lab.ipv6_subnet is None:
         raise NetHandlerException(f'fabnetv6 - sliver gateway missing "ipv6_subnet" label')
     # assume sliver has verified gateway.lab.ipv6 is included in gateway.lab.ipv6_subnet that has a valid subnet prefix
     data['gateway-ipv6'] = {'address': gateway.lab.ipv6, 'netmask': str(gateway.lab.ipv6_subnet).split('/')[1]}
     if gateway.lab.mac is not None:
         data['gateway-mac-address'] = gateway.lab.mac
     return data
Пример #4
0
    def __cleanup(self, *, sliver: NetworkServiceSliver, unit_id: str, raise_exception: bool = False):
        if sliver.get_labels() is None or sliver.get_labels().local_name is None:
            # truncate service_name length to no greater than 53 (36+1+16)
            sliver_name = sliver.get_name()[:16] if len(sliver.get_name()) > 16 else sliver.get_name()
            service_name = f'{sliver_name}-{unit_id}'
        else:
            service_name = sliver.get_labels().local_name
        resource_type = str(sliver.get_type())
        service_type = resource_type.lower()
        if service_type == 'fabnetv4' or service_type == 'fabnetv6':
            service_type = 'l3rt'
        elif service_type == 'portmirror':
            service_type = 'port-mirror'
        data = {
            "tailf-ncs:services": {
                f'{service_type}:{service_type}': [{
                    "name": f'{service_name}',
                    "__state": "absent"
                }]
            }
        }
        extra_vars = {
            "service_name": service_name,
            "service_type": service_type,
            "service_action": "delete",
            "data": data
        }
        try:
            playbook_path = self.get_config()[AmConstants.PLAYBOOK_SECTION][AmConstants.PB_LOCATION]
            inventory_path = self.get_config()[AmConstants.PLAYBOOK_SECTION][AmConstants.PB_INVENTORY]
            playbook = self.get_config()[AmConstants.PLAYBOOK_SECTION][resource_type]
            if playbook is None or inventory_path is None or playbook_path is None:
                raise NetHandlerException(f"Missing config parameters playbook: {playbook} "
                                          f"playbook_path: {playbook_path} inventory_path: {inventory_path}")
            playbook_path_full = f"{playbook_path}/{playbook}"
            ansible_helper = AnsibleHelper(inventory_path=inventory_path, logger=self.get_logger())
            ansible_helper.set_extra_vars(extra_vars=extra_vars)
            self.get_logger().debug(f"Executing playbook {playbook_path_full} to delete Network Service")
            ansible_helper.run_playbook(playbook_path=playbook_path_full)
            ansible_callback = ansible_helper.get_result_callback()
            unreachable = ansible_callback.get_json_result_unreachable()
            if unreachable:
                raise NetHandlerException(f'network service {service_name} was not cleaned up due to connection error')
            failed = ansible_callback.get_json_result_failed()
            if failed:
                ansible_callback.dump_all_failed(logger=self.get_logger())
                raise NetHandlerException(f'network service {service_name} was not cleaned up due to config error')
            ok = ansible_callback.get_json_result_ok()
            if ok:
                if not ok['changed']:
                    self.get_logger().info(f'network service {service_name} was cleaned up ok but without change')

        except Exception as e:
            self.get_logger().error(f"Exception occurred in cleanup {e}")
            self.get_logger().error(traceback.format_exc())
            if raise_exception:
                raise e
 def testNetworkServiceSliver(self):
     ns = NetworkServiceSliver()
     p = Path()
     p.set_symmetric(['a', 'b', 'c'])
     pi = PathInfo()
     pi.set(payload=p)
     ns.set_properties(path_info=pi)
     e = ERO()
     e.set(payload=p)
     ns.set_properties(ero=e)
     pi1 = ns.get_property('path_info')
     assert(pi.get() == pi1.get())
Пример #6
0
 def __service_guardrails(sliver: NetworkServiceSliver, interface: Interface):
     """
     Checks if this interface can be added to this service for various reasons related to e.g.
     service implementation constraints (that can be temporary and change from release to release).
     :param sliver:
     :param interface:
     :return:
     """
     # - L2P2P service does not work for shared ports
     # - L2S2S needs to warn that it may not work if the VMs with shared ports land on the same worker
     if sliver.get_type() == ServiceType.L2PTP and \
         interface.type == InterfaceType.SharedPort:
         raise TopologyException(f"Unable to connect interface {interface.name} to service {sliver.get_name()}: "
                                 f"L2P2P service currently doesn't support shared interfaces")
Пример #7
0
    def __allocate_services(
            self, *, rid: ID, inv: NetworkServiceInventory,
            sliver: NetworkServiceSliver,
            node_id_to_reservations: dict) -> Tuple[str, BaseSliver, Any]:
        """
        Allocate Network Service Slivers
        @param rid Reservation Id
        @param inv Inventory
        @param sliver Requested sliver
        @param node_id_to_reservations
        @return tuple containing delegation id, sliver, error message if any
        """
        self.logger.debug(f"Processing Network Service sliver: {sliver}")
        delegation_id = None
        error_msg = None
        owner_switch = None
        owner_mpls_ns = None

        # For each Interface Sliver;
        for ifs in sliver.interface_info.interfaces.values():

            # Fetch Network Node Id and BQM Component Id
            node_id, bqm_component_id = ifs.get_node_map()
            bqm_component = self.get_component_sliver(node_id=bqm_component_id)

            # Get BQM Connection Point in Site Delegation (c)
            site_cp = FimHelper.get_site_interface_sliver(
                component=bqm_component,
                local_name=ifs.get_labels().local_name)

            self.logger.debug(
                f"Interface Sliver [Site Delegation] (C): {site_cp}")

            # Get BQM Peer Connection Point in Site Delegation (a)
            net_cp = self.get_net_interface_sliver(
                site_ifs_id=site_cp.node_id, itype=InterfaceType.TrunkPort)

            if net_cp is None:
                error_msg = "Peer Connection Point not found from Network AM"
                raise BrokerException(msg=error_msg)

            self.logger.debug(
                f"Peer Interface Sliver [Network Delegation] (A): {site_cp}")

            # need to find the owner switch of the network service in CBM and take it's name or labels.local_name
            owner_switch, owner_mpls_ns = self.get_owners(
                node_id=net_cp.node_id)

            if bqm_component.get_type() == ComponentType.SharedNIC:
                # VLAN is already set by the Orchestrator using the information from the Node Sliver Parent Reservation
                if ifs.get_labels().vlan is None:
                    message = "Shared NIC VLAN cannot be None"
                    self.logger.error(message)
                    raise BrokerException(
                        error_code=ExceptionErrorCode.FAILURE,
                        msg=f"{message}")
            else:
                existing_reservations = self.get_existing_reservations(
                    node_id=owner_mpls_ns.node_id,
                    node_id_to_reservations=node_id_to_reservations)
                # Set vlan - source: (c) - only for dedicated NICs
                ifs = inv.allocate_ifs(
                    requested_ns=sliver,
                    requested_ifs=ifs,
                    owner_switch=owner_switch,
                    mpls_ns=owner_mpls_ns,
                    bqm_ifs_id=net_cp.node_id,
                    existing_reservations=existing_reservations)

            # local_name source: (a)
            ifs_labels = ifs.get_labels()
            ifs_labels = Labels.update(ifs_labels,
                                       local_name=net_cp.get_name())

            # NSO device name source: (a) - need to find the owner switch of the network service in CBM
            # and take its name or labels.local_name
            # Set the NSO device-name
            ifs_labels = Labels.update(ifs_labels,
                                       device_name=owner_switch.get_name())
            adm_ids = owner_switch.get_structural_info().adm_graph_ids
            site_adm_ids = bqm_component.get_structural_info().adm_graph_ids

            self.logger.debug(f"Owner MPLS Network Service: {owner_mpls_ns}")
            self.logger.debug(f"Owner Switch: {owner_switch}")
            self.logger.debug(
                f"Owner Switch: {owner_switch.network_service_info}")

            net_adm_ids = [
                x for x in adm_ids
                if not x in site_adm_ids or site_adm_ids.remove(x)
            ]
            if len(net_adm_ids) != 1:
                error_msg = f"More than 1 or 0 Network Delegations found! net_adm_ids: {net_adm_ids}"
                self.logger.error(error_msg)
                raise BrokerException(msg=error_msg)

            # Update the Interface Sliver Node Map to map to (a)
            ifs.set_node_map(node_map=(self.combined_broker_model_graph_id,
                                       net_cp.node_id))

            delegation_id = net_adm_ids[0]

            ifs.labels = ifs_labels

            self.logger.debug(
                f"Allocated Interface Sliver: {ifs} delegation: {delegation_id}"
            )

        # Update the Network Service Sliver Node Map to map to parent of (a)
        sliver.set_node_map(node_map=(self.combined_broker_model_graph_id,
                                      owner_mpls_ns.node_id))

        # Set the Subnet and gateway from the Owner Switch (a)
        if sliver.get_type() == ServiceType.FABNetv6 or sliver.get_type(
        ) == ServiceType.FABNetv4:
            existing_reservations = self.get_existing_reservations(
                node_id=owner_mpls_ns.node_id,
                node_id_to_reservations=node_id_to_reservations)
            sliver = inv.allocate(rid=rid,
                                  requested_ns=sliver,
                                  owner_switch=owner_switch,
                                  existing_reservations=existing_reservations)

        return delegation_id, sliver, error_msg
Пример #8
0
    def test_PortMirror(self):

        # create a NetworkService sliver for FABNetv6
        prop = {
            AmConstants.CONFIG_PROPERTIES_FILE:
            '../config/net_handler_config.yml'
        }

        handler = NetHandler(logger=self.logger,
                             properties=prop,
                             process_lock=threading.Lock())
        #
        # create a network sliver for FABNetv4 and its interfaces
        #
        sliver = NetworkServiceSliver()
        # service name (set by user) - only guaranteed unique within a slice
        sliver.set_name('PortMirror-UKY')
        sliver.set_type(ServiceType.PortMirror)
        sliver.set_layer(NSLayer.L2)

        # mirror_port is the name of the port being mirrored - actual name the way
        # service definition needs it. It comes directly from ASM network service sliver
        # whatever the right name is - user must to know it when creating a slice
        sliver.mirror_port = "TwentyFiveGigE0/0/0/24"
        # direction also comes from ASM network service sliver
        sliver.mirror_direction = MirrorDirection.Both

        #
        # interface to which the mirrored traffic is directed to
        # it is in the slice (ASM) model, the same way all other interfaces for network services are.
        #
        stp_to = InterfaceSliver()
        stp_to.set_name('Interface_To_Which_We_Send_Mirrored_Traffic')
        stp_to.set_type(InterfaceType.ServicePort)
        sliver_labels = Labels(local_name='TwentyFiveGigE0/0/0/23/1',
                               device_name='lbnl-data-sw')
        sliver_capacities = Capacities(bw=2000)
        stp_to.set_labels(sliver_labels)
        stp_to.set_capacities(sliver_capacities)

        # create interface info object, add populated interfaces to it
        ifi = InterfaceInfo()
        ifi.add_interface(stp_to)

        # add interface info object to sliver. All of this happens automagically normally
        sliver.interface_info = ifi

        # set a fake unit reservation
        uid = uuid.uuid3(uuid.NAMESPACE_DNS, 'test_PortMirror')
        self.unit = Unit(rid=ID(uid=str(uid)))
        self.unit.set_sliver(sliver=sliver)

        #
        # create a service (create needs to parse out sliver information
        # into exact parameters the service ansible script needs)
        #
        r, updated_unit = handler.create(unit=self.unit)
        self.assertEqual(r[Constants.PROPERTY_TARGET_NAME],
                         Constants.TARGET_CREATE)
        self.assertEqual(r[Constants.PROPERTY_ACTION_SEQUENCE_NUMBER], 0)
        self.assertEqual(r[Constants.PROPERTY_TARGET_RESULT_CODE],
                         Constants.RESULT_CODE_OK)

        time.sleep(30)

        #
        # delete - need to make sure the updated unit has the right info to delete the service
        #
        r, updated_unit = handler.delete(updated_unit)
        self.assertEqual(r[Constants.PROPERTY_TARGET_NAME],
                         Constants.TARGET_DELETE)
        self.assertEqual(r[Constants.PROPERTY_ACTION_SEQUENCE_NUMBER], 0)
        self.assertEqual(r[Constants.PROPERTY_TARGET_RESULT_CODE],
                         Constants.RESULT_CODE_OK)
Пример #9
0
    def test_FABNetv6(self):
        # create a NetworkService sliver for FABNetv6
        prop = {
            AmConstants.CONFIG_PROPERTIES_FILE:
            '../config/net_handler_config.yml'
        }

        handler = NetHandler(logger=self.logger,
                             properties=prop,
                             process_lock=threading.Lock())
        #
        # create a network sliver for FABNetv4 and its interfaces
        #
        sliver = NetworkServiceSliver()
        # service name (set by user) - only guaranteed unique within a slice
        sliver.set_name('L3-UKY-IPv6')
        # if service name global uniqueness is a requirement use Labels.local_name for that (optional)
        # e.g. concatenate name + res id (or another unique id)
        # sliver.set_labels(Labels().set_fields(local_name='test-l2bridge-shortname'))
        # per @xiyang he uses unit id for service name so this is not needed.
        sliver.set_type(ServiceType.FABNetv6)
        sliver.set_layer(NSLayer.L3)

        # this is the gateway with the IP range picked for this sliver in this slice on this site
        # can also be specified with ipv6/ipv6_subnet and mac is optional for both.
        # Q: does that mean that the advertisement needs to maintain information about multiple
        # subnet, gateway and mac tuples for each site?
        sliver.set_gateway(
            Gateway(
                Labels(ipv6="2602:FCFB:0001::1",
                       ipv6_subnet="2602:FCFB:0001::/64")))

        #
        # create a small number of Interface slivers, set their properties and link to service
        #

        #
        # First interface - let's assume it is SR-IOV
        #
        isl1 = InterfaceSliver()
        # the name is normally set by FIM as '-' concatenation of service name
        isl1.set_name('Interface1')
        # this will be a ServicePort in the network service sliver. It is created by FIM automatically when
        # the user adds a NetworkService to the ASM. The name is set by the FIM as '-' concatenation of service
        # name and peer interface sliver name.
        isl1.set_type(InterfaceType.ServicePort)

        # since this is SR-IOV, orchestrator picks VLAN for this function based on info in advertisement
        # other information is done in the same way it is done for L2 services
        sliver_labels = Labels(vlan='121',
                               local_name='HundredGigE0/0/0/5',
                               device_name='uky-data-sw')

        # capacities (bw in Gbps, burst size is in Mbytes) source: (b)
        sliver_capacities = Capacities(bw=1)

        # assign labels and capacities
        isl1.set_labels(sliver_labels)
        isl1.set_capacities(sliver_capacities)

        #
        # Second interface (let's assume this is a dedicated card)
        #
        isl2 = InterfaceSliver()
        isl2.set_name('Interface2')
        isl2.set_type(InterfaceType.ServicePort)

        # Q: who and how picks the VLAN in this case? I think we discussed having an advertised pool of 'Layer 3
        # vlans' which need to be kept track of and this would be one of them
        # other information is done in the same way it is done for L2 services
        sliver_labels = Labels(vlan='1001',
                               local_name='HundredGigE0/0/0/5',
                               device_name='uky-data-sw')
        sliver_capacities = Capacities(bw=1)

        isl2.set_labels(sliver_labels)
        isl2.set_capacities(sliver_capacities)

        # create interface info object, add populated interfaces to it
        ifi = InterfaceInfo()
        ifi.add_interface(isl1)
        ifi.add_interface(isl2)

        # add interface info object to sliver. All of this happens automagically normally
        sliver.interface_info = ifi

        # set a fake unit reservation
        uid = uuid.uuid3(uuid.NAMESPACE_DNS, 'test_FABNetv6')
        self.unit = Unit(rid=ID(uid=str(uid)))
        self.unit.set_sliver(sliver=sliver)

        #
        # create a service (create needs to parse out sliver information
        # into exact parameters the service ansible script needs)
        #
        r, updated_unit = handler.create(unit=self.unit)
        self.assertEqual(r[Constants.PROPERTY_TARGET_NAME],
                         Constants.TARGET_CREATE)
        self.assertEqual(r[Constants.PROPERTY_ACTION_SEQUENCE_NUMBER], 0)
        self.assertEqual(r[Constants.PROPERTY_TARGET_RESULT_CODE],
                         Constants.RESULT_CODE_OK)

        time.sleep(30)

        #
        # delete - need to make sure the updated unit has the right info to delete the service
        #
        r, updated_unit = handler.delete(updated_unit)
        self.assertEqual(r[Constants.PROPERTY_TARGET_NAME],
                         Constants.TARGET_DELETE)
        self.assertEqual(r[Constants.PROPERTY_ACTION_SEQUENCE_NUMBER], 0)
        self.assertEqual(r[Constants.PROPERTY_TARGET_RESULT_CODE],
                         Constants.RESULT_CODE_OK)
Пример #10
0
    def test_L2Bridge(self):
        # create a NetworkService sliver for L2Bridge
        prop = {
            AmConstants.CONFIG_PROPERTIES_FILE:
            '../config/net_handler_config.yml'
        }

        handler = NetHandler(logger=self.logger, properties=prop)
        #
        # create a network sliver for L2Bridge and its interfaces
        #
        sliver = NetworkServiceSliver()
        # service name (set by user) - only guaranteed unique within a slice
        sliver.set_name('L2BridgeServiceTest')
        # if service name global uniqueness is a requirement use Labels.local_name for that (optional)
        # e.g. concatenate name + res id (or another unique id)
        # sliver.set_labels(Labels().set_fields(local_name='test-l2bridge-shortname'))
        # per @xiyang he uses unit id for service name so this is not needed.
        sliver.set_type(ServiceType.L2Bridge)
        sliver.set_layer(NSLayer.L2)

        # Interface properties
        #
        # The service definitions make a distinction between interface which requires
        # type = parse(InterfaceSliver.Labels.local_name)
        # id = parse(InterfaceSliver.Labels.local_name)
        # outervlan = InterfaceSliver.Labels.vlan
        # innervlan = InterfaceSliver.Labels.inner_vlan
        # bw = InterfaceSliver.Capacities.bw (0 - best-effort)
        # burst size = InterfaceSliver.Capacities.burst_size
        #
        # and STP which in addition also requires NSO device name.
        # In deep network sliver NSO Device name goes on *each* interface, then handler.create can parse
        # out the interfaces and figure out which STP each interface goes with based on that.
        # NSO device name = InterfaceSliver.Labels.device_name
        #
        # The properties of InterfaceSlivers noted above must be copied by Orchestrator from various places
        # a) the switch TrunkPort port the ASM ServicePort maps to in CBM
        # b) the Shared or Dedicated ASM port on the card the ServicePort peers with in ASM
        # c) the Shared or Dedicated CBM port the peer ASM port maps to
        # Below for each property comments indicate where they come from by a, b, c

        # Orchestrator determines peer ports in ASM (between ServicePort and corresponding Shared/Dedicated card port)
        # and sets nodemaps to point from ASM ServicePort to corresponding CBM TrunkPort
        # as well as between Shared/Dedicated ASM port on the NIC and the corresponding CBM Shared/Dedicated port

        #
        # create a small number of Interface slivers, set their properties and link to service
        #
        isl1 = InterfaceSliver()
        # the name is set by FIM as '-' concatenation of service name
        isl1.set_name('Interface1')
        # this will be a ServicePort in the network service sliver. It is created by FIM automatically when
        # the user adds a NetworkService to the ASM. The name is set by the FIM as '-' concatenation of service
        # name and peer interface sliver name.
        isl1.set_type(InterfaceType.ServicePort)

        sliver_labels = Labels()
        sliver_capacities = Capacities()
        # inner_vlan - not used for now - user would fill it in directly on the sliver Labels -
        # need to discuss.
        # sl1labs.set_fields(inner_vlan='3')

        # vlan - source: (c)
        sliver_labels.set_fields(vlan='100')

        # local_name source: (a)
        sliver_labels.set_fields(local_name='HundredGigE0/0/0/17')

        # NSO device name source: (a) - need to find the owner switch of the network service in CBM
        # and take its .name or labels.local_name
        sliver_labels.set_fields(device_name='uky-data-sw')

        # capacities (bw in Gbps, burst size is in Mbytes) source: (b)
        sliver_capacities.set_fields(bw=1)

        # assign labels and capacities
        isl1.set_labels(sliver_labels)
        isl1.set_capacities(sliver_capacities)

        #
        # Second interface (comments for field info origin omitted below)
        #
        isl2 = InterfaceSliver()
        isl2.set_name('Interface2')
        isl2.set_type(InterfaceType.ServicePort)

        sliver_labels = Labels()
        sliver_capacities = Capacities()

        # sliver_labels.set_fields(vlan='102')
        sliver_labels.set_fields(local_name='TwentyFiveGigE0/0/0/23/1')
        sliver_labels.set_fields(device_name='uky-data-sw')

        sliver_capacities.set_fields(bw=1)

        isl2.set_labels(sliver_labels)
        isl2.set_capacities(sliver_capacities)

        # create interface info object, add populated interfaces to it
        ifi = InterfaceInfo()
        ifi.add_interface(isl1)
        ifi.add_interface(isl2)

        # add interface info object to sliver. All of this happens automagically normally
        sliver.interface_info = ifi
        # set a fake unit reservation
        uid = uuid.uuid3(uuid.NAMESPACE_DNS, 'test_L2Bridge')
        self.unit = Unit(rid=ID(uid=str(uid)))
        self.unit.set_sliver(sliver=sliver)

        #
        # create a service (create needs to parse out sliver information
        # into exact parameters the service ansible script needs)
        #
        r, updated_unit = handler.create(unit=self.unit)
        self.assertEqual(r[Constants.PROPERTY_TARGET_NAME],
                         Constants.TARGET_CREATE)
        self.assertEqual(r[Constants.PROPERTY_ACTION_SEQUENCE_NUMBER], 0)
        self.assertEqual(r[Constants.PROPERTY_TARGET_RESULT_CODE],
                         Constants.RESULT_CODE_OK)

        time.sleep(30)

        #
        # delete - need to make sure the updated unit has the right info to delete the service
        #
        r, updated_unit = handler.delete(updated_unit)
        self.assertEqual(r[Constants.PROPERTY_TARGET_NAME],
                         Constants.TARGET_DELETE)
        self.assertEqual(r[Constants.PROPERTY_ACTION_SEQUENCE_NUMBER], 0)
        self.assertEqual(r[Constants.PROPERTY_TARGET_RESULT_CODE],
                         Constants.RESULT_CODE_OK)
Пример #11
0
    def test_L2STS(self):
        # create a NetworkService sliver for L2STS
        prop = {
            AmConstants.CONFIG_PROPERTIES_FILE:
            '../config/net_handler_config.yml'
        }

        handler = NetHandler(logger=self.logger, properties=prop)

        #
        # create a network sliver for L2Bridge and its interfaces
        #
        sliver = NetworkServiceSliver()
        # service name - can we use the sliver name - only guaranteed unique in the slice
        sliver.set_name('L2STSServiceTest')
        sliver.set_type(ServiceType.L2STS)
        sliver.set_layer(NSLayer.L2)

        # ERO
        # first declare a path. Each path is a list of somethings. a2z and z2a maintained separately within Path
        ero_path = Path()

        ero_path.set_symmetric(["10.1.1.1", "10.1.1.2"])
        # default is loose ERO, set strict=True if want otherwise
        ero = ERO(strict=False)
        ero.set(ero_path)
        sliver.set_ero(ero)

        #
        # site A interfaces
        #
        stp_a1 = InterfaceSliver()
        stp_a1.set_name('Interface_A1')
        stp_a1.set_type(InterfaceType.ServicePort)
        sliver_labels = Labels()
        sliver_capacities = Capacities()
        # untagged w/o vlan label set
        sliver_labels.set_fields(local_name='TwentyFiveGigE0/0/0/23/1')
        sliver_labels.set_fields(device_name='lbnl-data-sw')
        sliver_capacities.set_fields(bw=2000)
        stp_a1.set_labels(sliver_labels)
        stp_a1.set_capacities(sliver_capacities)

        #
        # site Z interfaces
        #
        stp_z1 = InterfaceSliver()
        stp_z1.set_name('Interface_Z1')
        stp_z1.set_type(InterfaceType.ServicePort)
        sliver_labels = Labels()
        sliver_capacities = Capacities()
        sliver_labels.set_fields(vlan='235')
        sliver_labels.set_fields(local_name='HundredGigE0/0/0/13')
        sliver_labels.set_fields(device_name='uky-data-sw')
        sliver_capacities.set_fields(bw=1000)
        stp_z1.set_labels(sliver_labels)
        stp_z1.set_capacities(sliver_capacities)

        stp_z2 = InterfaceSliver()
        stp_z2.set_name('Interface_Z2')
        stp_z2.set_type(InterfaceType.ServicePort)
        sliver_labels = Labels()
        sliver_capacities = Capacities()
        # untagged w/o vlan label set
        sliver_labels.set_fields(local_name='TwentyFiveGigE0/0/0/23/2')
        sliver_labels.set_fields(device_name='uky-data-sw')
        sliver_capacities.set_fields(bw=1000)
        stp_z2.set_labels(sliver_labels)
        stp_z2.set_capacities(sliver_capacities)

        # create interface info object, add interfaces to it
        ifi = InterfaceInfo()
        ifi.add_interface(stp_a1)
        ifi.add_interface(stp_z1)
        ifi.add_interface(stp_z2)

        # All of this happens automagically in FIM
        sliver.interface_info = ifi
        uid = uuid.uuid3(uuid.NAMESPACE_DNS, 'test_L2STS')
        self.unit = Unit(rid=ID(uid=str(uid)))
        self.unit.set_sliver(sliver=sliver)

        #
        # create a service
        #
        r, updated_unit = handler.create(unit=self.unit)
        self.assertEqual(r[Constants.PROPERTY_TARGET_NAME],
                         Constants.TARGET_CREATE)
        self.assertEqual(r[Constants.PROPERTY_ACTION_SEQUENCE_NUMBER], 0)
        self.assertEqual(r[Constants.PROPERTY_TARGET_RESULT_CODE],
                         Constants.RESULT_CODE_OK)

        time.sleep(30)

        #
        # delete - need to make sure the updated unit has the right info to delete the service
        #
        r, updated_unit = handler.delete(updated_unit)
        self.assertEqual(r[Constants.PROPERTY_TARGET_NAME],
                         Constants.TARGET_DELETE)
        self.assertEqual(r[Constants.PROPERTY_ACTION_SEQUENCE_NUMBER], 0)
        self.assertEqual(r[Constants.PROPERTY_TARGET_RESULT_CODE],
                         Constants.RESULT_CODE_OK)
Пример #12
0
    def create_unit(include_pci: bool = True,
                    include_image: bool = True,
                    include_name: bool = True,
                    include_instance_name: bool = False,
                    include_ns: bool = False) -> Unit:
        """
        Create a unit
        :param include_pci:
        :param include_image:
        :param include_name:
        :param include_instance_name:
        :param include_ns:
        :return:
        """
        u = Unit(rid=ID(uid="rid-1"))
        sliver = NodeSliver()
        cap = Capacities()
        cap.set_fields(core=4, ram=64, disk=500)
        catalog = InstanceCatalog()
        instance_type = catalog.map_capacities_to_instance(cap=cap)
        cap_hints = CapacityHints().set_fields(instance_type=instance_type)
        sliver.set_properties(
            type=NodeType.VM,
            site="RENC",
            capacity_hints=cap_hints,
            capacity_allocations=catalog.get_instance_capacities(
                instance_type=instance_type))
        sliver.label_allocations = Labels().set_fields(
            instance_parent="renc-w1.fabric-testbed.net")

        if include_name:
            sliver.set_properties(name="n1")

        if include_image:
            sliver.set_properties(image_type='qcow2',
                                  image_ref='default_centos_8')

        if include_pci:
            component = ComponentSliver()
            labels = Labels()
            labels.set_fields(bdf=["0000:41:00.0", "0000:41:00.1"])
            component.set_properties(type=ComponentType.SmartNIC,
                                     model='ConnectX-6',
                                     name='nic1',
                                     label_allocations=labels)
            sliver.attached_components_info = AttachedComponentsInfo()
            sliver.attached_components_info.add_device(device_info=component)

        if include_instance_name:
            sliver.label_allocations.set_fields(instance="instance-001")

        if include_ns:
            sliver.network_service_info = NetworkServiceInfo()
            ns = NetworkServiceSliver()
            ns.interface_info = InterfaceInfo()
            ifs1 = InterfaceSliver()
            c = Capacities()
            c.bw = 100
            c.unit = 1
            l1 = Labels()
            l1.ipv4 = '192.168.11.3'
            l1.vlan = '200'
            l1.local_name = 'p1'
            la_1 = Labels()
            la_1.mac = '0C:42:A1:EA:C7:51'
            la_1.vlan = '200'
            ifs1.capacities = c
            ifs1.labels = l1
            ifs1.label_allocations = la_1

            ifs2 = InterfaceSliver()
            ifs2.capacities = c
            l2 = Labels()
            l2.ipv4 = '192.168.11.2'
            l2.local_name = 'p2'
            la_2 = Labels()
            la_2.mac = '0C:42:A1:EA:C7:52'

            ifs2.labels = l2
            ifs2.label_allocations = la_1

            ns.interface_info.interfaces = {'ifs1': ifs1, 'ifs2': ifs2}
            sliver.network_service_info.network_services = {'ns1': ns}

        u.set_sliver(sliver=sliver)
        return u
Пример #13
0
    def __init__(self, *, name: str, node_id: str = None, topo: Any,
                 etype: ElementType = ElementType.EXISTING,
                 parent_node_id: str = None,
                 interfaces: List[Interface] = None,
                 nstype: ServiceType = None, technology: str = None,
                 **kwargs):
        """
        Don't call this method yourself, call topology.add_network_service()
        node_id will be generated if not provided for experiment topologies

        :param name:
        :param node_id:
        :param topo:
        :param etype: is this supposed to exist or new should be created
        :param parent_node_id: node_id of the parent Node if any (for new components)
        :param interfaces: list of interface objects to connect
        :param nstype: service type if new
        :param technology: service technology
        :param kwargs: any additional properties
        """
        assert name is not None
        assert topo is not None

        site = None
        if etype == ElementType.NEW:
            # node id myst be specified for new nodes in substrate topologies
            if node_id is None:
                node_id = str(uuid.uuid4())
            super().__init__(name=name, node_id=node_id, topo=topo)
            if nstype is None:
                raise TopologyException("When creating new services you must specify ServiceType")
            # cant use isinstance as it would create circular import dependencies
            # We do more careful checks for ExperimentTopologies, but for substrate we let things loose
            if str(self.topo.__class__) == "<class 'fim.user.topology.ExperimentTopology'>" and interfaces:
                sites = self.__validate_nstype_constraints(nstype, interfaces)

                # if a single-site service
                if len(sites) == 1:
                    site = sites.pop()

            sliver = NetworkServiceSliver()
            sliver.node_id = self.node_id
            sliver.set_name(self.name)
            sliver.set_type(nstype)
            sliver.set_site(site)
            # set based on service type
            sliver.set_layer(NetworkServiceSliver.ServiceConstraints[nstype].layer)
            sliver.set_technology(technology)
            sliver.set_properties(**kwargs)
            self.topo.graph_model.add_network_service_sliver(parent_node_id=parent_node_id, network_service=sliver)
            self._interfaces = list()
            if interfaces is not None and len(interfaces) > 0:
                for i in interfaces:
                    # run through guardrails, then connect
                    self.__service_guardrails(sliver, i)
                    self.__connect_interface(interface=i)
        else:
            assert node_id is not None
            super().__init__(name=name, node_id=node_id, topo=topo)
            # check that this node exists
            existing_node_id = self.topo.\
                graph_model.find_node_by_name(node_name=name,
                                              label=ABCPropertyGraph.CLASS_NetworkService)
            if existing_node_id != node_id:
                raise TopologyException(f'Service name {name} node id does not match the expected node id.')
            # collect a list of interface nodes it attaches to
            interface_list = self.topo.graph_model.get_all_ns_or_link_connection_points(link_id=self.node_id)
            name_id_tuples = list()
            # need to look up their names - a bit inefficient, need to think about this /ib
            for iff in interface_list:
                _, props = self.topo.graph_model.get_node_properties(node_id=iff)
                name_id_tuples.append((props[ABCPropertyGraph.PROP_NAME], iff))
            self._interfaces = [Interface(node_id=tup[1], topo=topo, name=tup[0]) for tup in name_id_tuples]
Пример #14
0
 def list_properties() -> Tuple[str]:
     return NetworkServiceSliver.list_properties()
Пример #15
0
    def allocate_ifs(
            self, *, requested_ns: NetworkServiceSliver,
            requested_ifs: InterfaceSliver, owner_switch: NodeSliver,
            mpls_ns: NetworkServiceSliver, bqm_ifs_id: str,
            existing_reservations: List[ABCReservationMixin]
    ) -> InterfaceSliver:
        """
        Allocate Interface Sliver
        - For L2 services, validate the VLAN tag specified is within the allowed range
        - For L3 services,
            - grab the VLAN from BQM Site specific NetworkService
            - exclude the VLAN already assigned to other Interface Sliver on the same port
            - allocate the first available VLAN to the Interface Sliver
        :param requested_ns: Requested NetworkService
        :param requested_ifs: Requested Interface Sliver
        :param owner_switch: BQM Owner site switch identified to serve the InterfaceSliver
        :param mpls_ns: BQM MPLS NetworkService identified to serve the InterfaceSliver
        :param bqm_ifs_id: BQM InterfaceSliver identified to serve the InterfaceSliver
        :param existing_reservations: Existing Reservations which also are served by the owner switch
        :return Interface Sliver updated with the allocated VLAN tag for FABNetv4 and FABNetv6 services
        :raises Exception if vlan tag range is not in the valid range for L2 services
        Return the sliver updated with the VLAN
        """
        if requested_ns.get_layer() == NSLayer.L2:
            delegation_id, delegated_label = self._get_delegations(
                lab_cap_delegations=mpls_ns.get_label_delegations())
            vlans = None
            if delegated_label.vlan_range is not None:
                vlans = delegated_label.vlan_range.split("-")
            if vlans is not None and requested_ifs.labels.vlan is not None and \
                    int(vlans[0]) > int(requested_ifs.labels.vlan) > int(vlans[1]):
                raise BrokerException(
                    error_code=ExceptionErrorCode.FAILURE,
                    msg=f"Vlan for L2 service is outside the allowed range "
                    f"{mpls_ns.label_delegations.vlan_range}")

        else:
            for ns in owner_switch.network_service_info.network_services.values(
            ):
                if requested_ns.get_type() == ns.get_type():
                    # Grab Label Delegations
                    delegation_id, delegated_label = self._get_delegations(
                        lab_cap_delegations=ns.get_label_delegations())

                    # Get the VLAN range
                    vlans = None
                    vlan_range = None
                    if delegated_label.vlan_range is not None:
                        vlans = delegated_label.vlan_range.split("-")
                        vlan_range = list(range(int(vlans[0]), int(vlans[1])))

                    # Exclude the already allocated VLANs and subnets
                    if existing_reservations is not None:
                        for reservation in existing_reservations:
                            # For Active or Ticketed or Ticketing reservations; reduce the counts from available
                            allocated_sliver = None
                            if reservation.is_ticketing(
                            ) and reservation.get_approved_resources(
                            ) is not None:
                                allocated_sliver = reservation.get_approved_resources(
                                ).get_sliver()

                            if (reservation.is_active() or reservation.is_ticketed()) and \
                                    reservation.get_resources() is not None:
                                allocated_sliver = reservation.get_resources(
                                ).get_sliver()

                            self.logger.debug(
                                f"Existing res# {reservation.get_reservation_id()} allocated: {allocated_sliver}"
                            )

                            if allocated_sliver is None:
                                continue

                            # Ignore reservations for L2 services
                            if allocated_sliver.get_type() != ServiceType.FABNetv4 or \
                                    allocated_sliver.get_type() != ServiceType.FABNetv6:
                                continue

                            if allocated_sliver.interface_info is None or allocated_sliver.interface_info.interfaces is None:
                                continue

                            for allocated_ifs in allocated_sliver.interface_info.interfaces.values(
                            ):
                                # Ignore the Interface Slivers not on the same port
                                if allocated_ifs.get_node_map(
                                )[0] != bqm_ifs_id:
                                    continue

                                self.logger.debug(
                                    f"Excluding already allocated VLAN: "
                                    f"{allocated_ifs.label_allocations.vlan} to "
                                    f"res# {reservation.get_reservation_id()}")

                                # Exclude VLANs on the allocated on the same port
                                if vlan_range is not None and allocated_ifs.label_allocations.vlan in vlan_range:
                                    vlan_range.remove(
                                        int(allocated_sliver.label_allocations.
                                            vlan))

                    # Allocate the first available VLAN
                    if vlan_range is not None:
                        requested_ifs.labels.vlan = str(vlan_range[0])
                        requested_ifs.label_allocations = Labels(
                            vlan=str(vlan_range[0]))
                    break
        return requested_ifs
Пример #16
0
    def allocate(
        self, *, rid: ID, requested_ns: NetworkServiceSliver,
        owner_switch: NodeSliver,
        existing_reservations: List[ABCReservationMixin]
    ) -> NetworkServiceSliver:
        """
        Allocate Network Service Sliver (Only for L3 Service)
            - grab the /17 or /48 from BQM Site specific NetworkService
            - divide it into /24 or /64 subnets
            - exclude the 1st subnet (reserved for control plane)
            - exclude the subnets already assigned to other V3/V4 NetworkService on the same owner switch
            - allocate the first available subnet to the NetworkService
        :param requested_ns: Requested NetworkService
        :param owner_switch: BQM Owner site switch identified to serve the NetworkService
        :param existing_reservations: Existing Reservations which also are served by the owner switch
        :return NetworkService updated with the allocated subnet for FABNetv4 and FABNetv6 services
        Return the sliver updated with the subnet
        """
        if requested_ns.get_type(
        ) != ServiceType.FABNetv4 and requested_ns.get_type(
        ) != ServiceType.FABNetv6:
            return requested_ns

        for ns in owner_switch.network_service_info.network_services.values():
            if requested_ns.get_type() == ns.get_type():
                # Grab Label Delegations
                delegation_id, delegated_label = self._get_delegations(
                    lab_cap_delegations=ns.get_label_delegations())

                subnet_list = None
                # Get Subnet
                if ns.get_type() == ServiceType.FABNetv6:
                    ip_network = IPv6Network(delegated_label.ipv6_subnet)
                    subnet_list = list(ip_network.subnets(new_prefix=64))

                elif ns.get_type() == ServiceType.FABNetv4:
                    ip_network = IPv4Network(delegated_label.ipv4_subnet)
                    subnet_list = list(ip_network.subnets(new_prefix=24))

                # Exclude the 1st subnet as it is reserved for control plane
                subnet_list.pop(0)

                # Exclude the already allocated VLANs and subnets
                for reservation in existing_reservations:
                    if rid == reservation.get_reservation_id():
                        continue
                    # For Active or Ticketed or Ticketing reservations; reduce the counts from available
                    allocated_sliver = None
                    if reservation.is_ticketing(
                    ) and reservation.get_approved_resources() is not None:
                        allocated_sliver = reservation.get_approved_resources(
                        ).get_sliver()

                    if (reservation.is_active() or reservation.is_ticketed()) and \
                            reservation.get_resources() is not None:
                        allocated_sliver = reservation.get_resources(
                        ).get_sliver()

                    self.logger.debug(
                        f"Existing res# {reservation.get_reservation_id()} allocated: {allocated_sliver}"
                    )

                    if allocated_sliver is None:
                        continue

                    if allocated_sliver.get_type() != requested_ns.get_type():
                        continue

                    if allocated_sliver.get_type() == ServiceType.FABNetv4:
                        subnet_to_remove = IPv4Network(
                            allocated_sliver.get_gateway().lab.ipv4_subnet)
                        subnet_list.remove(subnet_to_remove)
                        self.logger.debug(
                            f"Excluding already allocated IP4Subnet: "
                            f"{allocated_sliver.get_gateway().lab.ipv4_subnet}"
                            f" to res# {reservation.get_reservation_id()}")

                    elif allocated_sliver.get_gateway(
                    ).lab.ipv6_subnet is not None:
                        subnet_to_remove = IPv6Network(
                            allocated_sliver.get_gateway().lab.ipv6_subnet)
                        subnet_list.remove(subnet_to_remove)
                        self.logger.debug(
                            f"Excluding already allocated IPv6Subnet: "
                            f"{allocated_sliver.get_gateway().lab.ipv6_subnet}"
                            f" to res# {reservation.get_reservation_id()}")

                gateway_labels = Labels()
                if requested_ns.get_type() == ServiceType.FABNetv4:
                    gateway_labels.ipv4_subnet = subnet_list[0].with_prefixlen
                    gateway_labels.ipv4 = str(next(subnet_list[0].hosts()))

                elif requested_ns.get_type() == ServiceType.FABNetv6:
                    gateway_labels.ipv6_subnet = subnet_list[0].with_prefixlen
                    gateway_labels.ipv6 = str(next(subnet_list[0].hosts()))

                requested_ns.gateway = Gateway(lab=gateway_labels)
                break
        return requested_ns