def test_delete_flavor_info(self): instance_type = flavors.get_default_flavor() metadata = {} flavors.save_flavor_info(metadata, instance_type) flavors.save_flavor_info(metadata, instance_type, '_') flavors.delete_flavor_info(metadata, '', '_') self.assertEqual(metadata, {})
def _migrate_flavor(instance): """Migrate a fractional flavor to a full one stored in extra. This method migrates flavor information stored in an instance's system_metadata to instance_extra. Since the information in the former is not complete, we must attempt to fetch the original flavor by id to merge its extra_specs with what we store. This is a transitional tool and can be removed in a later release once we can ensure that everyone has migrated their instances (likely the L release). """ # NOTE(danms): Always use admin context and read_deleted=yes here # because we need to make sure we can look up our original flavor # and try to reconstruct extra_specs, even if it has been deleted ctxt = context.get_admin_context(read_deleted="yes") instance.flavor = flavors.extract_flavor(instance) flavors.delete_flavor_info(instance.system_metadata, "") for ftype in ("old", "new"): attrname = "%s_flavor" % ftype prefix = "%s_" % ftype try: flavor = flavors.extract_flavor(instance, prefix) setattr(instance, attrname, flavor) flavors.delete_flavor_info(instance.system_metadata, prefix) except KeyError: setattr(instance, attrname, None) # NOTE(danms): Merge in the extra_specs from the original flavor # since they weren't stored with the instance. for flv in (instance.flavor, instance.new_flavor, instance.old_flavor): if flv is not None: try: db_flavor = objects.Flavor.get_by_flavor_id(ctxt, flv.flavorid) except exception.FlavorNotFound: continue extra_specs = dict(db_flavor.extra_specs) extra_specs.update(flv.get("extra_specs", {})) flv.extra_specs = extra_specs
def test_flavor_numa_extras_are_saved(self): instance_type = flavors.get_default_flavor() instance_type['extra_specs'] = { 'hw:numa_mem.0': '123', 'hw:numa_cpus.0': '456', 'hw:numa_mem.1': '789', 'hw:numa_cpus.1': 'ABC', 'foo': 'bar', } sysmeta = flavors.save_flavor_info({}, instance_type) _instance_type = flavors.extract_flavor({'system_metadata': sysmeta}) expected_extra_specs = { 'hw:numa_mem.0': '123', 'hw:numa_cpus.0': '456', 'hw:numa_mem.1': '789', 'hw:numa_cpus.1': 'ABC', } self.assertEqual(expected_extra_specs, _instance_type['extra_specs']) flavors.delete_flavor_info(sysmeta, '') self.assertEqual({}, sysmeta)
def test_flavor_numa_extras_are_saved(self): instance_type = flavors.get_default_flavor() instance_type["extra_specs"] = { "hw:numa_mem.0": "123", "hw:numa_cpus.0": "456", "hw:numa_mem.1": "789", "hw:numa_cpus.1": "ABC", "foo": "bar", } sysmeta = flavors.save_flavor_info({}, instance_type) _instance_type = flavors.extract_flavor({"system_metadata": sysmeta}) expected_extra_specs = { "hw:numa_mem.0": "123", "hw:numa_cpus.0": "456", "hw:numa_mem.1": "789", "hw:numa_cpus.1": "ABC", } self.assertEqual(expected_extra_specs, _instance_type["extra_specs"]) flavors.delete_flavor_info(sysmeta, "") self.assertEqual({}, sysmeta)
def _maybe_upgrade_flavor(self): # NOTE(danms): We may have regressed to flavors stored in sysmeta, # so we have to merge back in here. That could happen if we pass # a converted instance to an older node, which still stores the # flavor in sysmeta, which then calls save(). We need to not # store that flavor info back into sysmeta after we've already # converted it. if not self.obj_attr_is_set("system_metadata") or "instance_type_id" not in self.system_metadata: return LOG.debug("Transforming legacy flavors on save", instance=self) for ftype in ("", "old_", "new_"): attr = "%sflavor" % ftype try: flavor = flavors.extract_flavor(self, prefix=ftype) flavors.delete_flavor_info(self.system_metadata, ftype) # NOTE(danms): This may trigger a lazy-load of the flavor # information, but only once and it avoids re-fetching and # re-migrating the original flavor. getattr(self, attr).update(flavor) except AttributeError: setattr(self, attr, flavor) except KeyError: setattr(self, attr, None)
def delete_flavor(self, namespace): self.system_metadata = flavors.delete_flavor_info( self.system_metadata, "%s_" % namespace) self.save()