def set_fields(self, **kwargs):
     """
     Universal integer setter for all fields.
     Values should be non-negative integers. Throws a RuntimeError
     if you try to set a non-existent field.
     :param kwargs:
     :return: self to support call chaining
     """
     for k, v in kwargs.items():
         try:
             # will toss an exception if field is not defined
             self.__getattribute__(k)
             if k == Constants.PROP_CAPACITIES or k == Constants.PROP_ALLOCATED_CAPACITIES:
                 c = Capacities()
                 v = c.from_json(json_string=v)
             elif k == Constants.PROP_LABELS or k == Constants.PROP_ALLOCATED_LABELS:
                 l = Labels()
                 v = l.from_json(json_string=v)
             elif k == Constants.PROP_CAPACITY_HINTS:
                 ch = CapacityHints()
                 v = ch.from_json(json_string=v)
             self.__setattr__(k, v)
         except AttributeError:
             raise RuntimeError(
                 f"Unable to set field {k} of reservation, no such field available"
             )
     return self
Beispiel #2
0
    def testCollector4(self):
        # test from ASM
        az = ResourceAuthZAttributes()
        print(az)
        t = ExperimentTopology()
        n1 = t.add_node(name='n1', site='RENC', capacities=Capacities(core=1, ram=10, disk=25))
        c1 = n1.add_component(name='c1', model_type=ComponentModelType.SmartNIC_ConnectX_6)
        c2 = n1.add_component(name='c2', model_type=ComponentModelType.SharedNIC_ConnectX_6)
        n1.add_component(name='c3', model_type=ComponentModelType.NVME_P4510)
        n2 = t.add_node(name='n2', site='UKY', capacities=Capacities(core=10, ram=10, disk=35))
        c4 = n2.add_component(name='c4', model_type=ComponentModelType.SmartNIC_ConnectX_5)
        s1 = t.add_network_service(name='s1', nstype=ServiceType.L2PTP,
                                   interfaces=[c1.interface_list[0], c4.interface_list[0]],
                                   capacities=Capacities(bw=12))
        fac1 = t.add_facility(name='RENCI-DTN', site='RENC', capacities=Capacities(bw=10))
        sfac = t.add_network_service(name='s-fac', nstype=ServiceType.L2STS,
                                     interfaces=[fac1.interface_list[0],
                                                 c2.interface_list[0]])

        serial_asm = t.serialize()

        asm_imp = NetworkXGraphImporter()
        pgraph = asm_imp.import_graph_from_string(graph_string=serial_asm)
        asm = NetworkXASMFactory.create(pgraph)

        # this will take just about anything - an ASM, a Node, a NetworkService,
        # a sliver. So it can be called in AM, Broker or Orchestrator
        #
        # However to get things like peering sites, facility sites, it is best to
        # call it on the ASM (in Orchestrator)
        az.collect_resource_attributes(source=asm)
        # generally you also want to set the lifetime (provided externally)
        now = datetime.now(timezone.utc)
        delta = timedelta(days=13, hours=11, minutes=7, seconds=4, milliseconds=10)
        future = now + delta
        az.set_lifetime(future)
        print(az)
        self.assertTrue('SmartNIC' in az.attributes[ResourceAuthZAttributes.RESOURCE_COMPONENT])
        self.assertTrue('NVME' in az.attributes[ResourceAuthZAttributes.RESOURCE_COMPONENT])
        self.assertTrue(25 in az.attributes[ResourceAuthZAttributes.RESOURCE_DISK])
        self.assertTrue(12 in az.attributes[ResourceAuthZAttributes.RESOURCE_BW])
        self.assertTrue('RENC' in az.attributes[ResourceAuthZAttributes.RESOURCE_SITE])
        self.assertTrue('UKY' in az.attributes[ResourceAuthZAttributes.RESOURCE_SITE])
        self.assertTrue('P13DT11H7M4S' in az.attributes[ResourceAuthZAttributes.RESOURCE_LIFETIME])
        self.assertEqual(az.attributes[ResourceAuthZAttributes.RESOURCE_TYPE], ["sliver"])

        az.set_subject_attributes(subject_id="*****@*****.**", project=["Project1"],
                                  project_tag=["Tag1", "Tag2"])
        az.set_action("create")
        az.set_resource_subject_and_project(subject_id="*****@*****.**", project="Project1")

        # convert to full PDP request after adding attributes
        req_json = az.transform_to_pdp_request()
        req_dict = az.transform_to_pdp_request(as_json=False)

        print(f'4: JSON {req_json}')
