Пример #1
0
 def setUp(self):
     super(TestListOfSetsOfIntegers, self).setUp()
     self.field = fields.ListOfSetsOfIntegersField()
     self.coerce_good_values = [([set(['1', 2]), set([3, '4'])],
                                 [set([1, 2]), set([3, 4])])]
     self.coerce_bad_values = [[set(['foo'])]]
     self.to_primitive_values = [([set([1])], [tuple([1])])]
     self.from_primitive_values = [([tuple([1])], [set([1])])]
Пример #2
0
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)
Пример #3
0
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)
Пример #4
0
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)
Пример #5
0
class NUMACell(base.NovaObject):
    # Version 1.0: Initial version
    # Version 1.1: Added pinned_cpus and siblings fields
    # Version 1.2: Added mempages field
    VERSION = '1.2'

    fields = {
        'id': fields.IntegerField(read_only=True),
        'cpuset': fields.SetOfIntegersField(),
        'memory': fields.IntegerField(),
        'cpu_usage': fields.IntegerField(default=0),
        'memory_usage': fields.IntegerField(default=0),
        'pinned_cpus': fields.SetOfIntegersField(),
        'siblings': fields.ListOfSetsOfIntegersField(),
        'mempages': fields.ListOfObjectsField('NUMAPagesTopology'),
    }

    obj_relationships = {'NUMAPagesTopology': [('1.2', '1.0')]}

    def __init__(self, **kwargs):
        super(NUMACell, self).__init__(**kwargs)
        if 'pinned_cpus' not in kwargs:
            self.pinned_cpus = set()
        if 'siblings' not in kwargs:
            self.siblings = []

    @property
    def free_cpus(self):
        return self.cpuset - self.pinned_cpus or set()

    def _to_dict(self):
        return {
            'id': self.id,
            'cpus': hardware.format_cpu_spec(self.cpuset, allow_ranges=False),
            'mem': {
                'total': self.memory,
                'used': self.memory_usage
            },
            'cpu_usage': self.cpu_usage
        }

    @classmethod
    def _from_dict(cls, data_dict):
        cpuset = hardware.parse_cpu_spec(data_dict.get('cpus', ''))
        cpu_usage = data_dict.get('cpu_usage', 0)
        memory = data_dict.get('mem', {}).get('total', 0)
        memory_usage = data_dict.get('mem', {}).get('used', 0)
        cell_id = data_dict.get('id')
        return cls(id=cell_id,
                   cpuset=cpuset,
                   memory=memory,
                   cpu_usage=cpu_usage,
                   memory_usage=memory_usage,
                   mempages=[])

    def can_fit_hugepages(self, pagesize, memory):
        """Returns whether memory can fit into hugepages size

        :param pagesize: a page size in KibB
        :param memory: a memory size asked to fit in KiB

        :returns: whether memory can fit in hugepages
        :raises: MemoryPageSizeNotSupported if page size not supported
        """
        for pages in self.mempages:
            if pages.size_kb == pagesize:
                return (memory <= pages.free_kb
                        and (memory % pages.size_kb) == 0)
        raise exception.MemoryPageSizeNotSupported(pagesize=pagesize)
Пример #6
0
class NUMACell(base.NovaObject):
    # Version 1.0: Initial version
    # Version 1.1: Added pinned_cpus and siblings fields
    # Version 1.2: Added mempages field
    VERSION = '1.2'

    fields = {
        'id': fields.IntegerField(read_only=True),
        'cpuset': fields.SetOfIntegersField(),
        'memory': fields.IntegerField(),
        'cpu_usage': fields.IntegerField(default=0),
        'memory_usage': fields.IntegerField(default=0),
        'pinned_cpus': fields.SetOfIntegersField(),
        'siblings': fields.ListOfSetsOfIntegersField(),
        'mempages': fields.ListOfObjectsField('NUMAPagesTopology'),
    }

    def __eq__(self, other):
        return all_things_equal(self, other)

    def __ne__(self, other):
        return not (self == other)

    @property
    def free_cpus(self):
        return self.cpuset - self.pinned_cpus or set()

    @property
    def free_siblings(self):
        return [sibling_set & self.free_cpus for sibling_set in self.siblings]

    @property
    def avail_cpus(self):
        return len(self.free_cpus)

    @property
    def avail_memory(self):
        return self.memory - self.memory_usage

    def pin_cpus(self, cpus):
        if cpus - self.cpuset:
            raise exception.CPUPinningUnknown(requested=list(cpus),
                                              cpuset=list(self.pinned_cpus))
        if self.pinned_cpus & cpus:
            raise exception.CPUPinningInvalid(requested=list(cpus),
                                              pinned=list(self.pinned_cpus))
        self.pinned_cpus |= cpus

    def unpin_cpus(self, cpus):
        if cpus - self.cpuset:
            raise exception.CPUPinningUnknown(requested=list(cpus),
                                              cpuset=list(self.pinned_cpus))
        if (self.pinned_cpus & cpus) != cpus:
            raise exception.CPUPinningInvalid(requested=list(cpus),
                                              pinned=list(self.pinned_cpus))
        self.pinned_cpus -= cpus

    def _to_dict(self):
        return {
            'id': self.id,
            'cpus': hardware.format_cpu_spec(self.cpuset, allow_ranges=False),
            'mem': {
                'total': self.memory,
                'used': self.memory_usage
            },
            'cpu_usage': self.cpu_usage
        }

    @classmethod
    def _from_dict(cls, data_dict):
        cpuset = hardware.parse_cpu_spec(data_dict.get('cpus', ''))
        cpu_usage = data_dict.get('cpu_usage', 0)
        memory = data_dict.get('mem', {}).get('total', 0)
        memory_usage = data_dict.get('mem', {}).get('used', 0)
        cell_id = data_dict.get('id')
        return cls(id=cell_id,
                   cpuset=cpuset,
                   memory=memory,
                   cpu_usage=cpu_usage,
                   memory_usage=memory_usage,
                   mempages=[],
                   pinned_cpus=set([]),
                   siblings=[])

    def can_fit_hugepages(self, pagesize, memory):
        """Returns whether memory can fit into hugepages size

        :param pagesize: a page size in KibB
        :param memory: a memory size asked to fit in KiB

        :returns: whether memory can fit in hugepages
        :raises: MemoryPageSizeNotSupported if page size not supported
        """
        for pages in self.mempages:
            if pages.size_kb == pagesize:
                return (memory <= pages.free_kb
                        and (memory % pages.size_kb) == 0)
        raise exception.MemoryPageSizeNotSupported(pagesize=pagesize)
