Example #1
0
    def test_parse_cpu_spec_valid_syntax_works(self):
        cpuset_ids = hw.parse_cpu_spec("1")
        self.assertEqual(set([1]), cpuset_ids)

        cpuset_ids = hw.parse_cpu_spec("1,2")
        self.assertEqual(set([1, 2]), cpuset_ids)

        cpuset_ids = hw.parse_cpu_spec(", ,   1 ,  ,,  2,    ,")
        self.assertEqual(set([1, 2]), cpuset_ids)

        cpuset_ids = hw.parse_cpu_spec("1-1")
        self.assertEqual(set([1]), cpuset_ids)

        cpuset_ids = hw.parse_cpu_spec(" 1 - 1, 1 - 2 , 1 -3")
        self.assertEqual(set([1, 2, 3]), cpuset_ids)

        cpuset_ids = hw.parse_cpu_spec("1,^2")
        self.assertEqual(set([1]), cpuset_ids)

        cpuset_ids = hw.parse_cpu_spec("1-2, ^1")
        self.assertEqual(set([2]), cpuset_ids)

        cpuset_ids = hw.parse_cpu_spec("1-3,5,^2")
        self.assertEqual(set([1, 3, 5]), cpuset_ids)

        cpuset_ids = hw.parse_cpu_spec(" 1 -    3        ,   ^2,        5")
        self.assertEqual(set([1, 3, 5]), cpuset_ids)

        cpuset_ids = hw.parse_cpu_spec(" 1,1, ^1")
        self.assertEqual(set([]), cpuset_ids)
Example #2
0
    def test_parse_cpu_spec_valid_syntax_works(self):
        cpuset_ids = hw.parse_cpu_spec("1")
        self.assertEqual(set([1]), cpuset_ids)

        cpuset_ids = hw.parse_cpu_spec("1,2")
        self.assertEqual(set([1, 2]), cpuset_ids)

        cpuset_ids = hw.parse_cpu_spec(", ,   1 ,  ,,  2,    ,")
        self.assertEqual(set([1, 2]), cpuset_ids)

        cpuset_ids = hw.parse_cpu_spec("1-1")
        self.assertEqual(set([1]), cpuset_ids)

        cpuset_ids = hw.parse_cpu_spec(" 1 - 1, 1 - 2 , 1 -3")
        self.assertEqual(set([1, 2, 3]), cpuset_ids)

        cpuset_ids = hw.parse_cpu_spec("1,^2")
        self.assertEqual(set([1]), cpuset_ids)

        cpuset_ids = hw.parse_cpu_spec("1-2, ^1")
        self.assertEqual(set([2]), cpuset_ids)

        cpuset_ids = hw.parse_cpu_spec("1-3,5,^2")
        self.assertEqual(set([1, 3, 5]), cpuset_ids)

        cpuset_ids = hw.parse_cpu_spec(" 1 -    3        ,   ^2,        5")
        self.assertEqual(set([1, 3, 5]), cpuset_ids)

        cpuset_ids = hw.parse_cpu_spec(" 1,1, ^1")
        self.assertEqual(set([]), cpuset_ids)
Example #3
0
    def _migrate_legacy_object(cls, context, instance_uuid, primitive):
        """Convert a pre-Liberty object to a real o.vo.

        Handle an unversioned object created prior to Liberty, by transforming
        to a versioned object and saving back the serialized version of this.

        :param context: RequestContext
        :param instance_uuid: The UUID of the instance this topology is
            associated with.
        :param primitive: A serialized representation of the legacy object.
        :returns: A serialized representation of the updated object.
        """
        obj = cls(
            instance_uuid=instance_uuid,
            cells=[
                InstanceNUMACell(
                    id=cell.get('id'),
                    cpuset=hardware.parse_cpu_spec(cell.get('cpus', '')),
                    pcpuset=set(),
                    memory=cell.get('mem', {}).get('total', 0),
                    pagesize=cell.get('pagesize'),
                ) for cell in primitive.get('cells', [])
            ],
        )
        db_obj = jsonutils.dumps(obj.obj_to_primitive())
        values = {
            'numa_topology': db_obj,
        }
        db.instance_extra_update_by_uuid(context, instance_uuid, values)
        return obj
 def _from_dict(cls, data_dict):
     # NOTE(sahid): Used as legacy, could be renamed in
     # _legacy_from_dict_ to the future to avoid confusing.
     cpuset = hardware.parse_cpu_spec(data_dict.get('cpus', ''))
     memory = data_dict.get('mem', {}).get('total', 0)
     cell_id = data_dict.get('id')
     pagesize = data_dict.get('pagesize')
     return cls(id=cell_id, cpuset=cpuset, memory=memory, pagesize=pagesize)
Example #5
0
 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)
Example #6
0
 def _from_dict(cls, data_dict):
     # NOTE(sahid): Used as legacy, could be renamed in
     # _legacy_from_dict_ to the future to avoid confusing.
     cpuset = hardware.parse_cpu_spec(data_dict.get('cpus', ''))
     memory = data_dict.get('mem', {}).get('total', 0)
     cell_id = data_dict.get('id')
     pagesize = data_dict.get('pagesize')
     return cls(id=cell_id, cpuset=cpuset,
                memory=memory, pagesize=pagesize)