Beispiel #3
0
    def create_unit(include_pci: bool = True,
                    include_image: bool = True,
                    include_name: bool = True,
                    include_instance_name: bool = False) -> Unit:
        """
        Create a unit
        :param include_pci:
        :param include_image:
        :param include_name:
        :param include_instance_name:
        :return:
        """
        u = Unit(rid=ID(uid='rid-1'))
        sliver = NodeSliver()
        cap = Capacities()
        cap.set_fields(core=2, ram=8, disk=10)
        sliver.set_properties(type=NodeType.VM,
                              site="RENC",
                              capacity_allocations=cap)
        sliver.label_allocations = Labels().set_fields(
            instance_parent="renc-w3")
        catalog = InstanceCatalog()
        instance_type = catalog.map_capacities_to_instance(cap=cap)
        cap_hints = CapacityHints().set_fields(instance_type=instance_type)
        sliver.set_properties(
            capacity_hints=cap_hints,
            capacity_allocations=catalog.get_instance_capacities(
                instance_type=instance_type))

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

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

        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-5',
                                     name='nic1',
                                     label_allocations=labels)
            #labels.set_fields(bdf="0000:81:00.0")
            #component.set_properties(type=ComponentType.GPU, model='Tesla T4', name='nic12', 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")

        u.set_sliver(sliver=sliver)
        return u
 def testInstanceCatalog(self):
     cata = InstanceCatalog()
     cap = Capacities(ram=20, cpu=1, core=9, disk=110)
     c = cata.map_capacities_to_instance(cap=cap)
     cap1 = cata.get_instance_capacities(instance_type=c)
     self.assertTrue(cap1.core > cap.core and cap1.ram > cap.ram
                     and cap1.disk > cap.disk)
     cap = Capacities(ram=20, cpu=1, core=9, disk=110)
     c = cata.map_capacities_to_instance(cap=cap)
     cap1 = cata.get_instance_capacities(instance_type=c)
     self.assertTrue(cap1.core > cap.core and cap1.ram > cap.ram
                     and cap1.disk > cap.disk)
Beispiel #5
0
    def testCapacityAssignment(self):
        c = Capacities(cpu=1, core=2)

        self.assertEqual(c.cpu, 1)
        self.assertEqual(c.core, 2)

        s = '{"core": 32, "disk": 3000, "ram": 384, "unit": 1}'
        c1 = Capacities.from_json(s)
        self.assertEqual(c1.unit, 1)
        self.assertEqual(c1.ram, 384)
        # because we sort the dict
        self.assertEqual(c1.to_json(), s)
        self.assertEqual(c1.core, 32)
    def __occupied_node_capacity(
        self, *, node_id: str
    ) -> Tuple[Capacities, Dict[ComponentType, Dict[str, Capacities]]]:
        """
        Figure out the total capacity occupied in the network node and return a tuple of
        capacities occupied in this node and a dict of component capacities that are occupied
        organized by component type and model.
        """
        assert node_id is not None
        # get existing reservations for this node
        existing_reservations = self.actor.get_plugin().get_database().\
            get_reservations_by_graph_node_id(graph_node_id=node_id)

        # node capacities
        occupied_capacities = Capacities()
        occupied_component_capacities = defaultdict(dict)
        # Remove allocated capacities to the reservations
        if existing_reservations is not None:
            for reservation in existing_reservations:
                # For Active or Ticketed or Ticketing reservations; compute 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()

                if allocated_sliver is not None:
                    occupied_capacities = occupied_capacities + allocated_sliver.get_capacities(
                    )

                    if allocated_sliver.attached_components_info is not None:
                        for allocated_component in allocated_sliver.attached_components_info.devices.values(
                        ):
                            rt = allocated_component.resource_type
                            rm = allocated_component.resource_model
                            if occupied_component_capacities[rt].get(
                                    rm) is None:
                                occupied_component_capacities[rt][
                                    rm] = Capacities()

                            occupied_component_capacities[rt][rm] = occupied_component_capacities[rt][rm] + \
                                                          allocated_component.capacity_allocations

        return occupied_capacities, occupied_component_capacities