Пример #7
0
class NUMACell(base.NovaObject):
    # Version 1.0: Initial version
    # Version 1.1: Added pinned_cpus and siblings fields
    # Version 1.2: Added mempages field
    # Version 1.3: Add network_metadata field
    VERSION = '1.3'

    fields = {
        'id': fields.IntegerField(read_only=True),
        'cpuset': fields.SetOfIntegersField(),
        'memory': fields.IntegerField(),
        'cpu_usage': fields.IntegerField(default=0),
        'memory_usage': fields.IntegerField(default=0),
        'pinned_cpus': fields.SetOfIntegersField(),
        'siblings': fields.ListOfSetsOfIntegersField(),
        'mempages': fields.ListOfObjectsField('NUMAPagesTopology'),
        'network_metadata': fields.ObjectField('NetworkMetadata'),
    }

    def obj_make_compatible(self, primitive, target_version):
        super(NUMACell, self).obj_make_compatible(primitive, target_version)
        target_version = versionutils.convert_version_to_tuple(target_version)
        if target_version < (1, 3):
            primitive.pop('network_metadata', None)

    def __eq__(self, other):
        return all_things_equal(self, other)

    def __ne__(self, other):
        return not (self == other)

    @property
    def free_cpus(self):
        return self.cpuset - self.pinned_cpus or set()

    @property
    def free_siblings(self):
        return [sibling_set & self.free_cpus for sibling_set in self.siblings]

    @property
    def avail_cpus(self):
        return len(self.free_cpus)

    @property
    def avail_memory(self):
        return self.memory - self.memory_usage

    @property
    def has_threads(self):
        """Check if SMT threads, a.k.a. HyperThreads, are present."""
        return any(len(sibling_set) > 1 for sibling_set in self.siblings)

    def pin_cpus(self, cpus):
        if cpus - self.cpuset:
            raise exception.CPUPinningUnknown(requested=list(cpus),
                                              cpuset=list(self.cpuset))
        if self.pinned_cpus & cpus:
            raise exception.CPUPinningInvalid(requested=list(cpus),
                                              free=list(self.cpuset -
                                                        self.pinned_cpus))
        self.pinned_cpus |= cpus

    def unpin_cpus(self, cpus):
        if cpus - self.cpuset:
            raise exception.CPUUnpinningUnknown(requested=list(cpus),
                                                cpuset=list(self.cpuset))
        if (self.pinned_cpus & cpus) != cpus:
            raise exception.CPUUnpinningInvalid(requested=list(cpus),
                                                pinned=list(self.pinned_cpus))
        self.pinned_cpus -= cpus

    def pin_cpus_with_siblings(self, cpus):
        pin_siblings = set()
        for sib in self.siblings:
            if cpus & sib:
                pin_siblings.update(sib)
        self.pin_cpus(pin_siblings)

    def unpin_cpus_with_siblings(self, cpus):
        pin_siblings = set()
        for sib in self.siblings:
            if cpus & sib:
                pin_siblings.update(sib)
        self.unpin_cpus(pin_siblings)

    @classmethod
    def _from_dict(cls, data_dict):
        cpuset = hardware.parse_cpu_spec(data_dict.get('cpus', ''))
        cpu_usage = data_dict.get('cpu_usage', 0)
        memory = data_dict.get('mem', {}).get('total', 0)
        memory_usage = data_dict.get('mem', {}).get('used', 0)
        cell_id = data_dict.get('id')
        return cls(id=cell_id,
                   cpuset=cpuset,
                   memory=memory,
                   cpu_usage=cpu_usage,
                   memory_usage=memory_usage,
                   mempages=[],
                   pinned_cpus=set([]),
                   siblings=[])

    def can_fit_hugepages(self, pagesize, memory):
        """Returns whether memory can fit into hugepages size

        :param pagesize: a page size in KibB
        :param memory: a memory size asked to fit in KiB

        :returns: whether memory can fit in hugepages
        :raises: MemoryPageSizeNotSupported if page size not supported
        """
        for pages in self.mempages:
            if pages.size_kb == pagesize:
                return (memory <= pages.free_kb
                        and (memory % pages.size_kb) == 0)
        raise exception.MemoryPageSizeNotSupported(pagesize=pagesize)