Example #7
0
 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=[])
Example #8
0
    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
Example #9
0
 def obj_from_db_obj(cls, db_obj):
     if 'nova_object.name' in db_obj:
         obj_topology = cls.obj_from_primitive(db_obj)
     else:
         # NOTE(sahid): This compatibility code needs to stay until we can
         # guarantee that all compute nodes are using RPC API => 3.40.
         cell = db_obj['cells'][0]
         ram_ratio = cell['mem']['limit'] / float(cell['mem']['total'])
         cpu_ratio = cell['cpu_limit'] / float(
             len(hardware.parse_cpu_spec(cell['cpus'])))
         obj_topology = NUMATopologyLimits(cpu_allocation_ratio=cpu_ratio,
                                           ram_allocation_ratio=ram_ratio)
     return obj_topology
Example #10
0
    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
Example #11
0
 def obj_from_db_obj(cls, db_obj):
     if 'nova_object.name' in db_obj:
         obj_topology = cls.obj_from_primitive(db_obj)
     else:
         # NOTE(sahid): This compatibility code needs to stay until we can
         # guarantee that all compute nodes are using RPC API => 3.40.
         cell = db_obj['cells'][0]
         ram_ratio = cell['mem']['limit'] / float(cell['mem']['total'])
         cpu_ratio = cell['cpu_limit'] / float(len(hardware.parse_cpu_spec(
             cell['cpus'])))
         obj_topology = NUMATopologyLimits(
             cpu_allocation_ratio=cpu_ratio,
             ram_allocation_ratio=ram_ratio)
     return obj_topology
Example #12
0
    def _set_numa_cpus(self, image_props):
        nodes = int(image_props.get("hw_numa_nodes", "1"))
        hw_numa_cpus = [None for i in range(nodes)]
        hw_numa_cpus_set = False
        for cellid in range(nodes):
            cpuprop = "hw_numa_cpus.%d" % cellid
            if cpuprop in image_props:
                hw_numa_cpus[cellid] = \
                    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
Example #13
0
    def _set_numa_cpus(self, image_props):
        nodes = int(image_props.get("hw_numa_nodes", "1"))
        hw_numa_cpus = [None for i in range(nodes)]
        hw_numa_cpus_set = False
        for cellid in range(nodes):
            cpuprop = "hw_numa_cpus.%d" % cellid
            if cpuprop in image_props:
                hw_numa_cpus[cellid] = \
                    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
Example #14
0
 def get_pinset(self):
     """
 Parse the vcpu_pin_set line from nova.conf
 using nova's parse_cpu_spec() function
 """
     broken = None
     try:
         oc_pin_set, broken = host.ssh(
             "sudo crudini --get /etc/nova/nova.conf DEFAULT vcpu_pin_set | cat 2>&1"
         )
         line = "".join(oc_pin_set).rstrip()
         self.pinset_list = parse_cpu_spec(line)
         self.pinset_line = line
     except:
         log.error("[%s] Unable to parse vcpu_pin_set: %s" % (self, line))
         pass
     return broken
Example #15
0
    def from_legacy_object(cls, primitive: str):
        """Convert a pre-Liberty object to a (serialized) real o.vo.

        :param primitive: A serialized representation of the legacy object.
        :returns: A serialized representation of the updated object.
        """
        topology = cls(cells=[
            NUMACell(
                id=cell.get('id'),
                cpuset=hardware.parse_cpu_spec(cell.get('cpus', '')),
                cpu_usage=cell.get('cpu_usage', 0),
                memory=cell.get('mem', {}).get('total', 0),
                memory_usage=cell.get('mem', {}).get('used', 0),
                mempages=[],
                pinned_cpus=set(),
                siblings=[],
            ) for cell in jsonutils.loads(primitive).get('cells', [])
        ], )
        return topology._to_json()