Beispiel #7
0
    def testPools(self):
        p = Pool(atype=DelegationType.LABEL, pool_id="pool1")
        p.set_delegation_id(delegation_id="del1")
        p.set_defined_on(node_id="node1")
        p.set_defined_for(node_id_list=["node4"])
        p.add_defined_for(node_ids=["node2", "node3", "node1"])
        p.set_pool_details(caporlab=Capacities(cpu=2, ram=1024))

        pp = Pools(atype=DelegationType.LABEL)
        pp.add_pool(pool=p)
        pp.build_index_by_delegation_id()
        p1l = pp.get_pools_by_delegation_id(delegation_id="del1")
        p2 = pp.get_pool_by_id(pool_id="pool1")
        assert p2 in p1l
 def build_sliver(self) -> BaseSliver:
     node_sliver = NodeSliver()
     node_sliver.resource_type = NodeType.VM
     node_sliver.node_id = "test-slice-node-1"
     cap = Capacities(core=4, ram=64, disk=500)
     catalog = InstanceCatalog()
     instance_type = catalog.map_capacities_to_instance(cap=cap)
     cap_hints = CapacityHints(instance_type=instance_type)
     node_sliver.set_properties(name="node-1", type=NodeType.VM, site="RENC",
                                capacities=cap, image_type='qcow2', image_ref='default_centos_8',
                                capacity_hints=cap_hints)
     node_sliver.set_capacity_allocations(cap=catalog.get_instance_capacities(instance_type=instance_type))
     node_map = tuple([self.arm.graph_id, 'HX6VQ53'])
     node_sliver.set_node_map(node_map=node_map)
     return node_sliver
 def build_sliver(self) -> NodeSliver:
     node_sliver = NodeSliver()
     node_sliver.resource_type = NodeType.VM
     node_sliver.node_id = "test-slice-node-1"
     cap = Capacities(core=4, ram=64, disk=500)
     catalog = InstanceCatalog()
     instance_type = catalog.map_capacities_to_instance(cap=cap)
     cap_hints = CapacityHints(instance_type=instance_type)
     node_sliver.set_properties(name="node-1",
                                type=NodeType.VM,
                                site="RENC",
                                capacities=cap,
                                image_type='qcow2',
                                image_ref='default_centos_8',
                                capacity_hints=cap_hints)
     return node_sliver
    def __check_component_labels_and_capacities(
            self, *, available_component: ComponentSliver, graph_id: str,
            requested_component: ComponentSliver) -> ComponentSliver:
        """
        Check if available component capacities, labels to match requested component
        :param available_component: available component
        :param graph_id: BQM graph id
        :param requested_component: requested component
        :return: requested component annotated with properties in case of success, None otherwise
        """
        if requested_component.get_model() is not None and \
                requested_component.get_model() != available_component.get_model():
            return requested_component

        # Checking capacity for component
        delegation_id, delegated_capacity = self._get_delegations(
            lab_cap_delegations=available_component.get_capacity_delegations())

        # Delegated capacity would have been decremented already to exclude allocated shared NICs
        if delegated_capacity.unit < 1:
            message = f"Insufficient Capacities for component: {requested_component}"
            self.logger.error(message)
            raise BrokerException(
                error_code=ExceptionErrorCode.INSUFFICIENT_RESOURCES,
                msg=f"{message}")

        requested_component.capacity_allocations = Capacities(unit=1)

        # Check labels
        delegation_id, delegated_label = self._get_delegations(
            lab_cap_delegations=available_component.get_label_delegations())

        if requested_component.get_type() == ComponentType.SharedNIC:
            requested_component = self.__update_shared_nic_labels_and_capacities(
                available_component=available_component,
                requested_component=requested_component)
        else:
            requested_component.label_allocations = delegated_label
            if requested_component.get_type() == ComponentType.SmartNIC:
                requested_component = self.__update_smart_nic_labels_and_capacities(
                    available_component=available_component,
                    requested_component=requested_component)

        node_map = tuple([graph_id, available_component.node_id])
        requested_component.set_node_map(node_map=node_map)

        return requested_component
    def build_ifs_from_props(node_props: dict) -> InterfaceSliver:
        """
        Build Interface Sliver from the node properties
        @param node_props Node properties
        @return Interface Sliver
        """
        ifs = InterfaceSliver()
        ifs.node_id = node_props[ABCPropertyGraph.NODE_ID]
        cap_json = node_props.get(ABCPropertyGraph.PROP_CAPACITIES, None)
        labels_json = node_props.get(ABCPropertyGraph.PROP_LABELS, None)
        ifs.set_properties(name=node_props[ABCPropertyGraph.PROP_NAME],
                           type=node_props[ABCPropertyGraph.PROP_TYPE])
        if cap_json is not None:
            ifs.set_capacities(cap=Capacities().from_json(cap_json))

        if labels_json is not None:
            ifs.set_labels(lab=Labels().from_json(labels_json))
        return ifs