Пример #8
0
class NUMACell(base.NovaObject):
    # Version 1.0: Initial version
    # Version 1.1: Added pinned_cpus and siblings fields
    # Version 1.2: Added mempages field
    # Version 1.3: Add network_metadata field
    # Version 1.4: Add pcpuset
    VERSION = '1.4'

    fields = {
        'id': obj_fields.IntegerField(read_only=True),
        'cpuset': obj_fields.SetOfIntegersField(),
        'pcpuset': obj_fields.SetOfIntegersField(),
        'memory': obj_fields.IntegerField(),
        'cpu_usage': obj_fields.IntegerField(default=0),
        'memory_usage': obj_fields.IntegerField(default=0),
        'pinned_cpus': obj_fields.SetOfIntegersField(),
        'siblings': obj_fields.ListOfSetsOfIntegersField(),
        'mempages': obj_fields.ListOfObjectsField('NUMAPagesTopology'),
        'network_metadata': obj_fields.ObjectField('NetworkMetadata'),
    }

    def obj_make_compatible(self, primitive, target_version):
        super(NUMACell, self).obj_make_compatible(primitive, target_version)
        target_version = versionutils.convert_version_to_tuple(target_version)
        if target_version < (1, 4):
            primitive.pop('pcpuset', None)
        if target_version < (1, 3):
            primitive.pop('network_metadata', None)

    def __eq__(self, other):
        return base.all_things_equal(self, other)

    def __ne__(self, other):
        return not (self == other)

    @property
    def free_pcpus(self):
        """Return available dedicated CPUs."""
        return self.pcpuset - self.pinned_cpus or set()

    @property
    def free_siblings(self):
        """Return available dedicated CPUs in their sibling set form."""
        return [sibling_set & self.free_pcpus for sibling_set in self.siblings]

    @property
    def avail_pcpus(self):
        """Return number of available dedicated CPUs."""
        return len(self.free_pcpus)

    @property
    def avail_memory(self):
        return self.memory - self.memory_usage

    @property
    def has_threads(self):
        """Check if SMT threads, a.k.a. HyperThreads, are present."""
        return any(len(sibling_set) > 1 for sibling_set in self.siblings)

    def pin_cpus(self, cpus):
        if cpus - self.pcpuset:
            raise exception.CPUPinningUnknown(requested=list(cpus),
                                              available=list(self.pcpuset))

        if self.pinned_cpus & cpus:
            available = list(self.pcpuset - self.pinned_cpus)
            raise exception.CPUPinningInvalid(requested=list(cpus),
                                              available=available)

        self.pinned_cpus |= cpus

    def unpin_cpus(self, cpus):
        if cpus - self.pcpuset:
            raise exception.CPUUnpinningUnknown(requested=list(cpus),
                                                available=list(self.pcpuset))

        if (self.pinned_cpus & cpus) != cpus:
            raise exception.CPUUnpinningInvalid(requested=list(cpus),
                                                available=list(
                                                    self.pinned_cpus))

        self.pinned_cpus -= cpus

    def pin_cpus_with_siblings(self, cpus):
        pin_siblings = set()
        for sib in self.siblings:
            if cpus & sib:
                pin_siblings.update(sib)
        self.pin_cpus(pin_siblings)

    def unpin_cpus_with_siblings(self, cpus):
        pin_siblings = set()
        for sib in self.siblings:
            if cpus & sib:
                pin_siblings.update(sib)
        self.unpin_cpus(pin_siblings)

    def can_fit_pagesize(self, pagesize, memory, use_free=True):
        """Returns whether memory can fit into a given pagesize.

        :param pagesize: a page size in KibB
        :param memory: a memory size asked to fit in KiB
        :param use_free: if true, assess based on free memory rather than total
            memory. This means overcommit is not allowed, which should be the
            case for hugepages since these are memlocked by the kernel and
            can't be swapped out.

        :returns: whether memory can fit in hugepages
        :raises: MemoryPageSizeNotSupported if page size not supported
        """
        for pages in self.mempages:
            avail_kb = pages.free_kb if use_free else pages.total_kb
            if pages.size_kb == pagesize:
                return memory <= avail_kb and (memory % pages.size_kb) == 0
        raise exception.MemoryPageSizeNotSupported(pagesize=pagesize)