def _instance_supported(self, host_state, image_props, hypervisor_version): img_arch = image_props.get('architecture', None) img_h_type = image_props.get('hypervisor_type', None) img_vm_mode = image_props.get('vm_mode', None) checked_img_props = ( arch.canonicalize(img_arch), hv_type.canonicalize(img_h_type), vm_mode.canonicalize(img_vm_mode) ) # Supported if no compute-related instance properties are specified if not any(checked_img_props): return True supp_instances = host_state.supported_instances # Not supported if an instance property is requested but nothing # advertised by the host. if not supp_instances: LOG.debug("Instance contains properties %(image_props)s, " "but no corresponding supported_instances are " "advertised by the compute node", {'image_props': image_props}) return False def _compare_props(props, other_props): for i in props: if i and i not in other_props: return False return True def _compare_product_version(hyper_version, image_props): version_required = image_props.get('hypervisor_version_requires') if not(hypervisor_version and version_required): return True img_prop_predicate = versionpredicate.VersionPredicate( 'image_prop (%s)' % version_required) hyper_ver_str = utils.convert_version_to_str(hyper_version) return img_prop_predicate.satisfied_by(hyper_ver_str) for supp_inst in supp_instances: if _compare_props(checked_img_props, supp_inst): if _compare_product_version(hypervisor_version, image_props): return True LOG.debug("Instance contains properties %(image_props)s " "that are not provided by the compute node " "supported_instances %(supp_instances)s or " "hypervisor version %(hypervisor_version)s do not match", {'image_props': image_props, 'supp_instances': supp_instances, 'hypervisor_version': hypervisor_version}) return False
def _instance_supported(self, host_state, image_props, hypervisor_version): img_arch = image_props.get('architecture', None) img_h_type = image_props.get('hypervisor_type', None) img_vm_mode = image_props.get('vm_mode', None) checked_img_props = (arch.canonicalize(img_arch), hv_type.canonicalize(img_h_type), vm_mode.canonicalize(img_vm_mode)) # Supported if no compute-related instance properties are specified if not any(checked_img_props): return True supp_instances = host_state.supported_instances # Not supported if an instance property is requested but nothing # advertised by the host. if not supp_instances: LOG.debug( "Instance contains properties %(image_props)s, " "but no corresponding supported_instances are " "advertised by the compute node", {'image_props': image_props}) return False def _compare_props(props, other_props): for i in props: if i and i not in other_props: return False return True def _compare_product_version(hyper_version, image_props): version_required = image_props.get('hypervisor_version_requires') if not (hypervisor_version and version_required): return True img_prop_predicate = versionpredicate.VersionPredicate( 'image_prop (%s)' % version_required) hyper_ver_str = utils.convert_version_to_str(hyper_version) return img_prop_predicate.satisfied_by(hyper_ver_str) for supp_inst in supp_instances: if _compare_props(checked_img_props, supp_inst): if _compare_product_version(hypervisor_version, image_props): return True LOG.debug( "Instance contains properties %(image_props)s " "that are not provided by the compute node " "supported_instances %(supp_instances)s or " "hypervisor version %(hypervisor_version)s do not match", { 'image_props': image_props, 'supp_instances': supp_instances, 'hypervisor_version': hypervisor_version }) return False
def get_arch(image_meta): """Determine the architecture of the guest (or host). This method determines the CPU architecture that must be supported by the hypervisor. It gets the (guest) arch info from image_meta properties, and it will fallback to the patron-compute (host) arch if no architecture info is provided in image_meta. :param image_meta: the metadata associated with the instance image :returns: guest (or host) architecture """ if image_meta: image_arch = image_meta.get('properties', {}).get('architecture') if image_arch is not None: return arch.canonicalize(image_arch) return arch.from_host()
def to_supported_instances(host_capabilities): if not host_capabilities: return [] result = [] for capability in host_capabilities: try: # 'capability'is unicode but we want arch/ostype # to be strings to match the standard constants capability = str(capability) ostype, _version, guestarch = capability.split("-") guestarch = arch.canonicalize(guestarch) ostype = vm_mode.canonicalize(ostype) result.append((guestarch, hv_type.XEN, ostype)) except ValueError: LOG.warning(_LW("Failed to extract instance support from %s"), capability) return result
def _node_resource(self, node): """Helper method to create resource dict from node stats.""" vcpus = int(node.properties.get('cpus', 0)) memory_mb = int(node.properties.get('memory_mb', 0)) local_gb = int(node.properties.get('local_gb', 0)) raw_cpu_arch = node.properties.get('cpu_arch', None) try: cpu_arch = arch.canonicalize(raw_cpu_arch) except exception.InvalidArchitectureName: cpu_arch = None if not cpu_arch: LOG.warning(_LW("cpu_arch not defined for node '%s'"), node.uuid) nodes_extra_specs = {} # NOTE(deva): In Havana and Icehouse, the flavor was required to link # to an arch-specific deploy kernel and ramdisk pair, and so the flavor # also had to have extra_specs['cpu_arch'], which was matched against # the ironic node.properties['cpu_arch']. # With Juno, the deploy image(s) may be referenced directly by the # node.driver_info, and a flavor no longer needs to contain any of # these three extra specs, though the cpu_arch may still be used # in a heterogeneous environment, if so desired. # NOTE(dprince): we use the raw cpu_arch here because extra_specs # filters aren't canonicalized nodes_extra_specs['cpu_arch'] = raw_cpu_arch # NOTE(gilliard): To assist with more precise scheduling, if the # node.properties contains a key 'capabilities', we expect the value # to be of the form "k1:v1,k2:v2,etc.." which we add directly as # key/value pairs into the node_extra_specs to be used by the # ComputeCapabilitiesFilter capabilities = node.properties.get('capabilities') if capabilities: for capability in str(capabilities).split(','): parts = capability.split(':') if len(parts) == 2 and parts[0] and parts[1]: nodes_extra_specs[parts[0]] = parts[1] else: LOG.warning( _LW("Ignoring malformed capability '%s'. " "Format should be 'key:val'."), capability) vcpus_used = 0 memory_mb_used = 0 local_gb_used = 0 if self._node_resources_used(node): # Node is in the process of deploying, is deployed, or is in # the process of cleaning up from a deploy. Report all of its # resources as in use. vcpus_used = vcpus memory_mb_used = memory_mb local_gb_used = local_gb elif self._node_resources_unavailable(node): # The node's current state is such that it should not present any # of its resources to Nova vcpus = 0 memory_mb = 0 local_gb = 0 dic = { 'hypervisor_hostname': str(node.uuid), 'hypervisor_type': self._get_hypervisor_type(), 'hypervisor_version': self._get_hypervisor_version(), # The Ironic driver manages multiple hosts, so there are # likely many different CPU models in use. As such it is # impossible to provide any meaningful info on the CPU # model of the "host" 'cpu_info': None, 'vcpus': vcpus, 'vcpus_used': vcpus_used, 'local_gb': local_gb, 'local_gb_used': local_gb_used, 'disk_available_least': local_gb - local_gb_used, 'memory_mb': memory_mb, 'memory_mb_used': memory_mb_used, 'supported_instances': jsonutils.dumps(_get_nodes_supported_instances(cpu_arch)), 'stats': jsonutils.dumps(nodes_extra_specs), } return dic
def test_canonicalize_case(self): self.assertEqual(arch.X86_64, arch.canonicalize("X86_64"))
def test_canonicalize_compat_xen2(self): self.assertEqual(arch.I686, arch.canonicalize("x86_32p"))
def test_canonicalize_i386(self): self.assertEqual(arch.I686, arch.canonicalize("i386"))
def test_canonicalize_amd64(self): self.assertEqual(arch.X86_64, arch.canonicalize("amd64"))
def _node_resource(self, node): """Helper method to create resource dict from node stats.""" vcpus = int(node.properties.get('cpus', 0)) memory_mb = int(node.properties.get('memory_mb', 0)) local_gb = int(node.properties.get('local_gb', 0)) raw_cpu_arch = node.properties.get('cpu_arch', None) try: cpu_arch = arch.canonicalize(raw_cpu_arch) except exception.InvalidArchitectureName: cpu_arch = None if not cpu_arch: LOG.warning(_LW("cpu_arch not defined for node '%s'"), node.uuid) nodes_extra_specs = {} # NOTE(deva): In Havana and Icehouse, the flavor was required to link # to an arch-specific deploy kernel and ramdisk pair, and so the flavor # also had to have extra_specs['cpu_arch'], which was matched against # the ironic node.properties['cpu_arch']. # With Juno, the deploy image(s) may be referenced directly by the # node.driver_info, and a flavor no longer needs to contain any of # these three extra specs, though the cpu_arch may still be used # in a heterogeneous environment, if so desired. # NOTE(dprince): we use the raw cpu_arch here because extra_specs # filters aren't canonicalized nodes_extra_specs['cpu_arch'] = raw_cpu_arch # NOTE(gilliard): To assist with more precise scheduling, if the # node.properties contains a key 'capabilities', we expect the value # to be of the form "k1:v1,k2:v2,etc.." which we add directly as # key/value pairs into the node_extra_specs to be used by the # ComputeCapabilitiesFilter capabilities = node.properties.get('capabilities') if capabilities: for capability in str(capabilities).split(','): parts = capability.split(':') if len(parts) == 2 and parts[0] and parts[1]: nodes_extra_specs[parts[0]] = parts[1] else: LOG.warning(_LW("Ignoring malformed capability '%s'. " "Format should be 'key:val'."), capability) vcpus_used = 0 memory_mb_used = 0 local_gb_used = 0 if self._node_resources_used(node): # Node is in the process of deploying, is deployed, or is in # the process of cleaning up from a deploy. Report all of its # resources as in use. vcpus_used = vcpus memory_mb_used = memory_mb local_gb_used = local_gb elif self._node_resources_unavailable(node): # The node's current state is such that it should not present any # of its resources to Nova vcpus = 0 memory_mb = 0 local_gb = 0 dic = { 'hypervisor_hostname': str(node.uuid), 'hypervisor_type': self._get_hypervisor_type(), 'hypervisor_version': self._get_hypervisor_version(), # The Ironic driver manages multiple hosts, so there are # likely many different CPU models in use. As such it is # impossible to provide any meaningful info on the CPU # model of the "host" 'cpu_info': None, 'vcpus': vcpus, 'vcpus_used': vcpus_used, 'local_gb': local_gb, 'local_gb_used': local_gb_used, 'disk_available_least': local_gb - local_gb_used, 'memory_mb': memory_mb, 'memory_mb_used': memory_mb_used, 'supported_instances': jsonutils.dumps( _get_nodes_supported_instances(cpu_arch)), 'stats': jsonutils.dumps(nodes_extra_specs), } return dic