Beispiel #12
0
    def testDelegationsSerDes(self):
        d1 = Delegation(atype=DelegationType.LABEL,
                        aformat=DelegationFormat.SinglePool,
                        delegation_id='del1')
        d2 = Delegation(atype=DelegationType.LABEL,
                        aformat=DelegationFormat.PoolDefinition,
                        delegation_id='del2',
                        pool_id='pool1')
        d3 = Delegation(atype=DelegationType.LABEL,
                        aformat=DelegationFormat.PoolReference,
                        delegation_id='del3',
                        pool_id='pool1')
        ds = Delegations(atype=DelegationType.LABEL)
        d1.set_details(Labels(vlan_range='1-100'))
        d2.set_details(Labels(vlan_range='101-200'))
        with self.assertRaises(DelegationException) as de:
            d2.set_details(Capacities(unit=1))

        with self.assertRaises(DelegationException) as de:
            d3.set_details(Labels(vlan_range='100-200'))

        ds.add_delegations(d1)
        ds.add_delegations(d2, d3)

        json_str = ds.to_json()

        #print(json_str)

        ds1 = Delegations.from_json(json_str=json_str,
                                    atype=DelegationType.LABEL)

        self.assertEqual(ds1.delegations['del1'].get_details().vlan_range,
                         '1-100')
        self.assertEqual(ds1.delegations['del2'].get_format(),
                         DelegationFormat.PoolDefinition)
        self.assertEqual(ds1.delegations['del3'].get_format(),
                         DelegationFormat.PoolReference)

        with self.assertRaises(AssertionError) as de:
            d3 = Delegation(atype=DelegationType.CAPACITY,
                            aformat=DelegationFormat.PoolReference,
                            delegation_id='del3',
                            pool_id='pool1')
            ds.add_delegations(d3)
    def testCapacitiesLabels(self):
        ns = NodeSliver()
        cap_hint = CapacityHints(instance_type='blah')
        lab = Labels(vlan_range='1-4096')
        ns.set_properties(capacities=Capacities(unit=1, core=2), labels=lab, capacity_hints=cap_hint)
        assert(ns.get_capacity_hints().instance_type == 'blah')
        assert(ns.get_labels().vlan_range == '1-4096')
        assert(ns.get_capacities().core == 2)

        with self.assertRaises(LabelException):
            Labels(vlan_range='1-8000')

        with self.assertRaises(LabelException):
            Labels(asn='600000')

        with self.assertRaises(LabelException):
            Labels(vlan='4098')

        with self.assertRaises(LabelException):
            Labels(inner_vlan='6000')
    def build_sliver_with_components(self) -> NodeSliver:
        node_sliver = NodeSliver()
        node_sliver.resource_type = NodeType.VM
        node_sliver.node_id = "test-slice-node-1"
        cap = Capacities(core=4, ram=64, disk=500)
        catalog = InstanceCatalog()
        instance_type = catalog.map_capacities_to_instance(cap=cap)
        cap_hints = CapacityHints(instance_type=instance_type)
        node_sliver.set_properties(name="node-1",
                                   type=NodeType.VM,
                                   site="RENC",
                                   capacities=cap,
                                   image_type='qcow2',
                                   image_ref='default_centos_8',
                                   capacity_hints=cap_hints)
        component_sliver = ComponentSliver()
        component_sliver.set_properties(type=ComponentType.SmartNIC,
                                        model='ConnectX-6',
                                        name='nic1')
        node_sliver.attached_components_info = AttachedComponentsInfo()
        node_sliver.attached_components_info.add_device(
            device_info=component_sliver)

        return node_sliver
    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
