Merge "Improve compute flavor handling"

This commit is contained in:
Zuul 2022-02-02 16:16:21 +00:00 committed by Gerrit Code Review
commit 9d3ee1d321
5 changed files with 65 additions and 14 deletions

View File

@ -43,18 +43,20 @@ class Flavor(resource.Resource):
#: The description of the flavor.
description = resource.Body('description')
#: Size of the disk this flavor offers. *Type: int*
disk = resource.Body('disk', type=int)
disk = resource.Body('disk', type=int, default=0)
#: ``True`` if this is a publicly visible flavor. ``False`` if this is
#: a private image. *Type: bool*
is_public = resource.Body('os-flavor-access:is_public', type=bool)
is_public = resource.Body(
'os-flavor-access:is_public', type=bool, default=True)
#: The amount of RAM (in MB) this flavor offers. *Type: int*
ram = resource.Body('ram', type=int)
ram = resource.Body('ram', type=int, default=0)
#: The number of virtual CPUs this flavor offers. *Type: int*
vcpus = resource.Body('vcpus', type=int)
vcpus = resource.Body('vcpus', type=int, default=0)
#: Size of the swap partitions.
swap = resource.Body('swap')
swap = resource.Body('swap', default=0)
#: Size of the ephemeral data disk attached to this server. *Type: int*
ephemeral = resource.Body('OS-FLV-EXT-DATA:ephemeral', type=int)
ephemeral = resource.Body(
'OS-FLV-EXT-DATA:ephemeral', type=int, default=0)
#: ``True`` if this flavor is disabled, ``False`` if not. *Type: bool*
is_disabled = resource.Body('OS-FLV-DISABLED:disabled', type=bool)
#: The bandwidth scaling factor this flavor receives on the network.
@ -64,6 +66,25 @@ class Flavor(resource.Resource):
#: A dictionary of the flavor's extra-specs key-and-value pairs.
extra_specs = resource.Body('extra_specs', type=dict, default={})
def __getattribute__(self, name):
"""Return an attribute on this instance
This is mostly a pass-through except for a specialization on
the 'id' name, as this can exist under a different name via the
`alternate_id` argument to resource.Body.
"""
if name == "id":
# ID handling in flavor is very tricky. Sometimes we get ID back,
# sometimes we get only name (but it is same as id), sometimes we
# get original_name back, but it is still id.
# To get this handled try sequentially to access it from various
# places until we find first non-empty value.
for xname in ["id", "name", "original_name"]:
if xname in self._body and self._body[xname]:
return self._body[xname]
else:
return super().__getattribute__(name)
@classmethod
def list(cls, session, paginated=True, base_path='/flavors/detail',
allow_unknown_params=False, **params):

View File

@ -11,6 +11,7 @@
# under the License.
from openstack.common import metadata
from openstack.common import tag
from openstack.compute.v2 import flavor
from openstack.compute.v2 import volume_attachment
from openstack import exceptions
from openstack.image.v2 import image
@ -109,8 +110,7 @@ class Server(resource.Resource, metadata.MetadataMixin, tag.TagMixin):
#: this server.
flavor_id = resource.Body('flavorRef')
#: The flavor property as returned from server.
# TODO(gtema): replace with flavor.Flavor addressing flavor.original_name
flavor = resource.Body('flavor', type=dict)
flavor = resource.Body('flavor', type=flavor.Flavor)
#: Indicates whether a configuration drive enables metadata injection.
#: Not all cloud providers enable this feature.
has_config_drive = resource.Body('config_drive')

View File

@ -47,7 +47,6 @@ class TestInventory(base.BaseFunctionalTest):
def _test_host_content(self, host):
self.assertEqual(host['image']['id'], self.image.id)
self.assertNotIn('id', host['flavor'])
self.assertIsInstance(host['volumes'], list)
self.assertIsInstance(host['metadata'], dict)
self.assertIn('interface_ip', host)
@ -78,9 +77,6 @@ class TestInventory(base.BaseFunctionalTest):
self.assertEqual(host['image']['id'], self.image.id)
self.assertNotIn('links', host['image'])
self.assertNotIn('name', host['name'])
self.assertNotIn('id', host['flavor'])
self.assertNotIn('links', host['flavor'])
self.assertNotIn('name', host['flavor'])
self.assertIn('ram', host['flavor'])
host_found = False

View File

@ -33,6 +33,11 @@ BASIC_EXAMPLE = {
'OS-FLV-DISABLED:disabled': False,
'rxtx_factor': 11.0
}
DEFAULTS_EXAMPLE = {
'links': '2',
'original_name': IDENTIFIER,
'description': 'Testing flavor',
}
class TestFlavor(base.TestCase):
@ -80,6 +85,28 @@ class TestFlavor(base.TestCase):
sot.is_disabled)
self.assertEqual(BASIC_EXAMPLE['rxtx_factor'], sot.rxtx_factor)
def test_make_defaults(self):
sot = flavor.Flavor(**DEFAULTS_EXAMPLE)
self.assertEqual(DEFAULTS_EXAMPLE['original_name'], sot.name)
self.assertEqual(0, sot.disk)
self.assertEqual(True, sot.is_public)
self.assertEqual(0, sot.ram)
self.assertEqual(0, sot.vcpus)
self.assertEqual(0, sot.swap)
self.assertEqual(0, sot.ephemeral)
self.assertEqual(IDENTIFIER, sot.id)
def test_flavor_id(self):
id = 'fake_id'
sot = flavor.Flavor(id=id)
self.assertEqual(sot.id, id)
sot = flavor.Flavor(name=id)
self.assertEqual(sot.id, id)
self.assertEqual(sot.name, id)
sot = flavor.Flavor(original_name=id)
self.assertEqual(sot.id, id)
self.assertEqual(sot.original_name, id)
def test_add_tenant_access(self):
sot = flavor.Flavor(**BASIC_EXAMPLE)
resp = mock.Mock()

View File

@ -12,6 +12,7 @@
from unittest import mock
from openstack.compute.v2 import flavor
from openstack.compute.v2 import server
from openstack.image.v2 import image
from openstack.tests.unit import base
@ -64,7 +65,6 @@ EXAMPLE = {
'original_name': 'm1.tiny.specs',
'ram': 512,
'swap': 0,
'vcpus': 1
},
'hostId': '2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6',
'host_status': 'UP',
@ -194,7 +194,7 @@ class TestServer(base.TestCase):
self.assertEqual(EXAMPLE['created'], sot.created_at)
self.assertEqual(EXAMPLE['config_drive'], sot.has_config_drive)
self.assertEqual(EXAMPLE['flavorRef'], sot.flavor_id)
self.assertEqual(EXAMPLE['flavor'], sot.flavor)
self.assertEqual(flavor.Flavor(**EXAMPLE['flavor']), sot.flavor)
self.assertEqual(EXAMPLE['hostId'], sot.host_id)
self.assertEqual(EXAMPLE['host_status'], sot.host_status)
self.assertEqual(EXAMPLE['id'], sot.id)
@ -251,6 +251,13 @@ class TestServer(base.TestCase):
self.assertEqual(EXAMPLE['trusted_image_certificates'],
sot.trusted_image_certificates)
def test_to_dict_flavor(self):
# Ensure to_dict properly resolves flavor and uses defaults for not
# specified flavor proerties.
sot = server.Server(**EXAMPLE)
dct = sot.to_dict()
self.assertEqual(0, dct['flavor']['vcpus'])
def test__prepare_server(self):
zone = 1
data = 2