class HVSpec(base.NovaObject): # Version 1.0: Initial version # Version 1.1: Added 'vz' hypervisor # Version 1.2: Added 'lxd' hypervisor VERSION = '1.2' fields = { 'arch': fields.ArchitectureField(), 'hv_type': fields.HVTypeField(), 'vm_mode': fields.VMModeField(), } # NOTE(pmurray): for backward compatibility, the supported instance # data is stored in the database as a list. @classmethod def from_list(cls, data): return cls(arch=data[0], hv_type=data[1], vm_mode=data[2]) def to_list(self): return [self.arch, self.hv_type, self.vm_mode] def obj_make_compatible(self, primitive, target_version): super(HVSpec, self).obj_make_compatible(primitive, target_version) target_version = versionutils.convert_version_to_tuple(target_version) if (target_version < (1, 1) and 'hv_type' in primitive and hv_type.VIRTUOZZO == primitive['hv_type']): primitive['hv_type'] = hv_type.PARALLELS
class VirtCPUModel(base.NovaObject): # Version 1.0: Initial version VERSION = '1.0' fields = { 'arch': fields.ArchitectureField(nullable=True), 'vendor': fields.StringField(nullable=True), 'topology': fields.ObjectField('VirtCPUTopology', nullable=True), 'features': fields.ListOfObjectsField("VirtCPUFeature", default=[]), 'mode': fields.CPUModeField(nullable=True), 'model': fields.StringField(nullable=True), 'match': fields.CPUMatchField(nullable=True), } def obj_load_attr(self, attrname): setattr(self, attrname, None) def to_json(self): return jsonutils.dumps(self.obj_to_primitive()) @classmethod def from_json(cls, jsonstr): return cls.obj_from_primitive(jsonutils.loads(jsonstr)) @base.remotable_classmethod def get_by_instance_uuid(cls, context, instance_uuid): db_extra = db.instance_extra_get_by_instance_uuid( context, instance_uuid, columns=['vcpu_model']) if not db_extra or not db_extra['vcpu_model']: return None return cls.obj_from_primitive(jsonutils.loads(db_extra['vcpu_model']))
def setUp(self): super(TestArchitecture, self).setUp() self.field = fields.ArchitectureField() self.coerce_good_values = [('x86_64', 'x86_64'), ('amd64', 'x86_64'), ('I686', 'i686'), ('i386', 'i686')] self.coerce_bad_values = ['x86_99'] self.to_primitive_values = self.coerce_good_values[0:1] self.from_primitive_values = self.coerce_good_values[0:1]
class HVSpec(base.NovaObject, base.NovaObjectDictCompat): # Version 1.0: Initial version VERSION = '1.0' fields = { 'arch': fields.ArchitectureField(), 'hv_type': fields.HVTypeField(), 'vm_mode': fields.VMModeField(), } # NOTE(pmurray): for backward compatibility, the supported instance # data is stored in the database as a list. @classmethod def from_list(cls, data): return cls(arch=data[0], hv_type=data[1], vm_mode=data[2]) def to_list(self): return [self.arch, self.hv_type, self.vm_mode]
class ImageMetaProps(base.NovaObject): # Version 1.0: Initial version # Version 1.1: added os_require_quiesce field # Version 1.2: added img_hv_type and img_hv_requested_version fields # Version 1.3: HVSpec version 1.1 # Version 1.4: added hw_vif_multiqueue_enabled field # Version 1.5: added os_admin_user field VERSION = ImageMeta.VERSION # Maximum number of NUMA nodes permitted for the guest topology NUMA_NODES_MAX = 128 # 'hw_' - settings affecting the guest virtual machine hardware # 'img_' - settings affecting the use of images by the compute node # 'os_' - settings affecting the guest operating system setup fields = { # name of guest hardware architecture eg i686, x86_64, ppc64 'hw_architecture': fields.ArchitectureField(), # used to decide to expand root disk partition and fs to full size of # root disk 'hw_auto_disk_config': fields.StringField(), # whether to display BIOS boot device menu 'hw_boot_menu': fields.FlexibleBooleanField(), # name of the CDROM bus to use eg virtio, scsi, ide 'hw_cdrom_bus': fields.DiskBusField(), # preferred number of CPU cores per socket 'hw_cpu_cores': fields.IntegerField(), # preferred number of CPU sockets 'hw_cpu_sockets': fields.IntegerField(), # maximum number of CPU cores per socket 'hw_cpu_max_cores': fields.IntegerField(), # maximum number of CPU sockets 'hw_cpu_max_sockets': fields.IntegerField(), # maximum number of CPU threads per core 'hw_cpu_max_threads': fields.IntegerField(), # CPU thread allocation policy 'hw_cpu_policy': fields.CPUAllocationPolicyField(), # preferred number of CPU threads per core 'hw_cpu_threads': fields.IntegerField(), # guest ABI version for guest xentools either 1 or 2 (or 3 - depends on # Citrix PV tools version installed in image) 'hw_device_id': fields.IntegerField(), # name of the hard disk bus to use eg virtio, scsi, ide 'hw_disk_bus': fields.DiskBusField(), # allocation mode eg 'preallocated' 'hw_disk_type': fields.StringField(), # name of the floppy disk bus to use eg fd, scsi, ide 'hw_floppy_bus': fields.DiskBusField(), # boolean - used to trigger code to inject networking when booting a CD # image with a network boot image 'hw_ipxe_boot': fields.FlexibleBooleanField(), # There are sooooooooooo many possible machine types in # QEMU - several new ones with each new release - that it # is not practical to enumerate them all. So we use a free # form string 'hw_machine_type': fields.StringField(), # One of the magic strings 'small', 'any', 'large' # or an explicit page size in KB (eg 4, 2048, ...) 'hw_mem_page_size': fields.StringField(), # Number of guest NUMA nodes 'hw_numa_nodes': fields.IntegerField(), # Each list entry corresponds to a guest NUMA node and the # set members indicate CPUs for that node 'hw_numa_cpus': fields.ListOfSetsOfIntegersField(), # Each list entry corresponds to a guest NUMA node and the # list value indicates the memory size of that node. 'hw_numa_mem': fields.ListOfIntegersField(), # boolean 'yes' or 'no' to enable QEMU guest agent 'hw_qemu_guest_agent': fields.FlexibleBooleanField(), # name of the RNG device type eg virtio 'hw_rng_model': fields.RNGModelField(), # number of serial ports to create 'hw_serial_port_count': fields.IntegerField(), # name of the SCSI bus controller eg 'virtio-scsi', 'lsilogic', etc 'hw_scsi_model': fields.SCSIModelField(), # name of the video adapter model to use, eg cirrus, vga, xen, qxl 'hw_video_model': fields.VideoModelField(), # MB of video RAM to provide eg 64 'hw_video_ram': fields.IntegerField(), # name of a NIC device model eg virtio, e1000, rtl8139 'hw_vif_model': fields.VIFModelField(), # "xen" vs "hvm" 'hw_vm_mode': fields.VMModeField(), # action to take when watchdog device fires eg reset, poweroff, pause, # none 'hw_watchdog_action': fields.WatchdogActionField(), # boolean - If true, this will enable the virtio-multiqueue feature 'hw_vif_multiqueue_enabled': fields.FlexibleBooleanField(), # if true download using bittorrent 'img_bittorrent': fields.FlexibleBooleanField(), # Which data format the 'img_block_device_mapping' field is # using to represent the block device mapping 'img_bdm_v2': fields.FlexibleBooleanField(), # Block device mapping - the may can be in one or two completely # different formats. The 'img_bdm_v2' field determines whether # it is in legacy format, or the new current format. Ideally # we would have a formal data type for this field instead of a # dict, but with 2 different formats to represent this is hard. # See nova/block_device.py from_legacy_mapping() for the complex # conversion code. So for now leave it as a dict and continue # to use existing code that is able to convert dict into the # desired internal BDM formats 'img_block_device_mapping': fields.ListOfDictOfNullableStringsField(), # boolean - if True, and image cache set to "some" decides if image # should be cached on host when server is booted on that host 'img_cache_in_nova': fields.FlexibleBooleanField(), # Compression level for images. (1-9) 'img_compression_level': fields.IntegerField(), # hypervisor supported version, eg. '>=2.6' 'img_hv_requested_version': fields.VersionPredicateField(), # type of the hypervisor, eg kvm, ironic, xen 'img_hv_type': fields.HVTypeField(), # boolean flag to set space-saving or performance behavior on the # Datastore 'img_linked_clone': fields.FlexibleBooleanField(), # Image mappings - related to Block device mapping data - mapping # of virtual image names to device names. This could be represented # as a formatl data type, but is left as dict for same reason as # img_block_device_mapping field. It would arguably make sense for # the two to be combined into a single field and data type in the # future. 'img_mappings': fields.ListOfDictOfNullableStringsField(), # image project id (set on upload) 'img_owner_id': fields.StringField(), # root device name, used in snapshotting eg /dev/<blah> 'img_root_device_name': fields.StringField(), # boolean - if false don't talk to nova agent 'img_use_agent': fields.FlexibleBooleanField(), # integer value 1 'img_version': fields.IntegerField(), # string of username with admin privileges 'os_admin_user': fields.StringField(), # string of boot time command line arguments for the guest kernel 'os_command_line': fields.StringField(), # the name of the specific guest operating system distro. This # is not done as an Enum since the list of operating systems is # growing incredibly fast, and valid values can be arbitrarily # user defined. Nova has no real need for strict validation so # leave it freeform 'os_distro': fields.StringField(), # boolean - if true, then guest must support disk quiesce # or snapshot operation will be denied 'os_require_quiesce': fields.FlexibleBooleanField(), # boolean - if using agent don't inject files, assume someone else is # doing that (cloud-init) 'os_skip_agent_inject_files_at_boot': fields.FlexibleBooleanField(), # boolean - if using agent don't try inject ssh key, assume someone # else is doing that (cloud-init) 'os_skip_agent_inject_ssh': fields.FlexibleBooleanField(), # The guest operating system family such as 'linux', 'windows' - this # is a fairly generic type. For a detailed type consider os_distro # instead 'os_type': fields.OSTypeField(), } # The keys are the legacy property names and # the values are the current preferred names _legacy_property_map = { 'architecture': 'hw_architecture', 'owner_id': 'img_owner_id', 'vmware_disktype': 'hw_disk_type', 'vmware_image_version': 'img_version', 'vmware_ostype': 'os_distro', 'auto_disk_config': 'hw_auto_disk_config', 'ipxe_boot': 'hw_ipxe_boot', 'xenapi_device_id': 'hw_device_id', 'xenapi_image_compression_level': 'img_compression_level', 'vmware_linked_clone': 'img_linked_clone', 'xenapi_use_agent': 'img_use_agent', 'xenapi_skip_agent_inject_ssh': 'os_skip_agent_inject_ssh', 'xenapi_skip_agent_inject_files_at_boot': 'os_skip_agent_inject_files_at_boot', 'cache_in_nova': 'img_cache_in_nova', 'vm_mode': 'hw_vm_mode', 'bittorrent': 'img_bittorrent', 'mappings': 'img_mappings', 'block_device_mapping': 'img_block_device_mapping', 'bdm_v2': 'img_bdm_v2', 'root_device_name': 'img_root_device_name', 'hypervisor_version_requires': 'img_hv_requested_version', } # TODO(berrange): Need to run this from a data migration # at some point so we can eventually kill off the compat def _set_attr_from_legacy_names(self, image_props): for legacy_key in self._legacy_property_map: new_key = self._legacy_property_map[legacy_key] if legacy_key not in image_props: continue setattr(self, new_key, image_props[legacy_key]) vmware_adaptertype = image_props.get("vmware_adaptertype") if vmware_adaptertype == "ide": setattr(self, "hw_disk_bus", "ide") elif vmware_adaptertype is not None: setattr(self, "hw_disk_bus", "scsi") setattr(self, "hw_scsi_model", vmware_adaptertype) def _set_numa_mem(self, image_props): hw_numa_mem = [] hw_numa_mem_set = False for cellid in range(ImageMetaProps.NUMA_NODES_MAX): memprop = "hw_numa_mem.%d" % cellid if memprop not in image_props: break hw_numa_mem.append(int(image_props[memprop])) hw_numa_mem_set = True del image_props[memprop] if hw_numa_mem_set: self.hw_numa_mem = hw_numa_mem def _set_numa_cpus(self, image_props): hw_numa_cpus = [] hw_numa_cpus_set = False for cellid in range(ImageMetaProps.NUMA_NODES_MAX): cpuprop = "hw_numa_cpus.%d" % cellid if cpuprop not in image_props: break hw_numa_cpus.append(hardware.parse_cpu_spec(image_props[cpuprop])) hw_numa_cpus_set = True del image_props[cpuprop] if hw_numa_cpus_set: self.hw_numa_cpus = hw_numa_cpus def _set_attr_from_current_names(self, image_props): for key in self.fields: # The two NUMA fields need special handling to # un-stringify them correctly if key == "hw_numa_mem": self._set_numa_mem(image_props) elif key == "hw_numa_cpus": self._set_numa_cpus(image_props) else: if key not in image_props: continue setattr(self, key, image_props[key]) @classmethod def from_dict(cls, image_props): """Create instance from image properties dict :param image_props: dictionary of image metdata properties Creates a new object instance, initializing from a dictionary of image metadata properties :returns: an ImageMetaProps instance """ obj = cls() # We look to see if the dict has entries for any # of the legacy property names first. Then we use # the current property names. That way if both the # current and legacy names are set, the value # associated with the current name takes priority obj._set_attr_from_legacy_names(image_props) obj._set_attr_from_current_names(image_props) return obj def get(self, name, defvalue=None): """Get the value of an attribute :param name: the attribute to request :param defvalue: the default value if not set This returns the value of an attribute if it is currently set, otherwise it will return None. This differs from accessing props.attrname, because that will raise an exception if the attribute has no value set. So instead of if image_meta.properties.obj_attr_is_set("some_attr"): val = image_meta.properties.some_attr else val = None Callers can rely on unconditional access val = image_meta.properties.get("some_attr") :returns: the attribute value or None """ if not self.obj_attr_is_set(name): return defvalue return getattr(self, name)
class ImageMetaPropsPayload(base.NotificationPayloadBase): # Version 1.0: Initial version # Version 1.1: Added 'gop', 'virtio' and 'none' to hw_video_model field VERSION = '1.1' SCHEMA = { 'hw_architecture': ('image_meta_props', 'hw_architecture'), 'hw_auto_disk_config': ('image_meta_props', 'hw_auto_disk_config'), 'hw_boot_menu': ('image_meta_props', 'hw_boot_menu'), 'hw_cdrom_bus': ('image_meta_props', 'hw_cdrom_bus'), 'hw_cpu_cores': ('image_meta_props', 'hw_cpu_cores'), 'hw_cpu_sockets': ('image_meta_props', 'hw_cpu_sockets'), 'hw_cpu_max_cores': ('image_meta_props', 'hw_cpu_max_cores'), 'hw_cpu_max_sockets': ('image_meta_props', 'hw_cpu_max_sockets'), 'hw_cpu_max_threads': ('image_meta_props', 'hw_cpu_max_threads'), 'hw_cpu_policy': ('image_meta_props', 'hw_cpu_policy'), 'hw_cpu_thread_policy': ('image_meta_props', 'hw_cpu_thread_policy'), 'hw_cpu_realtime_mask': ('image_meta_props', 'hw_cpu_realtime_mask'), 'hw_cpu_threads': ('image_meta_props', 'hw_cpu_threads'), 'hw_device_id': ('image_meta_props', 'hw_device_id'), 'hw_disk_bus': ('image_meta_props', 'hw_disk_bus'), 'hw_disk_type': ('image_meta_props', 'hw_disk_type'), 'hw_floppy_bus': ('image_meta_props', 'hw_floppy_bus'), 'hw_firmware_type': ('image_meta_props', 'hw_firmware_type'), 'hw_ipxe_boot': ('image_meta_props', 'hw_ipxe_boot'), 'hw_machine_type': ('image_meta_props', 'hw_machine_type'), 'hw_mem_page_size': ('image_meta_props', 'hw_mem_page_size'), 'hw_numa_nodes': ('image_meta_props', 'hw_numa_nodes'), 'hw_numa_cpus': ('image_meta_props', 'hw_numa_cpus'), 'hw_numa_mem': ('image_meta_props', 'hw_numa_mem'), 'hw_pointer_model': ('image_meta_props', 'hw_pointer_model'), 'hw_qemu_guest_agent': ('image_meta_props', 'hw_qemu_guest_agent'), 'hw_rescue_bus': ('image_meta_props', 'hw_rescue_bus'), 'hw_rescue_device': ('image_meta_props', 'hw_rescue_device'), 'hw_rng_model': ('image_meta_props', 'hw_rng_model'), 'hw_serial_port_count': ('image_meta_props', 'hw_serial_port_count'), 'hw_scsi_model': ('image_meta_props', 'hw_scsi_model'), 'hw_video_model': ('image_meta_props', 'hw_video_model'), 'hw_video_ram': ('image_meta_props', 'hw_video_ram'), 'hw_vif_model': ('image_meta_props', 'hw_vif_model'), 'hw_vm_mode': ('image_meta_props', 'hw_vm_mode'), 'hw_watchdog_action': ('image_meta_props', 'hw_watchdog_action'), 'hw_vif_multiqueue_enabled': ('image_meta_props', 'hw_vif_multiqueue_enabled'), 'img_bittorrent': ('image_meta_props', 'img_bittorrent'), 'img_bdm_v2': ('image_meta_props', 'img_bdm_v2'), 'img_block_device_mapping': ('image_meta_props', 'img_block_device_mapping'), 'img_cache_in_nova': ('image_meta_props', 'img_cache_in_nova'), 'img_compression_level': ('image_meta_props', 'img_compression_level'), 'img_hv_requested_version': ('image_meta_props', 'img_hv_requested_version'), 'img_hv_type': ('image_meta_props', 'img_hv_type'), 'img_config_drive': ('image_meta_props', 'img_config_drive'), 'img_linked_clone': ('image_meta_props', 'img_linked_clone'), 'img_mappings': ('image_meta_props', 'img_mappings'), 'img_owner_id': ('image_meta_props', 'img_owner_id'), 'img_root_device_name': ('image_meta_props', 'img_root_device_name'), 'img_use_agent': ('image_meta_props', 'img_use_agent'), 'img_version': ('image_meta_props', 'img_version'), 'img_signature': ('image_meta_props', 'img_signature'), 'img_signature_hash_method': ('image_meta_props', 'img_signature_hash_method'), 'img_signature_certificate_uuid': ('image_meta_props', 'img_signature_certificate_uuid'), 'img_signature_key_type': ('image_meta_props', 'img_signature_key_type'), 'img_hide_hypervisor_id': ('image_meta_props', 'img_hide_hypervisor_id'), 'os_admin_user': ('image_meta_props', 'os_admin_user'), 'os_command_line': ('image_meta_props', 'os_command_line'), 'os_distro': ('image_meta_props', 'os_distro'), 'os_require_quiesce': ('image_meta_props', 'os_require_quiesce'), 'os_secure_boot': ('image_meta_props', 'os_secure_boot'), 'os_skip_agent_inject_files_at_boot': ('image_meta_props', 'os_skip_agent_inject_files_at_boot'), 'os_skip_agent_inject_ssh': ('image_meta_props', 'os_skip_agent_inject_ssh'), 'os_type': ('image_meta_props', 'os_type'), 'traits_required': ('image_meta_props', 'traits_required') } fields = { 'hw_architecture': fields.ArchitectureField(), 'hw_auto_disk_config': fields.StringField(), 'hw_boot_menu': fields.FlexibleBooleanField(), 'hw_cdrom_bus': fields.DiskBusField(), 'hw_cpu_cores': fields.IntegerField(), 'hw_cpu_sockets': fields.IntegerField(), 'hw_cpu_max_cores': fields.IntegerField(), 'hw_cpu_max_sockets': fields.IntegerField(), 'hw_cpu_max_threads': fields.IntegerField(), 'hw_cpu_policy': fields.CPUAllocationPolicyField(), 'hw_cpu_thread_policy': fields.CPUThreadAllocationPolicyField(), 'hw_cpu_realtime_mask': fields.StringField(), 'hw_cpu_threads': fields.IntegerField(), 'hw_device_id': fields.IntegerField(), 'hw_disk_bus': fields.DiskBusField(), 'hw_disk_type': fields.StringField(), 'hw_floppy_bus': fields.DiskBusField(), 'hw_firmware_type': fields.FirmwareTypeField(), 'hw_ipxe_boot': fields.FlexibleBooleanField(), 'hw_machine_type': fields.StringField(), 'hw_mem_page_size': fields.StringField(), 'hw_numa_nodes': fields.IntegerField(), 'hw_numa_cpus': fields.ListOfSetsOfIntegersField(), 'hw_numa_mem': fields.ListOfIntegersField(), 'hw_pointer_model': fields.PointerModelField(), 'hw_qemu_guest_agent': fields.FlexibleBooleanField(), 'hw_rescue_bus': fields.DiskBusField(), 'hw_rescue_device': fields.BlockDeviceTypeField(), 'hw_rng_model': fields.RNGModelField(), 'hw_serial_port_count': fields.IntegerField(), 'hw_scsi_model': fields.SCSIModelField(), 'hw_video_model': fields.VideoModelField(), 'hw_video_ram': fields.IntegerField(), 'hw_vif_model': fields.VIFModelField(), 'hw_vm_mode': fields.VMModeField(), 'hw_watchdog_action': fields.WatchdogActionField(), 'hw_vif_multiqueue_enabled': fields.FlexibleBooleanField(), 'img_bittorrent': fields.FlexibleBooleanField(), 'img_bdm_v2': fields.FlexibleBooleanField(), 'img_block_device_mapping': fields.ListOfDictOfNullableStringsField(), 'img_cache_in_nova': fields.FlexibleBooleanField(), 'img_compression_level': fields.IntegerField(), 'img_hv_requested_version': fields.VersionPredicateField(), 'img_hv_type': fields.HVTypeField(), 'img_config_drive': fields.ConfigDrivePolicyField(), 'img_linked_clone': fields.FlexibleBooleanField(), 'img_mappings': fields.ListOfDictOfNullableStringsField(), 'img_owner_id': fields.StringField(), 'img_root_device_name': fields.StringField(), 'img_use_agent': fields.FlexibleBooleanField(), 'img_version': fields.IntegerField(), 'img_signature': fields.StringField(), 'img_signature_hash_method': fields.ImageSignatureHashTypeField(), 'img_signature_certificate_uuid': fields.UUIDField(), 'img_signature_key_type': fields.ImageSignatureKeyTypeField(), 'img_hide_hypervisor_id': fields.FlexibleBooleanField(), 'os_admin_user': fields.StringField(), 'os_command_line': fields.StringField(), 'os_distro': fields.StringField(), 'os_require_quiesce': fields.FlexibleBooleanField(), 'os_secure_boot': fields.SecureBootField(), 'os_skip_agent_inject_files_at_boot': fields.FlexibleBooleanField(), 'os_skip_agent_inject_ssh': fields.FlexibleBooleanField(), 'os_type': fields.OSTypeField(), 'traits_required': fields.ListOfStringsField() } def __init__(self, image_meta_props): super(ImageMetaPropsPayload, self).__init__() # NOTE(takashin): If fields are not set in the ImageMetaProps object, # it will not set the fields in the ImageMetaPropsPayload # in order to avoid too many fields whose values are None. self.populate_schema(set_none=False, image_meta_props=image_meta_props)
class ImageMetaProps(base.NovaObject): # Version 1.0: Initial version # Version 1.1: added os_require_quiesce field # Version 1.2: added img_hv_type and img_hv_requested_version fields # Version 1.3: HVSpec version 1.1 # Version 1.4: added hw_vif_multiqueue_enabled field # Version 1.5: added os_admin_user field # Version 1.6: Added 'lxc' and 'uml' enum types to DiskBusField # Version 1.7: added img_config_drive field # Version 1.8: Added 'lxd' to hypervisor types # Version 1.9: added hw_cpu_thread_policy field # Version 1.10: added hw_cpu_realtime_mask field # Version 1.11: Added hw_firmware_type field # Version 1.12: Added properties for image signature verification # Version 1.13: added os_secure_boot field # Version 1.14: Added 'hw_pointer_model' field # Version 1.15: Added hw_rescue_bus and hw_rescue_device. # Version 1.16: WatchdogActionField supports 'disabled' enum. # Version 1.17: Add lan9118 as valid nic for hw_vif_model property for qemu # Version 1.18: Pull signature properties from cursive library # Version 1.19: Added 'img_hide_hypervisor_id' type field # Version 1.20: Added 'traits_required' list field # Version 1.21: Added 'hw_time_hpet' field # Version 1.22: Added 'gop', 'virtio' and 'none' to hw_video_model field # Version 1.23: Added 'hw_pmu' field VERSION = '1.23' def obj_make_compatible(self, primitive, target_version): super(ImageMetaProps, self).obj_make_compatible(primitive, target_version) target_version = versionutils.convert_version_to_tuple(target_version) if target_version < (1, 23): primitive.pop('hw_pmu', None) # NOTE(sean-k-mooney): unlike other nova object we version this object # when composed object are updated. if target_version < (1, 22): video = primitive.get('hw_video_model', None) if video in ('gop', 'virtio', 'none'): raise exception.ObjectActionError( action='obj_make_compatible', reason='hw_video_model=%s not supported in version %s' % (video, target_version)) if target_version < (1, 21): primitive.pop('hw_time_hpet', None) if target_version < (1, 20): primitive.pop('traits_required', None) if target_version < (1, 19): primitive.pop('img_hide_hypervisor_id', None) if target_version < (1, 16) and 'hw_watchdog_action' in primitive: # Check to see if hw_watchdog_action was set to 'disabled' and if # so, remove it since not specifying it is the same behavior. if primitive['hw_watchdog_action'] == \ fields.WatchdogAction.DISABLED: primitive.pop('hw_watchdog_action') if target_version < (1, 15): primitive.pop('hw_rescue_bus', None) primitive.pop('hw_rescue_device', None) if target_version < (1, 14): primitive.pop('hw_pointer_model', None) if target_version < (1, 13): primitive.pop('os_secure_boot', None) if target_version < (1, 11): primitive.pop('hw_firmware_type', None) if target_version < (1, 10): primitive.pop('hw_cpu_realtime_mask', None) if target_version < (1, 9): primitive.pop('hw_cpu_thread_policy', None) if target_version < (1, 7): primitive.pop('img_config_drive', None) if target_version < (1, 5): primitive.pop('os_admin_user', None) if target_version < (1, 4): primitive.pop('hw_vif_multiqueue_enabled', None) if target_version < (1, 2): primitive.pop('img_hv_type', None) primitive.pop('img_hv_requested_version', None) if target_version < (1, 1): primitive.pop('os_require_quiesce', None) if target_version < (1, 6): bus = primitive.get('hw_disk_bus', None) if bus in ('lxc', 'uml'): raise exception.ObjectActionError( action='obj_make_compatible', reason='hw_disk_bus=%s not supported in version %s' % (bus, target_version)) # Maximum number of NUMA nodes permitted for the guest topology NUMA_NODES_MAX = 128 # 'hw_' - settings affecting the guest virtual machine hardware # 'img_' - settings affecting the use of images by the compute node # 'os_' - settings affecting the guest operating system setup # 'traits_required' - The required traits associated with the image fields = { # name of guest hardware architecture eg i686, x86_64, ppc64 'hw_architecture': fields.ArchitectureField(), # used to decide to expand root disk partition and fs to full size of # root disk 'hw_auto_disk_config': fields.StringField(), # whether to display BIOS boot device menu 'hw_boot_menu': fields.FlexibleBooleanField(), # name of the CDROM bus to use eg virtio, scsi, ide 'hw_cdrom_bus': fields.DiskBusField(), # preferred number of CPU cores per socket 'hw_cpu_cores': fields.IntegerField(), # preferred number of CPU sockets 'hw_cpu_sockets': fields.IntegerField(), # maximum number of CPU cores per socket 'hw_cpu_max_cores': fields.IntegerField(), # maximum number of CPU sockets 'hw_cpu_max_sockets': fields.IntegerField(), # maximum number of CPU threads per core 'hw_cpu_max_threads': fields.IntegerField(), # CPU allocation policy 'hw_cpu_policy': fields.CPUAllocationPolicyField(), # CPU thread allocation policy 'hw_cpu_thread_policy': fields.CPUThreadAllocationPolicyField(), # CPU mask indicates which vCPUs will have realtime enable, # example ^0-1 means that all vCPUs except 0 and 1 will have a # realtime policy. 'hw_cpu_realtime_mask': fields.StringField(), # preferred number of CPU threads per core 'hw_cpu_threads': fields.IntegerField(), # guest ABI version for guest xentools either 1 or 2 (or 3 - depends on # Citrix PV tools version installed in image) 'hw_device_id': fields.IntegerField(), # name of the hard disk bus to use eg virtio, scsi, ide 'hw_disk_bus': fields.DiskBusField(), # allocation mode eg 'preallocated' 'hw_disk_type': fields.StringField(), # name of the floppy disk bus to use eg fd, scsi, ide 'hw_floppy_bus': fields.DiskBusField(), # This indicates the guest needs UEFI firmware 'hw_firmware_type': fields.FirmwareTypeField(), # boolean - used to trigger code to inject networking when booting a CD # image with a network boot image 'hw_ipxe_boot': fields.FlexibleBooleanField(), # There are sooooooooooo many possible machine types in # QEMU - several new ones with each new release - that it # is not practical to enumerate them all. So we use a free # form string 'hw_machine_type': fields.StringField(), # One of the magic strings 'small', 'any', 'large' # or an explicit page size in KB (eg 4, 2048, ...) 'hw_mem_page_size': fields.StringField(), # Number of guest NUMA nodes 'hw_numa_nodes': fields.IntegerField(), # Each list entry corresponds to a guest NUMA node and the # set members indicate CPUs for that node 'hw_numa_cpus': fields.ListOfSetsOfIntegersField(), # Each list entry corresponds to a guest NUMA node and the # list value indicates the memory size of that node. 'hw_numa_mem': fields.ListOfIntegersField(), # Generic property to specify the pointer model type. 'hw_pointer_model': fields.PointerModelField(), # boolean 'true' or 'false' to enable virtual performance # monitoring unit (vPMU). 'hw_pmu': fields.FlexibleBooleanField(), # boolean 'yes' or 'no' to enable QEMU guest agent 'hw_qemu_guest_agent': fields.FlexibleBooleanField(), # name of the rescue bus to use with the associated rescue device. 'hw_rescue_bus': fields.DiskBusField(), # name of rescue device to use. 'hw_rescue_device': fields.BlockDeviceTypeField(), # name of the RNG device type eg virtio 'hw_rng_model': fields.RNGModelField(), # boolean 'true' or 'false' to enable HPET 'hw_time_hpet': fields.FlexibleBooleanField(), # number of serial ports to create 'hw_serial_port_count': fields.IntegerField(), # name of the SCSI bus controller eg 'virtio-scsi', 'lsilogic', etc 'hw_scsi_model': fields.SCSIModelField(), # name of the video adapter model to use, eg cirrus, vga, xen, qxl 'hw_video_model': fields.VideoModelField(), # MB of video RAM to provide eg 64 'hw_video_ram': fields.IntegerField(), # name of a NIC device model eg virtio, e1000, rtl8139 'hw_vif_model': fields.VIFModelField(), # "xen" vs "hvm" 'hw_vm_mode': fields.VMModeField(), # action to take when watchdog device fires eg reset, poweroff, pause, # none 'hw_watchdog_action': fields.WatchdogActionField(), # boolean - If true, this will enable the virtio-multiqueue feature 'hw_vif_multiqueue_enabled': fields.FlexibleBooleanField(), # if true download using bittorrent 'img_bittorrent': fields.FlexibleBooleanField(), # Which data format the 'img_block_device_mapping' field is # using to represent the block device mapping 'img_bdm_v2': fields.FlexibleBooleanField(), # Block device mapping - the may can be in one or two completely # different formats. The 'img_bdm_v2' field determines whether # it is in legacy format, or the new current format. Ideally # we would have a formal data type for this field instead of a # dict, but with 2 different formats to represent this is hard. # See nova/block_device.py from_legacy_mapping() for the complex # conversion code. So for now leave it as a dict and continue # to use existing code that is able to convert dict into the # desired internal BDM formats 'img_block_device_mapping': fields.ListOfDictOfNullableStringsField(), # boolean - if True, and image cache set to "some" decides if image # should be cached on host when server is booted on that host 'img_cache_in_nova': fields.FlexibleBooleanField(), # Compression level for images. (1-9) 'img_compression_level': fields.IntegerField(), # hypervisor supported version, eg. '>=2.6' 'img_hv_requested_version': fields.VersionPredicateField(), # type of the hypervisor, eg kvm, ironic, xen 'img_hv_type': fields.HVTypeField(), # Whether the image needs/expected config drive 'img_config_drive': fields.ConfigDrivePolicyField(), # boolean flag to set space-saving or performance behavior on the # Datastore 'img_linked_clone': fields.FlexibleBooleanField(), # Image mappings - related to Block device mapping data - mapping # of virtual image names to device names. This could be represented # as a formal data type, but is left as dict for same reason as # img_block_device_mapping field. It would arguably make sense for # the two to be combined into a single field and data type in the # future. 'img_mappings': fields.ListOfDictOfNullableStringsField(), # image project id (set on upload) 'img_owner_id': fields.StringField(), # root device name, used in snapshotting eg /dev/<blah> 'img_root_device_name': fields.StringField(), # boolean - if false don't talk to nova agent 'img_use_agent': fields.FlexibleBooleanField(), # integer value 1 'img_version': fields.IntegerField(), # base64 of encoding of image signature 'img_signature': fields.StringField(), # string indicating hash method used to compute image signature 'img_signature_hash_method': fields.ImageSignatureHashTypeField(), # string indicating Castellan uuid of certificate # used to compute the image's signature 'img_signature_certificate_uuid': fields.UUIDField(), # string indicating type of key used to compute image signature 'img_signature_key_type': fields.ImageSignatureKeyTypeField(), # boolean - hide hypervisor signature on instance 'img_hide_hypervisor_id': fields.FlexibleBooleanField(), # string of username with admin privileges 'os_admin_user': fields.StringField(), # string of boot time command line arguments for the guest kernel 'os_command_line': fields.StringField(), # the name of the specific guest operating system distro. This # is not done as an Enum since the list of operating systems is # growing incredibly fast, and valid values can be arbitrarily # user defined. Nova has no real need for strict validation so # leave it freeform 'os_distro': fields.StringField(), # boolean - if true, then guest must support disk quiesce # or snapshot operation will be denied 'os_require_quiesce': fields.FlexibleBooleanField(), # Secure Boot feature will be enabled by setting the "os_secure_boot" # image property to "required". Other options can be: "disabled" or # "optional". # "os:secure_boot" flavor extra spec value overrides the image property # value. 'os_secure_boot': fields.SecureBootField(), # boolean - if using agent don't inject files, assume someone else is # doing that (cloud-init) 'os_skip_agent_inject_files_at_boot': fields.FlexibleBooleanField(), # boolean - if using agent don't try inject ssh key, assume someone # else is doing that (cloud-init) 'os_skip_agent_inject_ssh': fields.FlexibleBooleanField(), # The guest operating system family such as 'linux', 'windows' - this # is a fairly generic type. For a detailed type consider os_distro # instead 'os_type': fields.OSTypeField(), # The required traits associated with the image. Traits are expected to # be defined as starting with `trait:` like below: # trait:HW_CPU_X86_AVX2=required # for trait in image_meta.traits_required: # will yield trait strings such as 'HW_CPU_X86_AVX2' 'traits_required': fields.ListOfStringsField(), } # The keys are the legacy property names and # the values are the current preferred names _legacy_property_map = { 'architecture': 'hw_architecture', 'owner_id': 'img_owner_id', 'vmware_disktype': 'hw_disk_type', 'vmware_image_version': 'img_version', 'vmware_ostype': 'os_distro', 'auto_disk_config': 'hw_auto_disk_config', 'ipxe_boot': 'hw_ipxe_boot', 'xenapi_device_id': 'hw_device_id', 'xenapi_image_compression_level': 'img_compression_level', 'vmware_linked_clone': 'img_linked_clone', 'xenapi_use_agent': 'img_use_agent', 'xenapi_skip_agent_inject_ssh': 'os_skip_agent_inject_ssh', 'xenapi_skip_agent_inject_files_at_boot': 'os_skip_agent_inject_files_at_boot', 'cache_in_nova': 'img_cache_in_nova', 'vm_mode': 'hw_vm_mode', 'bittorrent': 'img_bittorrent', 'mappings': 'img_mappings', 'block_device_mapping': 'img_block_device_mapping', 'bdm_v2': 'img_bdm_v2', 'root_device_name': 'img_root_device_name', 'hypervisor_version_requires': 'img_hv_requested_version', 'hypervisor_type': 'img_hv_type', } # TODO(berrange): Need to run this from a data migration # at some point so we can eventually kill off the compat def _set_attr_from_legacy_names(self, image_props): for legacy_key in self._legacy_property_map: new_key = self._legacy_property_map[legacy_key] if legacy_key not in image_props: continue setattr(self, new_key, image_props[legacy_key]) vmware_adaptertype = image_props.get("vmware_adaptertype") if vmware_adaptertype == "ide": setattr(self, "hw_disk_bus", "ide") elif vmware_adaptertype: setattr(self, "hw_disk_bus", "scsi") setattr(self, "hw_scsi_model", vmware_adaptertype) def _set_numa_mem(self, image_props): hw_numa_mem = [] hw_numa_mem_set = False for cellid in range(ImageMetaProps.NUMA_NODES_MAX): memprop = "hw_numa_mem.%d" % cellid if memprop not in image_props: break hw_numa_mem.append(int(image_props[memprop])) hw_numa_mem_set = True del image_props[memprop] if hw_numa_mem_set: self.hw_numa_mem = hw_numa_mem def _set_numa_cpus(self, image_props): hw_numa_cpus = [] hw_numa_cpus_set = False for cellid in range(ImageMetaProps.NUMA_NODES_MAX): cpuprop = "hw_numa_cpus.%d" % cellid if cpuprop not in image_props: break hw_numa_cpus.append(hardware.parse_cpu_spec(image_props[cpuprop])) hw_numa_cpus_set = True del image_props[cpuprop] if hw_numa_cpus_set: self.hw_numa_cpus = hw_numa_cpus def _set_attr_from_current_names(self, image_props): for key in self.fields: # The two NUMA fields need special handling to # un-stringify them correctly if key == "hw_numa_mem": self._set_numa_mem(image_props) elif key == "hw_numa_cpus": self._set_numa_cpus(image_props) else: # traits_required will be populated by # _set_attr_from_trait_names if key not in image_props or key == "traits_required": continue setattr(self, key, image_props[key]) def _set_attr_from_trait_names(self, image_props): for trait in [ six.text_type(k[6:]) for k, v in image_props.items() if six.text_type(k).startswith("trait:") and six.text_type(v) == six.text_type('required') ]: if 'traits_required' not in self: self.traits_required = [] self.traits_required.append(trait) @classmethod def from_dict(cls, image_props): """Create instance from image properties dict :param image_props: dictionary of image metadata properties Creates a new object instance, initializing from a dictionary of image metadata properties :returns: an ImageMetaProps instance """ obj = cls() # We look to see if the dict has entries for any # of the legacy property names first. Then we use # the current property names. That way if both the # current and legacy names are set, the value # associated with the current name takes priority obj._set_attr_from_legacy_names(image_props) obj._set_attr_from_current_names(image_props) obj._set_attr_from_trait_names(image_props) return obj def get(self, name, defvalue=None): """Get the value of an attribute :param name: the attribute to request :param defvalue: the default value if not set This returns the value of an attribute if it is currently set, otherwise it will return None. This differs from accessing props.attrname, because that will raise an exception if the attribute has no value set. So instead of if image_meta.properties.obj_attr_is_set("some_attr"): val = image_meta.properties.some_attr else val = None Callers can rely on unconditional access val = image_meta.properties.get("some_attr") :returns: the attribute value or None """ if not self.obj_attr_is_set(name): return defvalue return getattr(self, name)