Beispiel #16
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)
Beispiel #17
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)
Beispiel #18
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)
Beispiel #19
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)
    def plug_produce_bqm(self, *, cbm: ABCCBMPropertyGraph,
                         **kwargs) -> ABCBQMPropertyGraph:
        """
        Take a CBM, sort nodes by site, aggregate servers, components and interfaces to
        create a site-based advertisement. Use a NetworkX-based implementation.
        :param cbm:
        :param kwargs:
        :return:
        """
        if kwargs.get('query_level',
                      None) is None or kwargs['query_level'] != 1:
            return cbm.clone_graph(new_graph_id=str(uuid.uuid4()))

        # do a one-pass aggregation of servers, their components and interfaces
        # this includes facilities
        nnodes = cbm.get_all_nodes_by_class(
            label=ABCPropertyGraph.CLASS_NetworkNode)
        slivers_by_site = defaultdict(list)
        for n in nnodes:
            # build deep slivers for each advertised server, aggregate by site
            node_sliver = cbm.build_deep_node_sliver(node_id=n)
            slivers_by_site[node_sliver.site].append(node_sliver)

        # create a new blank Aggregated BQM NetworkX graph
        abqm = NetworkXAggregateBQM(
            graph_id=str(uuid.uuid4()),
            importer=NetworkXGraphImporter(logger=self.logger),
            logger=self.logger)

        site_to_composite_node_id = dict()
        site_to_ns_node_id = dict()
        facilities_by_site = defaultdict(list)
        for s, ls in slivers_by_site.items():
            # add up capacities and delegated capacities, skip labels for now
            # count up components and figure out links between site

            site_sliver = CompositeNodeSliver()
            # count what is taken
            site_sliver.capacity_allocations = Capacities()
            # count what is available
            site_sliver.capacities = Capacities()
            site_sliver.resource_name = s
            site_sliver.resource_type = NodeType.Server
            site_sliver.node_id = str(uuid.uuid4())
            # available components organized by [type][model]
            site_comps_by_type = defaultdict(dict)
            # occupied component capacities organized by [type][model] into lists (by server)
            site_allocated_comps_caps_by_type = defaultdict(dict)

            loc = None
            for sliver in ls:
                if sliver.get_type() != NodeType.Server:
                    # skipping NAS, Facility and dataplane switches
                    if sliver.get_type() == NodeType.Facility:
                        # keep track of facilities for each site
                        facilities_by_site[s].append(sliver)
                    continue
                if self.DEBUG_FLAG:
                    # for debugging and running in a test environment
                    allocated_comp_caps = dict()
                else:
                    # query database for everything taken on this node
                    allocated_caps, allocated_comp_caps = self.__occupied_node_capacity(
                        node_id=sliver.node_id)
                    site_sliver.capacity_allocations = site_sliver.capacity_allocations + allocated_caps

                # get the location if available
                if loc is None:
                    loc = sliver.get_location()

                # calculate available node capacities based on delegations
                if sliver.get_capacity_delegations() is not None:
                    # CBM only has one delegation if it has one
                    _, delegation = sliver.get_capacity_delegations(
                    ).get_sole_delegation()
                    # FIXME: skip pool definitions and references for now
                    if delegation.get_format() == DelegationFormat.SinglePool:
                        site_sliver.capacities = site_sliver.capacities + \
                            delegation.get_details()

                # merge allocated component capacities
                for kt, v in allocated_comp_caps.items():
                    for km, vcap in v.items():
                        if site_allocated_comps_caps_by_type[kt].get(
                                km) is None:
                            site_allocated_comps_caps_by_type[kt][
                                km] = Capacities()
                        site_allocated_comps_caps_by_type[kt][km] = site_allocated_comps_caps_by_type[kt][km] + \
                                                                    vcap

                # collect available components in lists by type and model for the site (for later aggregation)
                if sliver.attached_components_info is None:
                    continue
                for comp in sliver.attached_components_info.list_devices():
                    rt = comp.resource_type
                    rm = comp.resource_model
                    if site_comps_by_type[rt].get(rm) is None:
                        site_comps_by_type[rt][rm] = list()
                    site_comps_by_type[rt][rm].append(comp)

            # set location to whatever is available
            site_sliver.set_location(loc)
            site_sliver.set_site(s)

            # create a Composite node for every site
            site_to_composite_node_id[s] = site_sliver.node_id
            site_props = abqm.node_sliver_to_graph_properties_dict(site_sliver)
            abqm.add_node(node_id=site_sliver.node_id,
                          label=ABCPropertyGraph.CLASS_CompositeNode,
                          props=site_props)
            # add a network service
            ns_id = str(uuid.uuid4())
            site_to_ns_node_id[s] = ns_id
            ns_props = {
                ABCPropertyGraph.PROP_NAME: s + '_ns',
                ABCPropertyGraph.PROP_TYPE: str(ServiceType.MPLS)
            }
            abqm.add_node(node_id=ns_id,
                          label=ABCPropertyGraph.CLASS_NetworkService,
                          props=ns_props)
            abqm.add_link(node_a=site_sliver.node_id,
                          rel=ABCPropertyGraph.REL_HAS,
                          node_b=ns_id)

            # create a component sliver for every component type/model pairing
            # and add a node for it linking back to site node
            for ctype, cdict in site_comps_by_type.items():
                for cmodel, comp_list in cdict.items():
                    comp_sliver = ComponentSliver()
                    # count what is available
                    comp_sliver.capacities = Capacities()
                    # count what is taken (ignore those type/model pairings that were unused)
                    comp_sliver.capacity_allocations = site_allocated_comps_caps_by_type[ctype].get(cmodel) or \
                                                       Capacities()
                    comp_sliver.set_type(ctype)
                    comp_sliver.set_model(cmodel)
                    comp_sliver.set_name(str(ctype) + '-' + cmodel)
                    for comp in comp_list:
                        comp_sliver.capacities = comp_sliver.capacities + comp.capacities
                    comp_node_id = str(uuid.uuid4())
                    comp_props = abqm.component_sliver_to_graph_properties_dict(
                        comp_sliver)
                    abqm.add_node(node_id=comp_node_id,
                                  label=ABCPropertyGraph.CLASS_Component,
                                  props=comp_props)
                    abqm.add_link(node_a=site_sliver.node_id,
                                  rel=ABCPropertyGraph.REL_HAS,
                                  node_b=comp_node_id)

        # get all intersite links - add them to the aggregated BQM graph
        intersite_links = cbm.get_intersite_links()
        for l in intersite_links:
            source_switch = l[0]
            sink_switch = l[2]
            link = l[1]
            source_site = l[3]
            sink_site = l[4]
            source_cp = l[5]
            sink_cp = l[6]
            _, cbm_source_cp_props = cbm.get_node_properties(node_id=source_cp)
            _, cbm_sink_cp_props = cbm.get_node_properties(node_id=sink_cp)
            _, cbm_link_props = cbm.get_node_properties(node_id=link)
            # add connection point, link, connection point between two NetworkServices
            assert (site_to_ns_node_id.get(source_site) is not None
                    and site_to_ns_node_id.get(sink_site) is not None)
            source_cp_id = str(uuid.uuid4())
            sink_cp_id = str(uuid.uuid4())
            source_cp_props = {
                ABCPropertyGraph.PROP_NAME:
                "_".join([source_site, sink_site]),
                ABCPropertyGraph.PROP_TYPE:
                str(InterfaceType.TrunkPort),
                ABCPropertyGraph.PROP_CLASS:
                ABCPropertyGraph.CLASS_ConnectionPoint,
                ABCPropertyGraph.PROP_LABELS:
                cbm_source_cp_props.get(ABCPropertyGraph.PROP_LABELS),
                ABCPropertyGraph.PROP_CAPACITIES:
                cbm_source_cp_props.get(ABCPropertyGraph.PROP_CAPACITIES)
            }
            source_cp_props = {k: v for (k, v) in source_cp_props.items() if v}

            abqm.add_node(node_id=source_cp_id,
                          label=ABCPropertyGraph.CLASS_ConnectionPoint,
                          props=source_cp_props)
            # FIXME: CP names may not be unique if we are dealing with a multigraph
            sink_cp_props = {
                ABCPropertyGraph.PROP_NAME:
                "_".join([sink_site, source_site]),
                ABCPropertyGraph.PROP_TYPE:
                str(InterfaceType.TrunkPort),
                ABCPropertyGraph.PROP_CLASS:
                ABCPropertyGraph.CLASS_ConnectionPoint,
                ABCPropertyGraph.PROP_LABELS:
                cbm_sink_cp_props.get(ABCPropertyGraph.PROP_LABELS),
                ABCPropertyGraph.PROP_CAPACITIES:
                cbm_sink_cp_props.get(ABCPropertyGraph.PROP_CAPACITIES)
            }
            sink_cp_props = {k: v for (k, v) in sink_cp_props.items() if v}
            abqm.add_node(node_id=sink_cp_id,
                          label=ABCPropertyGraph.CLASS_ConnectionPoint,
                          props=sink_cp_props)
            # selectively replicate link node and its properties from CBM
            new_link_props = {
                ABCPropertyGraph.PROP_NAME:
                cbm_link_props[ABCPropertyGraph.PROP_NAME],
                ABCPropertyGraph.PROP_TYPE:
                cbm_link_props[ABCPropertyGraph.PROP_TYPE],
                ABCPropertyGraph.PROP_CLASS:
                cbm_link_props[ABCPropertyGraph.PROP_CLASS],
                ABCPropertyGraph.PROP_LAYER:
                cbm_link_props[ABCPropertyGraph.PROP_LAYER]
            }
            abqm.add_node(node_id=link,
                          label=ABCPropertyGraph.CLASS_Link,
                          props=new_link_props)
            # connect them together
            abqm.add_link(node_a=site_to_ns_node_id[source_site],
                          rel=ABCPropertyGraph.REL_CONNECTS,
                          node_b=source_cp_id)
            abqm.add_link(node_a=source_cp_id,
                          rel=ABCPropertyGraph.REL_CONNECTS,
                          node_b=link)
            abqm.add_link(node_a=link,
                          rel=ABCPropertyGraph.REL_CONNECTS,
                          node_b=sink_cp_id)
            abqm.add_link(node_a=sink_cp_id,
                          rel=ABCPropertyGraph.REL_CONNECTS,
                          node_b=site_to_ns_node_id[sink_site])

        # link facilities to their sites
        for s, lf in facilities_by_site.items():
            # multiple facilities per site possible
            for fac_sliver in lf:
                fac_nbs = cbm.get_first_and_second_neighbor(
                    node_id=fac_sliver.node_id,
                    rel1=ABCPropertyGraph.REL_HAS,
                    node1_label=ABCPropertyGraph.CLASS_NetworkService,
                    rel2=ABCPropertyGraph.REL_CONNECTS,
                    node2_label=ABCPropertyGraph.CLASS_ConnectionPoint)
                try:
                    fac_ns_node_id = fac_nbs[0][0]
                    fac_cp_node_id = fac_nbs[0][1]
                except KeyError:
                    if self.logger:
                        self.logger.warning(
                            f'Unable to trace facility ConnectionPoint for '
                            f'facility {fac_sliver.resource_name}, continuing')
                    else:
                        print(
                            f'Unable to trace facility ConnectionPoint for '
                            f'facility {fac_sliver.resource_name}, continuing')
                    continue
                _, fac_props = cbm.get_node_properties(
                    node_id=fac_sliver.node_id)
                _, fac_ns_props = cbm.get_node_properties(
                    node_id=fac_ns_node_id)
                _, fac_cp_props = cbm.get_node_properties(
                    node_id=fac_cp_node_id)

                # filter down only the needed properties then recreate the structure of facility in ABQM
                new_fac_props = {
                    ABCPropertyGraph.PROP_NAME:
                    fac_props[ABCPropertyGraph.PROP_NAME],
                    ABCPropertyGraph.PROP_TYPE:
                    fac_props[ABCPropertyGraph.PROP_TYPE]
                }
                abqm.add_node(node_id=fac_sliver.node_id,
                              label=ABCPropertyGraph.CLASS_NetworkNode,
                              props=new_fac_props)
                new_ns_props = {
                    ABCPropertyGraph.PROP_NAME:
                    fac_ns_props[ABCPropertyGraph.PROP_NAME],
                    ABCPropertyGraph.PROP_TYPE:
                    fac_ns_props[ABCPropertyGraph.PROP_TYPE]
                }
                abqm.add_node(node_id=fac_ns_node_id,
                              label=ABCPropertyGraph.CLASS_NetworkService,
                              props=new_ns_props)
                new_cp_props = {
                    ABCPropertyGraph.PROP_NAME:
                    fac_cp_props[ABCPropertyGraph.PROP_NAME],
                    ABCPropertyGraph.PROP_TYPE:
                    fac_cp_props[ABCPropertyGraph.PROP_TYPE],
                    ABCPropertyGraph.PROP_LABELS:
                    fac_cp_props.get(ABCPropertyGraph.PROP_LABELS),
                    ABCPropertyGraph.PROP_CAPACITIES:
                    fac_cp_props.get(ABCPropertyGraph.PROP_CAPACITIES)
                }
                new_cp_props = {k: v for (k, v) in new_cp_props.items() if v}
                abqm.add_node(node_id=fac_cp_node_id,
                              label=ABCPropertyGraph.CLASS_ConnectionPoint,
                              props=new_cp_props)
                abqm.add_link(node_a=fac_sliver.node_id,
                              rel=ABCPropertyGraph.REL_HAS,
                              node_b=fac_ns_node_id)
                abqm.add_link(node_a=fac_ns_node_id,
                              rel=ABCPropertyGraph.REL_CONNECTS,
                              node_b=fac_cp_node_id)

                # trace the link to a switch port/ConnectionPoint and replicate them for simplicity
                fac_cp_nbs = cbm.get_first_and_second_neighbor(
                    node_id=fac_cp_node_id,
                    rel1=ABCPropertyGraph.REL_CONNECTS,
                    node1_label=ABCPropertyGraph.CLASS_Link,
                    rel2=ABCPropertyGraph.REL_CONNECTS,
                    node2_label=ABCPropertyGraph.CLASS_ConnectionPoint)
                if len(fac_cp_nbs) == 0 or len(fac_cp_nbs) > 1:
                    if self.logger:
                        self.logger.warning(
                            f'Unable to trace switch port from Facility port '
                            f'for facility {fac_sliver.resource_name} {fac_cp_nbs}'
                        )
                    else:
                        print(
                            f'Unable to trace switch port from Facility port '
                            f'for facility {fac_sliver.resource_name} {fac_cp_nbs}'
                        )
                    continue

                fac_link_id = fac_cp_nbs[0][0]
                fac_sp_id = fac_cp_nbs[0][1]

                _, fac_link_props = cbm.get_node_properties(
                    node_id=fac_link_id)
                # selectively replicate link properties
                new_link_props = {
                    ABCPropertyGraph.PROP_NAME:
                    fac_link_props[ABCPropertyGraph.PROP_NAME],
                    ABCPropertyGraph.PROP_TYPE:
                    fac_link_props[ABCPropertyGraph.PROP_TYPE],
                    ABCPropertyGraph.PROP_LAYER:
                    fac_link_props[ABCPropertyGraph.PROP_LAYER]
                }
                abqm.add_node(node_id=fac_link_id,
                              label=ABCPropertyGraph.CLASS_Link,
                              props=new_link_props)
                try:
                    abqm.get_node_properties(node_id=fac_sp_id)
                except PropertyGraphQueryException:
                    # if the node doesn't exist we need to create it (it could have been created in the first pass)
                    _, fac_sp_props = cbm.get_node_properties(
                        node_id=fac_sp_id)
                    new_sp_props = {
                        ABCPropertyGraph.PROP_NAME:
                        fac_sp_props[ABCPropertyGraph.PROP_NAME],
                        ABCPropertyGraph.PROP_TYPE:
                        fac_sp_props[ABCPropertyGraph.PROP_TYPE],
                        ABCPropertyGraph.PROP_CAPACITIES:
                        fac_sp_props.get(ABCPropertyGraph.PROP_CAPACITIES),
                        ABCPropertyGraph.PROP_LABELS:
                        fac_sp_props.get(ABCPropertyGraph.PROP_LABELS)
                    }
                    new_sp_props = {
                        k: v
                        for (k, v) in new_sp_props.items() if v
                    }
                    abqm.add_node(node_id=fac_sp_id,
                                  label=ABCPropertyGraph.CLASS_ConnectionPoint,
                                  props=new_sp_props)

                # link these together
                abqm.add_link(node_a=fac_cp_node_id,
                              rel=ABCPropertyGraph.REL_CONNECTS,
                              node_b=fac_link_id)
                abqm.add_link(node_a=fac_link_id,
                              rel=ABCPropertyGraph.REL_CONNECTS,
                              node_b=fac_sp_id)
                abqm.add_link(node_a=fac_sp_id,
                              rel=ABCPropertyGraph.REL_CONNECTS,
                              node_b=site_to_ns_node_id[s])

        return abqm
    def allocate(
        self, *, rid: ID, requested_sliver: BaseSliver, graph_id: str,
        graph_node: BaseSliver,
        existing_reservations: List[ABCReservationMixin]
    ) -> Tuple[str, BaseSliver]:
        """
        Allocate an extending or ticketing reservation
        :param rid: reservation id of the reservation to be allocated
        :param requested_sliver: requested sliver
        :param graph_id: BQM graph id
        :param graph_node: BQM graph node identified to serve the reservation
        :param existing_reservations: Existing Reservations served by the same BQM node
        :return: Tuple of Delegation Id and the Requested Sliver annotated with BQM Node Id and other properties
        :raises: BrokerException in case the request cannot be satisfied
        """
        if graph_node.get_capacity_delegations() is None or rid is None:
            raise BrokerException(
                error_code=Constants.INVALID_ARGUMENT,
                msg=f"capacity_delegations is missing or reservation is None")

        if not isinstance(requested_sliver, NodeSliver):
            raise BrokerException(
                error_code=Constants.INVALID_ARGUMENT,
                msg=f"resource type: {requested_sliver.get_type()}")

        if not isinstance(graph_node, NodeSliver):
            raise BrokerException(
                error_code=Constants.INVALID_ARGUMENT,
                msg=f"resource type: {graph_node.get_type()}")

        # Always use requested capacities to be mapped from flavor i.e. capacity hints
        requested_capacity_hints = requested_sliver.get_capacity_hints()
        catalog = InstanceCatalog()
        requested_capacities = catalog.get_instance_capacities(
            instance_type=requested_capacity_hints.instance_type)

        # Check if Capacities can be satisfied
        delegation_id = self.__check_capacities(
            rid=rid,
            requested_capacities=requested_capacities,
            delegated_capacities=graph_node.get_capacity_delegations(),
            existing_reservations=existing_reservations)

        # Check if Components can be allocated
        if requested_sliver.attached_components_info is not None:
            requested_sliver.attached_components_info = self.__check_components(
                rid=rid,
                requested_components=requested_sliver.attached_components_info,
                graph_id=graph_id,
                graph_node=graph_node,
                existing_reservations=existing_reservations)

        requested_sliver.capacity_allocations = Capacities()
        requested_sliver.capacity_allocations = Labels.update(
            lab=requested_capacities)
        requested_sliver.label_allocations = Labels(
            instance_parent=graph_node.get_name())

        requested_sliver.set_node_map(node_map=(graph_id, graph_node.node_id))

        self.logger.info(
            f"Reservation# {rid} is being served by delegation# {delegation_id} "
            f"node# [{graph_id}/{graph_node.node_id}]")

        return delegation_id, requested_sliver