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
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}')
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)
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
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
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
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)
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)
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)
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