- return vnf_resources
-
- def _create_connection_point(self, account, c_point):
- """
- Create a connection point
- Arguments:
- account - a cloud account
- c_point - connection_points
- """
- kwargs = {}
- kwargs['name'] = c_point.name
- kwargs['network_id'] = c_point.virtual_link_id
- kwargs['admin_state_up'] = True
-
- if c_point.type_yang == 'VIRTIO' or c_point.type_yang == 'E1000':
- kwargs['port_type'] = 'normal'
- elif c_point.type_yang == 'SR_IOV':
- kwargs['port_type'] = 'direct'
- else:
- raise NotImplementedError("Port Type: %s not supported" %(c_point.type_yang))
-
- with self._use_driver(account) as drv:
- if c_point.has_field('security_group'):
- group = drv.neutron_security_group_by_name(c_point.security_group)
- if group is not None:
- kwargs['security_groups'] = [group['id']]
- return drv.neutron_port_create(**kwargs)
-
- def _allocate_floating_ip(self, drv, pool_name):
- """
- Allocate a floating_ip. If unused floating_ip exists then its reused.
- Arguments:
- drv: OpenstackDriver instance
- pool_name: Floating IP pool name
-
- Returns:
- An object of floating IP nova class (novaclient.v2.floating_ips.FloatingIP)
- """
-
- # available_ip = [ ip for ip in drv.nova_floating_ip_list() if ip.instance_id == None ]
-
- # if pool_name is not None:
- # ### Filter further based on IP address
- # available_ip = [ ip for ip in available_ip if ip.pool == pool_name ]
-
- # if not available_ip:
- # floating_ip = drv.nova_floating_ip_create(pool_name)
- # else:
- # floating_ip = available_ip[0]
-
- floating_ip = drv.nova_floating_ip_create(pool_name)
- return floating_ip
-
- def _match_vm_flavor(self, required, available):
- self.log.info("Matching VM Flavor attributes")
- if available.vcpu_count != required.vcpu_count:
- self.log.debug("VCPU requirement mismatch. Required: %d, Available: %d",
- required.vcpu_count,
- available.vcpu_count)
- return False
- if available.memory_mb != required.memory_mb:
- self.log.debug("Memory requirement mismatch. Required: %d MB, Available: %d MB",
- required.memory_mb,
- available.memory_mb)
- return False
- if available.storage_gb != required.storage_gb:
- self.log.debug("Storage requirement mismatch. Required: %d GB, Available: %d GB",
- required.storage_gb,
- available.storage_gb)
- return False
- self.log.debug("VM Flavor match found")
- return True
-
- def _match_guest_epa(self, required, available):
- self.log.info("Matching Guest EPA attributes")
- if required.has_field('pcie_device'):
- self.log.debug("Matching pcie_device")
- if available.has_field('pcie_device') == False:
- self.log.debug("Matching pcie_device failed. Not available in flavor")
- return False
- else:
- for dev in required.pcie_device:
- if not [ d for d in available.pcie_device
- if ((d.device_id == dev.device_id) and (d.count == dev.count)) ]:
- self.log.debug("Matching pcie_device failed. Required: %s, Available: %s", required.pcie_device, available.pcie_device)
- return False
- elif available.has_field('pcie_device'):
- self.log.debug("Rejecting available flavor because pcie_device not required but available")
- return False
-
-
- if required.has_field('mempage_size'):
- self.log.debug("Matching mempage_size")
- if available.has_field('mempage_size') == False:
- self.log.debug("Matching mempage_size failed. Not available in flavor")
- return False
- else:
- if required.mempage_size != available.mempage_size:
- self.log.debug("Matching mempage_size failed. Required: %s, Available: %s", required.mempage_size, available.mempage_size)
- return False
- elif available.has_field('mempage_size'):
- self.log.debug("Rejecting available flavor because mempage_size not required but available")
- return False
-
- if required.has_field('cpu_pinning_policy'):
- self.log.debug("Matching cpu_pinning_policy")
- if required.cpu_pinning_policy != 'ANY':
- if available.has_field('cpu_pinning_policy') == False:
- self.log.debug("Matching cpu_pinning_policy failed. Not available in flavor")
- return False
- else:
- if required.cpu_pinning_policy != available.cpu_pinning_policy:
- self.log.debug("Matching cpu_pinning_policy failed. Required: %s, Available: %s", required.cpu_pinning_policy, available.cpu_pinning_policy)
- return False
- elif available.has_field('cpu_pinning_policy'):
- self.log.debug("Rejecting available flavor because cpu_pinning_policy not required but available")
- return False
-
- if required.has_field('cpu_thread_pinning_policy'):
- self.log.debug("Matching cpu_thread_pinning_policy")
- if available.has_field('cpu_thread_pinning_policy') == False:
- self.log.debug("Matching cpu_thread_pinning_policy failed. Not available in flavor")
- return False
- else:
- if required.cpu_thread_pinning_policy != available.cpu_thread_pinning_policy:
- self.log.debug("Matching cpu_thread_pinning_policy failed. Required: %s, Available: %s", required.cpu_thread_pinning_policy, available.cpu_thread_pinning_policy)
- return False
- elif available.has_field('cpu_thread_pinning_policy'):
- self.log.debug("Rejecting available flavor because cpu_thread_pinning_policy not required but available")
- return False
-
- if required.has_field('trusted_execution'):
- self.log.debug("Matching trusted_execution")
- if required.trusted_execution == True:
- if available.has_field('trusted_execution') == False:
- self.log.debug("Matching trusted_execution failed. Not available in flavor")
- return False
- else:
- if required.trusted_execution != available.trusted_execution:
- self.log.debug("Matching trusted_execution failed. Required: %s, Available: %s", required.trusted_execution, available.trusted_execution)
- return False
- elif available.has_field('trusted_execution'):
- self.log.debug("Rejecting available flavor because trusted_execution not required but available")
- return False
-
- if required.has_field('numa_node_policy'):
- self.log.debug("Matching numa_node_policy")
- if available.has_field('numa_node_policy') == False:
- self.log.debug("Matching numa_node_policy failed. Not available in flavor")
- return False
- else:
- if required.numa_node_policy.has_field('node_cnt'):
- self.log.debug("Matching numa_node_policy node_cnt")
- if available.numa_node_policy.has_field('node_cnt') == False:
- self.log.debug("Matching numa_node_policy node_cnt failed. Not available in flavor")
- return False
- else:
- if required.numa_node_policy.node_cnt != available.numa_node_policy.node_cnt:
- self.log.debug("Matching numa_node_policy node_cnt failed. Required: %s, Available: %s",required.numa_node_policy.node_cnt, available.numa_node_policy.node_cnt)
- return False
- elif available.numa_node_policy.has_field('node_cnt'):
- self.log.debug("Rejecting available flavor because numa node count not required but available")
- return False
-
- if required.numa_node_policy.has_field('mem_policy'):
- self.log.debug("Matching numa_node_policy mem_policy")
- if available.numa_node_policy.has_field('mem_policy') == False:
- self.log.debug("Matching numa_node_policy mem_policy failed. Not available in flavor")
- return False
- else:
- if required.numa_node_policy.mem_policy != available.numa_node_policy.mem_policy:
- self.log.debug("Matching numa_node_policy mem_policy failed. Required: %s, Available: %s", required.numa_node_policy.mem_policy, available.numa_node_policy.mem_policy)
- return False
- elif available.numa_node_policy.has_field('mem_policy'):
- self.log.debug("Rejecting available flavor because num node mem_policy not required but available")
- return False
-
- if required.numa_node_policy.has_field('node'):
- self.log.debug("Matching numa_node_policy nodes configuration")
- if available.numa_node_policy.has_field('node') == False:
- self.log.debug("Matching numa_node_policy nodes configuration failed. Not available in flavor")
- return False
- for required_node in required.numa_node_policy.node:
- self.log.debug("Matching numa_node_policy nodes configuration for node %s", required_node)
- numa_match = False
- for available_node in available.numa_node_policy.node:
- if required_node.id != available_node.id:
- self.log.debug("Matching numa_node_policy nodes configuration failed. Required: %s, Available: %s", required_node, available_node)
- continue
- if required_node.vcpu != available_node.vcpu:
- self.log.debug("Matching numa_node_policy nodes configuration failed. Required: %s, Available: %s", required_node, available_node)
- continue
- if required_node.memory_mb != available_node.memory_mb:
- self.log.debug("Matching numa_node_policy nodes configuration failed. Required: %s, Available: %s", required_node, available_node)
- continue
- numa_match = True
- if numa_match == False:
- return False
- elif available.numa_node_policy.has_field('node'):
- self.log.debug("Rejecting available flavor because numa nodes not required but available")
- return False
- elif available.has_field('numa_node_policy'):
- self.log.debug("Rejecting available flavor because numa_node_policy not required but available")
- return False
- self.log.info("Successful match for Guest EPA attributes")
- return True
-
- def _match_vswitch_epa(self, required, available):
- self.log.debug("VSwitch EPA match found")
- return True
-
- def _match_hypervisor_epa(self, required, available):
- self.log.debug("Hypervisor EPA match found")
- return True
-
- def _match_host_epa(self, required, available):
- self.log.info("Matching Host EPA attributes")
- if required.has_field('cpu_model'):
- self.log.debug("Matching CPU model")
- if available.has_field('cpu_model') == False:
- self.log.debug("Matching CPU model failed. Not available in flavor")
- return False
- else:
- #### Convert all PREFER to REQUIRE since flavor will only have REQUIRE attributes
- if required.cpu_model.replace('PREFER', 'REQUIRE') != available.cpu_model:
- self.log.debug("Matching CPU model failed. Required: %s, Available: %s", required.cpu_model, available.cpu_model)
- return False
- elif available.has_field('cpu_model'):
- self.log.debug("Rejecting available flavor because cpu_model not required but available")
- return False
-
- if required.has_field('cpu_arch'):
- self.log.debug("Matching CPU architecture")
- if available.has_field('cpu_arch') == False:
- self.log.debug("Matching CPU architecture failed. Not available in flavor")
- return False
- else:
- #### Convert all PREFER to REQUIRE since flavor will only have REQUIRE attributes
- if required.cpu_arch.replace('PREFER', 'REQUIRE') != available.cpu_arch:
- self.log.debug("Matching CPU architecture failed. Required: %s, Available: %s", required.cpu_arch, available.cpu_arch)
- return False
- elif available.has_field('cpu_arch'):
- self.log.debug("Rejecting available flavor because cpu_arch not required but available")
- return False
-
- if required.has_field('cpu_vendor'):
- self.log.debug("Matching CPU vendor")
- if available.has_field('cpu_vendor') == False:
- self.log.debug("Matching CPU vendor failed. Not available in flavor")
- return False
- else:
- #### Convert all PREFER to REQUIRE since flavor will only have REQUIRE attributes
- if required.cpu_vendor.replace('PREFER', 'REQUIRE') != available.cpu_vendor:
- self.log.debug("Matching CPU vendor failed. Required: %s, Available: %s", required.cpu_vendor, available.cpu_vendor)
- return False
- elif available.has_field('cpu_vendor'):
- self.log.debug("Rejecting available flavor because cpu_vendor not required but available")
- return False
-
- if required.has_field('cpu_socket_count'):
- self.log.debug("Matching CPU socket count")
- if available.has_field('cpu_socket_count') == False:
- self.log.debug("Matching CPU socket count failed. Not available in flavor")
- return False
- else:
- if required.cpu_socket_count != available.cpu_socket_count:
- self.log.debug("Matching CPU socket count failed. Required: %s, Available: %s", required.cpu_socket_count, available.cpu_socket_count)
- return False
- elif available.has_field('cpu_socket_count'):
- self.log.debug("Rejecting available flavor because cpu_socket_count not required but available")
- return False
-
- if required.has_field('cpu_core_count'):
- self.log.debug("Matching CPU core count")
- if available.has_field('cpu_core_count') == False:
- self.log.debug("Matching CPU core count failed. Not available in flavor")
- return False
- else:
- if required.cpu_core_count != available.cpu_core_count:
- self.log.debug("Matching CPU core count failed. Required: %s, Available: %s", required.cpu_core_count, available.cpu_core_count)
- return False
- elif available.has_field('cpu_core_count'):
- self.log.debug("Rejecting available flavor because cpu_core_count not required but available")
- return False
-
- if required.has_field('cpu_core_thread_count'):
- self.log.debug("Matching CPU core thread count")
- if available.has_field('cpu_core_thread_count') == False:
- self.log.debug("Matching CPU core thread count failed. Not available in flavor")
- return False
- else:
- if required.cpu_core_thread_count != available.cpu_core_thread_count:
- self.log.debug("Matching CPU core thread count failed. Required: %s, Available: %s", required.cpu_core_thread_count, available.cpu_core_thread_count)
- return False
- elif available.has_field('cpu_core_thread_count'):
- self.log.debug("Rejecting available flavor because cpu_core_thread_count not required but available")
- return False
-
- if required.has_field('cpu_feature'):
- self.log.debug("Matching CPU feature list")
- if available.has_field('cpu_feature') == False:
- self.log.debug("Matching CPU feature list failed. Not available in flavor")
- return False
- else:
- for feature in required.cpu_feature:
- if feature not in available.cpu_feature:
- self.log.debug("Matching CPU feature list failed. Required feature: %s is not present. Available features: %s", feature, available.cpu_feature)
- return False
- elif available.has_field('cpu_feature'):
- self.log.debug("Rejecting available flavor because cpu_feature not required but available")
- return False
- self.log.info("Successful match for Host EPA attributes")
- return True
-
-
- def _match_placement_group_inputs(self, required, available):
- self.log.info("Matching Host aggregate attributes")
-
- if not required and not available:
- # Host aggregate not required and not available => success
- self.log.info("Successful match for Host Aggregate attributes")
- return True
- if required and available:
- # Host aggregate requested and available => Do a match and decide
- xx = [ x.as_dict() for x in required ]
- yy = [ y.as_dict() for y in available ]
- for i in xx:
- if i not in yy:
- self.log.debug("Rejecting available flavor because host Aggregate mismatch. Required: %s, Available: %s ", required, available)
- return False
- self.log.info("Successful match for Host Aggregate attributes")
- return True
- else:
- # Either of following conditions => Failure
- # - Host aggregate required but not available
- # - Host aggregate not required but available
- self.log.debug("Rejecting available flavor because host Aggregate mismatch. Required: %s, Available: %s ", required, available)
- return False
-
- def match_epa_params(self, resource_info, request_params):
- result = self._match_vm_flavor(getattr(request_params, 'vm_flavor'),
- getattr(resource_info, 'vm_flavor'))
- if result == False:
- self.log.debug("VM Flavor mismatched")
- return False
-
- result = self._match_guest_epa(getattr(request_params, 'guest_epa'),
- getattr(resource_info, 'guest_epa'))
- if result == False:
- self.log.debug("Guest EPA mismatched")
- return False
-
- result = self._match_vswitch_epa(getattr(request_params, 'vswitch_epa'),
- getattr(resource_info, 'vswitch_epa'))
- if result == False:
- self.log.debug("Vswitch EPA mismatched")
- return False
-
- result = self._match_hypervisor_epa(getattr(request_params, 'hypervisor_epa'),
- getattr(resource_info, 'hypervisor_epa'))
- if result == False:
- self.log.debug("Hypervisor EPA mismatched")
- return False
-
- result = self._match_host_epa(getattr(request_params, 'host_epa'),
- getattr(resource_info, 'host_epa'))
- if result == False:
- self.log.debug("Host EPA mismatched")
- return False
-
- result = self._match_placement_group_inputs(getattr(request_params, 'host_aggregate'),
- getattr(resource_info, 'host_aggregate'))
-
- if result == False:
- self.log.debug("Host Aggregate mismatched")
- return False
-
- return True
-
- def _select_resource_flavor(self, account, vdu_init):
- """
- Select a existing flavor if it matches the request or create new flavor
- """
- flavor = RwcalYang.FlavorInfoItem()
- flavor.name = str(uuid.uuid4())
- epa_types = ['vm_flavor', 'guest_epa', 'host_epa', 'host_aggregate', 'hypervisor_epa', 'vswitch_epa']
- epa_dict = {k: v for k, v in vdu_init.as_dict().items() if k in epa_types}
- flavor.from_dict(epa_dict)
-
- rc, response = self.do_get_flavor_list(account)
- if rc != RwTypes.RwStatus.SUCCESS:
- self.log.error("Get-flavor-info-list operation failed for cloud account: %s",
- account.name)
- raise OpenstackCALOperationFailure("Get-flavor-info-list operation failed for cloud account: %s" %(account.name))
-
- flavor_id = None
- flavor_list = response.flavorinfo_list
- self.log.debug("Received %d flavor information from RW.CAL", len(flavor_list))
- for flv in flavor_list:
- self.log.info("Attempting to match compute requirement for VDU: %s with flavor %s",
- vdu_init.name, flv)
- if self.match_epa_params(flv, vdu_init):
- self.log.info("Flavor match found for compute requirements for VDU: %s with flavor name: %s, flavor-id: %s",
- vdu_init.name, flv.name, flv.id)
- return flv.id
-
- if account.openstack.dynamic_flavor_support is False:
- self.log.error("Unable to create flavor for compute requirement for VDU: %s. VDU instantiation failed", vdu_init.name)
- raise OpenstackCALOperationFailure("No resource available with matching EPA attributes")
- else:
- rc,flavor_id = self.do_create_flavor(account,flavor)
- if rc != RwTypes.RwStatus.SUCCESS:
- self.log.error("Create-flavor operation failed for cloud account: %s",
- account.name)
- raise OpenstackCALOperationFailure("Create-flavor operation failed for cloud account: %s" %(account.name))
- return flavor_id
-
- def _create_vm(self, account, vduinfo, pci_assignement=None, server_group=None, port_list=None, network_list=None, imageinfo_list=None):
- """Create a new virtual machine.
-
- Arguments:
- account - a cloud account
- vminfo - information that defines the type of VM to create
-
- Returns:
- The image id
- """
- kwargs = {}
- kwargs['name'] = vduinfo.name
- kwargs['flavor_id'] = vduinfo.flavor_id
- if vduinfo.has_field('image_id'):
- kwargs['image_id'] = vduinfo.image_id
- else:
- kwargs['image_id'] = ""
-
- with self._use_driver(account) as drv:
- ### If floating_ip is required and we don't have one, better fail before any further allocation
- if vduinfo.has_field('allocate_public_address') and vduinfo.allocate_public_address:
- if account.openstack.has_field('floating_ip_pool'):
- pool_name = account.openstack.floating_ip_pool
- else:
- pool_name = None
- floating_ip = self._allocate_floating_ip(drv, pool_name)
- else:
- floating_ip = None
-
- if vduinfo.has_field('vdu_init') and vduinfo.vdu_init.has_field('userdata'):
- kwargs['userdata'] = vduinfo.vdu_init.userdata
- else:
- kwargs['userdata'] = ''
-
- if account.openstack.security_groups:
- kwargs['security_groups'] = account.openstack.security_groups
-
- kwargs['port_list'] = port_list
- kwargs['network_list'] = network_list
-
- metadata = {}
- # Add all metadata related fields
- if vduinfo.has_field('node_id'):
- metadata['node_id'] = vduinfo.node_id
- if pci_assignement is not None:
- metadata['pci_assignement'] = pci_assignement
- kwargs['metadata'] = metadata
-
- if vduinfo.has_field('availability_zone') and vduinfo.availability_zone.has_field('name'):
- kwargs['availability_zone'] = vduinfo.availability_zone
- else:
- kwargs['availability_zone'] = None
-
- if server_group is not None:
- kwargs['scheduler_hints'] = {'group': server_group}
- else:
- kwargs['scheduler_hints'] = None
-
- kwargs['block_device_mapping_v2'] = None
- if vduinfo.has_field('volumes') :
- kwargs['block_device_mapping_v2'] = []
- with self._use_driver(account) as drv:
- # Only support image->volume
- for volume in vduinfo.volumes:
- block_map = dict()
- block_map['boot_index'] = volume.boot_params.boot_priority
- if "image" in volume:
- # Support image->volume
- # Match retrived image info with volume based image name and checksum
- if volume.image is not None:
- matching_images = [img for img in imageinfo_list if img['name'] == volume.image]
- if volume.image_checksum is not None:
- matching_images = [img for img in matching_images if img['checksum'] == volume.image_checksum]
- img_id = matching_images[0]['id']
- if img_id is None:
- raise OpenstackCALOperationFailure("Create-vdu operation failed. Volume image not found for name {} checksum {}".format(volume.name, volume.checksum))
- block_map['uuid'] = img_id
- block_map['source_type'] = "image"
- else:
- block_map['source_type'] = "blank"
-
- block_map['device_name'] = volume.name
- block_map['destination_type'] = "volume"
- block_map['volume_size'] = volume.size
- block_map['delete_on_termination'] = True
- if volume.guest_params.has_field('device_type') and volume.guest_params.device_type == 'cdrom':
- block_map['device_type'] = 'cdrom'
- if volume.guest_params.has_field('device_bus') and volume.guest_params.device_bus == 'ide':
- block_map['disk_bus'] = 'ide'
- kwargs['block_device_mapping_v2'].append(block_map)
-
-
- with self._use_driver(account) as drv:
- vm_id = drv.nova_server_create(**kwargs)
- if floating_ip:
- self.prepare_vdu_on_boot(account, vm_id, floating_ip)
-
- return vm_id