Example #16
0
    def _validate_cache_node(flavor):
        # Split a list into evenly sized chunks
        def chunk(it, size):
            it = iter(it)
            return iter(lambda: tuple(islice(it, size)), ())

        specs = flavor.extra_specs
        KEYS = ['hw:cache_l3', 'hw:cache_l3_code', 'hw:cache_l3_data']
        for this_key in KEYS:
            this_prefix = this_key + '.'
            for key in specs:
                if key.startswith(this_prefix):
                    # Check that we have specified dedicated cpus
                    if specs.get(CPU_POLICY_KEY) != \
                            fields.CPUAllocationPolicy.DEDICATED:
                        msg = (_('%(K)s is not permitted when %(P)s is set to'
                                 ' shared.') %
                               {'K': this_key,
                                'P': CPU_POLICY_KEY})
                        raise webob.exc.HTTPConflict(explanation=msg)

                    # Virtual numa node must be valid
                    suffix = key.split(this_prefix, 1)[1]
                    try:
                        vnode = int(suffix)
                    except ValueError:
                        msg = _('%s virtual numa node number must be an '
                                'integer') % this_key
                        raise webob.exc.HTTPBadRequest(explanation=msg)
                    if vnode < 0:
                        msg = _('%s virtual numa node number must be greater '
                                'than or equal to 0') % this_key
                        raise webob.exc.HTTPBadRequest(explanation=msg)

                    # Cache size must be valid and positive
                    try:
                        value = int(specs[key])
                    except ValueError:
                        msg = _('%s must be an integer') % key
                        raise webob.exc.HTTPBadRequest(explanation=msg)
                    if value <= 0:
                        msg = _('%s must be positive') % key
                        raise webob.exc.HTTPBadRequest(explanation=msg)

        # Check that we can properly parse hw:cache_vcpus.x cpulist,
        # and that vcpus are within valid range.
        flavor_cpuset = set(range(flavor.vcpus))
        cache_key = 'hw:cache_vcpus'
        cache_prefix = cache_key + '.'
        for key in specs:
            if key.startswith(cache_prefix):
                suffix = key.split(cache_prefix, 1)[1]
                try:
                    vnode = int(suffix)
                except ValueError:
                    msg = _('%s virtual numa node number must be an '
                            'integer') % cache_key
                    raise webob.exc.HTTPBadRequest(explanation=msg)
                if vnode < 0:
                    msg = _('%s virtual numa node number must be greater '
                            'than or equal to 0') % cache_key
                    raise webob.exc.HTTPBadRequest(explanation=msg)

                try:
                    value = specs[key]
                    cpuset_ids = hardware.parse_cpu_spec(value)
                except Exception as e:
                    msg = (_("Invalid %(K)s '%(V)s'; reason: %(R)s.") %
                           {'K': key,
                            'V': value,
                            'R': e.format_message()
                            })
                    raise webob.exc.HTTPBadRequest(explanation=msg)

                if not cpuset_ids:
                    msg = (_("Invalid %(K)s '%(V)s'; reason: %(R)s.") %
                           {'K': key,
                            'V': value,
                            'R': 'no vcpus specified'
                            })
                    raise webob.exc.HTTPBadRequest(explanation=msg)

                if not cpuset_ids.issubset(flavor_cpuset):
                    msg = _('%(K)s value (%(V)s) must be a subset of vcpus '
                            '(%(S)s)') \
                            % {'K': key, 'V': value,
                               'S': utils.list_to_range(list(flavor_cpuset))}
                    raise webob.exc.HTTPBadRequest(explanation=msg)

                # Check whether hw:cache_vcpus.x are subset of hw:numa_cpus.x
                cpus_key = 'hw:numa_cpus.' + suffix
                if cpus_key in specs:
                    try:
                        cpus_value = specs[cpus_key]
                        numa_cpuset = hardware.parse_cpu_spec(cpus_value)
                    except Exception as e:
                        msg = (_("Invalid %(K)s '%(V)s'; reason: %(R)s.") %
                               {'K': cpus_key,
                                'V': cpus_value,
                                'R': e.format_message()
                                })
                        raise webob.exc.HTTPBadRequest(explanation=msg)
                else:
                    NUMA_NODES_KEY = 'hw:numa_nodes'
                    try:
                        hw_numa_nodes = int(specs.get(NUMA_NODES_KEY, 1))
                    except ValueError:
                        msg = _('hw:numa_nodes value must be an integer')
                        raise webob.exc.HTTPBadRequest(explanation=msg)
                    if vnode >= hw_numa_nodes:
                        msg = (_('%(K)s must use vnode id less than the '
                                 'specified hw:numa_nodes value %(N)s.') %
                               {'K': this_key,
                                'N': hw_numa_nodes})
                        raise webob.exc.HTTPBadRequest(explanation=msg)
                    chunk_size = flavor.vcpus / hw_numa_nodes
                    numa_cpus = list(chunk(range(flavor.vcpus), chunk_size))
                    try:
                        numa_cpuset = set(numa_cpus[vnode])
                    except IndexError:
                        msg = _('%s virtual numa node number must be subset '
                                'of numa nodes') % vnode
                        raise webob.exc.HTTPBadRequest(explanation=msg)
                if not cpuset_ids.issubset(numa_cpuset):
                    msg = (_('%(K)s value (%(V)s) must be a subset of '
                             'vcpus (%(S)s)') %
                           {'K': cache_key, 'V': value,
                            'S': utils.list_to_range(list(numa_cpuset))
                            })
                    raise webob.exc.HTTPBadRequest(explanation=msg)

                # Check that we have specified dedicated cpus
                if specs.get(CPU_POLICY_KEY) != \
                        fields.CPUAllocationPolicy.DEDICATED:
                    msg = (_('%(K)s is not permitted when %(P)s is set to'
                             ' shared.') %
                           {'K': key,
                            'P': CPU_POLICY_KEY})
                    raise webob.exc.HTTPConflict(explanation=msg)