Update compute.server resource

- Add current supported list filters
- Add missing attributes (from newer microversions)
- Sort attributes in the resource
- Use example response from compute docs in unittest (not to miss new 
attributes)
- add _max_microversion (and respective discovery calls in tests)

Change-Id: Iad1b57aee0affa345a2812c2b504d00a60441f27
This commit is contained in:
Artem Goncharov 2019-04-25 15:22:51 +02:00
parent 3bcdfcfb28
commit 769646c5c1
18 changed files with 372 additions and 154 deletions

View File

@ -38,6 +38,7 @@ _SERVER_FIELDS = (
'addresses',
'adminPass',
'created',
'description',
'key_name',
'metadata',
'networks',
@ -45,6 +46,7 @@ _SERVER_FIELDS = (
'private_v4',
'public_v4',
'public_v6',
'server_groups',
'status',
'updated',
'user_id',
@ -468,9 +470,11 @@ class Normalizer(object):
# OpenStack can return image as a string when you've booted
# from volume
if str(server['image']) != server['image']:
server['image'].pop('links', None)
ret['image'] = server.pop('image')
image = server.pop('image', None)
if str(image) != image:
image = munch.Munch(id=image['id'])
ret['image'] = image
# From original_names from sdk
server.pop('imageRef', None)
# From original_names from sdk
@ -515,6 +519,13 @@ class Normalizer(object):
'OS-EXT-SRV-ATTR:hypervisor_hostname',
'OS-EXT-SRV-ATTR:instance_name',
'OS-EXT-SRV-ATTR:user_data',
'OS-EXT-SRV-ATTR:host',
'OS-EXT-SRV-ATTR:hostname',
'OS-EXT-SRV-ATTR:kernel_id',
'OS-EXT-SRV-ATTR:launch_index',
'OS-EXT-SRV-ATTR:ramdisk_id',
'OS-EXT-SRV-ATTR:reservation_id',
'OS-EXT-SRV-ATTR:root_device_name',
'OS-SCH-HNT:scheduler_hints',
):
short_key = key.split(':')[1]

View File

@ -487,33 +487,8 @@ class Proxy(proxy.Proxy):
instances with only basic data will be returned. The default,
``True``, will cause instances with full data to be returned.
:param kwargs query: Optional query parameters to be sent to limit
the servers being returned. Available parameters include:
* changes_since: A time/date stamp for when the server last changed
status.
* image: An image resource or ID.
* flavor: A flavor resource or ID.
* name: Name of the server as a string. Can be queried with
regular expressions. The regular expression
?name=bob returns both bob and bobb. If you must match on
only bob, you can use a regular expression that
matches the syntax of the underlying database server that
is implemented for Compute, such as MySQL or PostgreSQL.
* status: Value of the status of the server so that you can filter
on "ACTIVE" for example.
* host: Name of the host as a string.
* all_projects: Flag to request servers be returned from all
projects, not just the currently scoped one.
* limit: Requests a specified page size of returned items from the
query. Returns a number of items up to the specified
limit value. Use the limit parameter to make an initial
limited request and use the ID of the last-seen item from
the response as the marker parameter value in a subsequent
limited request.
* marker: Specifies the ID of the last-seen item. Use the limit
parameter to make an initial limited request and use the
ID of the last-seen item from the response as the marker
parameter value in a subsequent limited request.
the servers being returned. Available parameters can be seen
under https://developer.openstack.org/api-ref/compute/#list-servers
:returns: A generator of server instances.
"""

View File

@ -11,6 +11,7 @@
# under the License.
from openstack.compute.v2 import metadata
from openstack.image.v2 import image
from openstack import resource
from openstack import utils
@ -28,19 +29,32 @@ class Server(resource.Resource, metadata.MetadataMixin, resource.TagMixin):
allow_list = True
_query_mapping = resource.QueryParameters(
"image", "flavor", "name",
"status", "host",
"auto_disk_config", "availability_zone",
"created_at", "description", "flavor",
"hostname", "image", "kernel_id", "key_name",
"launch_index", "launched_at", "locked_by", "name",
"node", "power_state", "progress", "project_id", "ramdisk_id",
"reservation_id", "root_device_name",
"status", "task_state", "terminated_at", "user_id",
"vm_state",
"sort_key", "sort_dir",
"reservation_id", "tags",
"project_id",
is_deleted="deleted",
access_ipv4="access_ip_v4",
access_ipv6="access_ip_v6",
has_config_drive="config_drive",
deleted_only="deleted",
compute_host="host",
is_soft_deleted="soft_deleted",
ipv4_address="ip",
ipv6_address="ip6",
changes_since="changes-since",
changes_before="changes-before",
id="uuid",
all_projects="all_tenants",
**resource.TagMixin._tag_query_parameters
)
_max_microversion = '2.72'
#: A list of dictionaries holding links relevant to this server.
links = resource.Body('links')
@ -53,92 +67,131 @@ class Server(resource.Resource, metadata.MetadataMixin, resource.TagMixin):
#: and ``version``, which is either 4 or 6 depending on the protocol
#: of the IP address. *Type: dict*
addresses = resource.Body('addresses', type=dict)
#: Timestamp of when the server was created.
created_at = resource.Body('created')
#: The flavor reference, as a ID or full URL, for the flavor to use for
#: this server.
flavor_id = resource.Body('flavorRef')
#: The flavor property as returned from server.
flavor = resource.Body('flavor', type=dict)
#: An ID representing the host of this server.
host_id = resource.Body('hostId')
#: The image reference, as a ID or full URL, for the image to use for
#: this server.
image_id = resource.Body('imageRef')
#: The image property as returned from server.
image = resource.Body('image', type=dict)
#: Metadata stored for this server. *Type: dict*
metadata = resource.Body('metadata', type=dict)
#: While the server is building, this value represents the percentage
#: of completion. Once it is completed, it will be 100. *Type: int*
progress = resource.Body('progress', type=int)
#: The ID of the project this server is associated with.
project_id = resource.Body('tenant_id')
#: The state this server is in. Valid values include ``ACTIVE``,
#: ``BUILDING``, ``DELETED``, ``ERROR``, ``HARD_REBOOT``, ``PASSWORD``,
#: ``PAUSED``, ``REBOOT``, ``REBUILD``, ``RESCUED``, ``RESIZED``,
#: ``REVERT_RESIZE``, ``SHUTOFF``, ``SOFT_DELETED``, ``STOPPED``,
#: ``SUSPENDED``, ``UNKNOWN``, or ``VERIFY_RESIZE``.
status = resource.Body('status')
#: Timestamp of when this server was last updated.
updated_at = resource.Body('updated')
#: The ID of the owners of this server.
user_id = resource.Body('user_id')
#: The name of an associated keypair
key_name = resource.Body('key_name')
#: The disk configuration. Either AUTO or MANUAL.
disk_config = resource.Body('OS-DCF:diskConfig')
#: Indicates whether a configuration drive enables metadata injection.
#: Not all cloud providers enable this feature.
has_config_drive = resource.Body('config_drive')
#: The name of the availability zone this server is a part of.
availability_zone = resource.Body('OS-EXT-AZ:availability_zone')
#: The power state of this server.
power_state = resource.Body('OS-EXT-STS:power_state')
#: The task state of this server.
task_state = resource.Body('OS-EXT-STS:task_state')
#: The VM state of this server.
vm_state = resource.Body('OS-EXT-STS:vm_state')
#: When a server is first created, it provides the administrator password.
admin_password = resource.Body('adminPass')
#: A list of an attached volumes. Each item in the list contains at least
#: an "id" key to identify the specific volumes.
attached_volumes = resource.Body(
'os-extended-volumes:volumes_attached')
#: The timestamp when the server was launched.
launched_at = resource.Body('OS-SRV-USG:launched_at')
#: The timestamp when the server was terminated (if it has been).
terminated_at = resource.Body('OS-SRV-USG:terminated_at')
#: A list of applicable security groups. Each group contains keys for
#: description, name, id, and rules.
security_groups = resource.Body('security_groups')
#: When a server is first created, it provides the administrator password.
admin_password = resource.Body('adminPass')
#: The file path and contents, text only, to inject into the server at
#: launch. The maximum size of the file path data is 255 bytes.
#: The maximum limit is The number of allowed bytes in the decoded,
#: rather than encoded, data.
personality = resource.Body('personality')
#: Configuration information or scripts to use upon launch.
#: Must be Base64 encoded.
user_data = resource.Body('OS-EXT-SRV-ATTR:user_data')
#: The name of the availability zone this server is a part of.
availability_zone = resource.Body('OS-EXT-AZ:availability_zone')
#: Enables fine grained control of the block device mapping for an
#: instance. This is typically used for booting servers from volumes.
block_device_mapping = resource.Body('block_device_mapping_v2')
#: The dictionary of data to send to the scheduler.
scheduler_hints = resource.Body('OS-SCH-HNT:scheduler_hints', type=dict)
#: A networks object. Required parameter when there are multiple
#: networks defined for the tenant. When you do not specify the
#: networks parameter, the server attaches to the only network
#: created for the current tenant.
networks = resource.Body('networks')
#: Indicates whether or not a config drive was used for this server.
config_drive = resource.Body('config_drive')
#: The name of the compute host on which this instance is running.
#: Appears in the response for administrative users only.
compute_host = resource.Body('OS-EXT-SRV-ATTR:host')
#: Timestamp of when the server was created.
created_at = resource.Body('created')
#: The description of the server. Before microversion
#: 2.19 this was set to the server name.
description = resource.Body('description')
#: The disk configuration. Either AUTO or MANUAL.
disk_config = resource.Body('OS-DCF:diskConfig')
#: The flavor reference, as a ID or full URL, for the flavor to use for
#: 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)
#: Indicates whether a configuration drive enables metadata injection.
#: Not all cloud providers enable this feature.
has_config_drive = resource.Body('config_drive')
#: An ID representing the host of this server.
host_id = resource.Body('hostId')
#: The host status.
host_status = resource.Body('host_status')
#: The hostname set on the instance when it is booted.
#: By default, it appears in the response for administrative users only.
hostname = resource.Body('OS-EXT-SRV-ATTR:hostname')
#: The hypervisor host name. Appears in the response for administrative
#: users only.
hypervisor_hostname = resource.Body('OS-EXT-SRV-ATTR:hypervisor_hostname')
#: The image reference, as a ID or full URL, for the image to use for
#: this server.
image_id = resource.Body('imageRef')
#: The image property as returned from server.
image = resource.Body('image', type=image.Image)
#: The instance name. The Compute API generates the instance name from the
#: instance name template. Appears in the response for administrative users
#: only.
instance_name = resource.Body('OS-EXT-SRV-ATTR:instance_name')
# The locked status of the server
is_locked = resource.Body('locked', type=bool)
#: The UUID of the kernel image when using an AMI. Will be null if not.
#: By default, it appears in the response for administrative users only.
kernel_id = resource.Body('OS-EXT-SRV-ATTR:kernel_id')
#: The name of an associated keypair
key_name = resource.Body('key_name')
#: When servers are launched via multiple create, this is the
#: sequence in which the servers were launched. By default, it
#: appears in the response for administrative users only.
launch_index = resource.Body('OS-EXT-SRV-ATTR:launch_index', type=int)
#: The timestamp when the server was launched.
launched_at = resource.Body('OS-SRV-USG:launched_at')
#: Metadata stored for this server. *Type: dict*
metadata = resource.Body('metadata', type=dict)
#: A networks object. Required parameter when there are multiple
#: networks defined for the tenant. When you do not specify the
#: networks parameter, the server attaches to the only network
#: created for the current tenant.
networks = resource.Body('networks')
#: The file path and contents, text only, to inject into the server at
#: launch. The maximum size of the file path data is 255 bytes.
#: The maximum limit is The number of allowed bytes in the decoded,
#: rather than encoded, data.
personality = resource.Body('personality')
#: The power state of this server.
power_state = resource.Body('OS-EXT-STS:power_state')
#: While the server is building, this value represents the percentage
#: of completion. Once it is completed, it will be 100. *Type: int*
progress = resource.Body('progress', type=int)
#: The ID of the project this server is associated with.
project_id = resource.Body('tenant_id')
#: The UUID of the ramdisk image when using an AMI. Will be null if not.
#: By default, it appears in the response for administrative users only.
ramdisk_id = resource.Body('OS-EXT-SRV-ATTR:ramdisk_id')
#: The reservation id for the server. This is an id that can be
#: useful in tracking groups of servers created with multiple create,
#: that will all have the same reservation_id. By default, it appears
#: in the response for administrative users only.
reservation_id = resource.Body('OS-EXT-SRV-ATTR:reservation_id')
#: The root device name for the instance By default, it appears in the
#: response for administrative users only.
root_device_name = resource.Body('OS-EXT-SRV-ATTR:root_device_name')
#: The dictionary of data to send to the scheduler.
scheduler_hints = resource.Body('OS-SCH-HNT:scheduler_hints', type=dict)
#: A list of applicable security groups. Each group contains keys for
#: description, name, id, and rules.
security_groups = resource.Body('security_groups')
#: The UUIDs of the server groups to which the server belongs.
#: Currently this can contain at most one entry.
server_groups = resource.Body('server_groups', type=list, list_type=dict)
#: The state this server is in. Valid values include ``ACTIVE``,
#: ``BUILDING``, ``DELETED``, ``ERROR``, ``HARD_REBOOT``, ``PASSWORD``,
#: ``PAUSED``, ``REBOOT``, ``REBUILD``, ``RESCUED``, ``RESIZED``,
#: ``REVERT_RESIZE``, ``SHUTOFF``, ``SOFT_DELETED``, ``STOPPED``,
#: ``SUSPENDED``, ``UNKNOWN``, or ``VERIFY_RESIZE``.
status = resource.Body('status')
#: The task state of this server.
task_state = resource.Body('OS-EXT-STS:task_state')
#: The timestamp when the server was terminated (if it has been).
terminated_at = resource.Body('OS-SRV-USG:terminated_at')
#: A list of trusted certificate IDs, that were used during image
#: signature verification to verify the signing certificate.
trusted_image_certificates = resource.Body(
'trusted_image_certificates', type=list)
#: Timestamp of when this server was last updated.
updated_at = resource.Body('updated')
#: Configuration information or scripts to use upon launch.
#: Must be Base64 encoded.
user_data = resource.Body('OS-EXT-SRV-ATTR:user_data')
#: The ID of the owners of this server.
user_id = resource.Body('user_id')
#: The VM state of this server.
vm_state = resource.Body('OS-EXT-STS:vm_state')
def _prepare_request(self, requires_id=True, prepend_key=True,
base_path=None):

View File

@ -183,6 +183,7 @@ class TestMemoryCache(base.TestCase):
self.cloud._SERVER_AGE = 2
fake_server = fakes.make_fake_server('1234', 'name')
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),

View File

@ -118,6 +118,7 @@ class TestCreateServer(base.TestCase):
u'max_count': 1,
u'min_count': 1,
u'name': u'server-name'}})),
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -157,6 +158,7 @@ class TestCreateServer(base.TestCase):
u'max_count': 1,
u'min_count': 1,
u'name': u'server-name'}})),
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -509,6 +511,7 @@ class TestCreateServer(base.TestCase):
u'max_count': 1,
u'min_count': 1,
u'name': u'server-name'}})),
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),

View File

@ -31,6 +31,7 @@ class TestDeleteServer(base.TestCase):
"""
server = fakes.make_fake_server('1234', 'daffy', 'ACTIVE')
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -48,6 +49,7 @@ class TestDeleteServer(base.TestCase):
Test that we return immediately when server is already gone
"""
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -59,6 +61,7 @@ class TestDeleteServer(base.TestCase):
def test_delete_server_already_gone_wait(self):
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -73,6 +76,7 @@ class TestDeleteServer(base.TestCase):
"""
server = fakes.make_fake_server('9999', 'wily', 'ACTIVE')
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -99,6 +103,7 @@ class TestDeleteServer(base.TestCase):
"""
server = fakes.make_fake_server('1212', 'speedy', 'ACTIVE')
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -130,6 +135,7 @@ class TestDeleteServer(base.TestCase):
server = fakes.make_fake_server('1234', 'porky', 'ACTIVE')
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -150,6 +156,7 @@ class TestDeleteServer(base.TestCase):
fip_id = uuid.uuid4().hex
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -198,6 +205,7 @@ class TestDeleteServer(base.TestCase):
server = fakes.make_fake_server('1234', 'porky', 'ACTIVE')
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -229,6 +237,7 @@ class TestDeleteServer(base.TestCase):
server = fakes.make_fake_server('1234', 'porky', 'ACTIVE')
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),

View File

@ -482,6 +482,7 @@ class TestFloatingIP(base.TestCase):
"fixed_ip_address": "10.4.0.16",
"port_id": "a767944e-057a-47d1-a669-824a21b8fb7b",
}})),
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri='{endpoint}/servers/detail'.format(
endpoint=fakes.COMPUTE_ENDPOINT),

View File

@ -425,8 +425,15 @@ class TestNormalize(base.TestCase):
expected = {
'OS-DCF:diskConfig': u'MANUAL',
'OS-EXT-AZ:availability_zone': u'ca-ymq-2',
'OS-EXT-SRV-ATTR:host': None,
'OS-EXT-SRV-ATTR:hostname': None,
'OS-EXT-SRV-ATTR:hypervisor_hostname': None,
'OS-EXT-SRV-ATTR:instance_name': None,
'OS-EXT-SRV-ATTR:kernel_id': None,
'OS-EXT-SRV-ATTR:launch_index': None,
'OS-EXT-SRV-ATTR:ramdisk_id': None,
'OS-EXT-SRV-ATTR:reservation_id': None,
'OS-EXT-SRV-ATTR:root_device_name': None,
'OS-EXT-SRV-ATTR:user_data': None,
'OS-EXT-STS:power_state': 1,
'OS-EXT-STS:task_state': None,
@ -454,17 +461,23 @@ class TestNormalize(base.TestCase):
'config_drive': u'True',
'created': u'2015-08-01T19:52:16Z',
'created_at': u'2015-08-01T19:52:16Z',
'description': None,
'disk_config': u'MANUAL',
'flavor': {u'id': u'bbcb7eb5-5c8d-498f-9d7e-307c575d3566'},
'has_config_drive': True,
'host': None,
'hostId': u'bd37',
'host_id': u'bd37',
'host_status': None,
'hostname': None,
'hypervisor_hostname': None,
'id': u'811c5197-dba7-4d3a-a3f6-68ca5328b9a7',
'image': {u'id': u'69c99b45-cd53-49de-afdc-f24789eb8f83'},
'instance_name': None,
'interface_ip': '',
'hypervisor_hostname': None,
'kernel_id': None,
'key_name': u'mordred',
'launch_index': None,
'launched_at': u'2015-08-01T19:52:02.000000',
'location': {
'cloud': '_test_cloud_',
@ -475,6 +488,7 @@ class TestNormalize(base.TestCase):
'name': None},
'region_name': u'RegionOne',
'zone': u'ca-ymq-2'},
'locked': True,
'metadata': {u'group': u'irc', u'groups': u'irc,enabled'},
'name': u'mordred-irc',
'networks': {
@ -490,8 +504,15 @@ class TestNormalize(base.TestCase):
'properties': {
'OS-DCF:diskConfig': u'MANUAL',
'OS-EXT-AZ:availability_zone': u'ca-ymq-2',
'OS-EXT-SRV-ATTR:host': None,
'OS-EXT-SRV-ATTR:hostname': None,
'OS-EXT-SRV-ATTR:hypervisor_hostname': None,
'OS-EXT-SRV-ATTR:instance_name': None,
'OS-EXT-SRV-ATTR:kernel_id': None,
'OS-EXT-SRV-ATTR:launch_index': None,
'OS-EXT-SRV-ATTR:ramdisk_id': None,
'OS-EXT-SRV-ATTR:reservation_id': None,
'OS-EXT-SRV-ATTR:root_device_name': None,
'OS-EXT-SRV-ATTR:user_data': None,
'OS-EXT-STS:power_state': 1,
'OS-EXT-STS:task_state': None,
@ -499,19 +520,26 @@ class TestNormalize(base.TestCase):
'OS-SCH-HNT:scheduler_hints': None,
'OS-SRV-USG:launched_at': u'2015-08-01T19:52:02.000000',
'OS-SRV-USG:terminated_at': None,
'host_status': None,
'locked': True,
'os-extended-volumes:volumes_attached': []},
'os-extended-volumes:volumes_attached': [],
'trusted_image_certificates': None},
'public_v4': None,
'public_v6': None,
'ramdisk_id': None,
'region': u'RegionOne',
'reservation_id': None,
'root_device_name': None,
'scheduler_hints': None,
'security_groups': [{u'name': u'default'}],
'server_groups': None,
'status': u'ACTIVE',
'locked': True,
'tags': [],
'task_state': None,
'tenant_id': u'db92b20496ae4fbda850a689ea9d563f',
'terminated_at': None,
'trusted_image_certificates': None,
'updated': u'2016-10-15T15:49:29Z',
'user_data': None,
'user_id': u'e9b21dc437d149858faee0898fb08e92',
@ -877,6 +905,7 @@ class TestStrictNormalize(base.TestCase):
def test_normalize_servers(self):
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -900,16 +929,21 @@ class TestStrictNormalize(base.TestCase):
'block_device_mapping': None,
'created': u'2015-08-01T19:52:16Z',
'created_at': u'2015-08-01T19:52:16Z',
'description': None,
'disk_config': u'MANUAL',
'flavor': {u'id': u'bbcb7eb5-5c8d-498f-9d7e-307c575d3566'},
'has_config_drive': True,
'host': None,
'host_id': u'bd37',
'hostname': None,
'hypervisor_hostname': None,
'id': u'811c5197-dba7-4d3a-a3f6-68ca5328b9a7',
'image': {u'id': u'69c99b45-cd53-49de-afdc-f24789eb8f83'},
'interface_ip': u'',
'instance_name': None,
'kernel_id': None,
'key_name': u'mordred',
'launch_index': None,
'launched_at': u'2015-08-01T19:52:02.000000',
'location': {
'cloud': '_test_cloud_',
@ -931,12 +965,18 @@ class TestStrictNormalize(base.TestCase):
'private_v4': None,
'progress': 0,
'properties': {
'locked': True
'host_status': None,
'locked': True,
'trusted_image_certificates': None
},
'public_v4': None,
'public_v6': None,
'ramdisk_id': None,
'reservation_id': None,
'root_device_name': None,
'scheduler_hints': None,
'security_groups': [{u'name': u'default'}],
'server_groups': None,
'status': u'ACTIVE',
'tags': [],
'task_state': None,

View File

@ -79,6 +79,7 @@ class TestRebuildServer(base.TestCase):
json={
'rebuild': {
'imageRef': 'a'}})),
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -105,6 +106,7 @@ class TestRebuildServer(base.TestCase):
json={
'rebuild': {
'imageRef': 'a'}})),
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -194,6 +196,7 @@ class TestRebuildServer(base.TestCase):
'rebuild': {
'imageRef': 'a',
'adminPass': password}})),
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -231,6 +234,7 @@ class TestRebuildServer(base.TestCase):
json={
'rebuild': {
'imageRef': 'a'}})),
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),

View File

@ -609,6 +609,7 @@ class TestSecurityGroups(base.TestCase):
self.cloud.secgroup_source = 'neutron'
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public',
@ -664,6 +665,7 @@ class TestSecurityGroups(base.TestCase):
validate = {'removeSecurityGroup': {'name': 'neutron-sec-group'}}
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public',
@ -691,6 +693,7 @@ class TestSecurityGroups(base.TestCase):
self.has_neutron = False
self.cloud.secgroup_source = 'nova'
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(
method='GET',
uri='{endpoint}/servers/detail'.format(
@ -717,6 +720,7 @@ class TestSecurityGroups(base.TestCase):
self.cloud.secgroup_source = 'neutron'
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public',
@ -737,6 +741,7 @@ class TestSecurityGroups(base.TestCase):
fake_server = fakes.make_fake_server('1234', 'server-name', 'ACTIVE')
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(
method='GET',
uri='{endpoint}/servers/detail'.format(

View File

@ -46,6 +46,7 @@ class TestServerConsole(base.TestCase):
def test_get_server_console_name_or_id(self):
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri='{endpoint}/servers/detail'.format(
endpoint=fakes.COMPUTE_ENDPOINT),

View File

@ -38,6 +38,7 @@ class TestServerDeleteMetadata(base.TestCase):
Test that a missing metadata throws an exception.
"""
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -58,6 +59,7 @@ class TestServerDeleteMetadata(base.TestCase):
def test_server_delete_metadata(self):
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),

View File

@ -35,6 +35,7 @@ class TestServerSetMetadata(base.TestCase):
def test_server_set_metadata_with_exception(self):
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -57,6 +58,7 @@ class TestServerSetMetadata(base.TestCase):
def test_server_set_metadata(self):
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),

View File

@ -81,6 +81,7 @@ class TestShade(base.TestCase):
server2 = fakes.make_fake_server('345', 'mouse')
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -95,6 +96,7 @@ class TestShade(base.TestCase):
def test_get_server_not_found(self):
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -108,6 +110,7 @@ class TestShade(base.TestCase):
def test_list_servers_exception(self):
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -146,6 +149,7 @@ class TestShade(base.TestCase):
server_name = self.getUniqueString('name')
fake_server = fakes.make_fake_server(server_id, server_name)
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -329,6 +333,7 @@ class TestShade(base.TestCase):
"name": "private-subnet-ipv4"
}]}
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -353,6 +358,7 @@ class TestShade(base.TestCase):
'''This test verifies that when list_servers is called with
`all_projects=True` that it passes `all_tenants=True` to nova.'''
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail'],
@ -369,6 +375,7 @@ class TestShade(base.TestCase):
'''This test verifies that when list_servers is called with
`filters` dict that it passes it to nova.'''
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail'],

View File

@ -40,6 +40,7 @@ class TestUpdateServer(base.TestCase):
update_server.
"""
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),
@ -65,6 +66,7 @@ class TestUpdateServer(base.TestCase):
self.server_id, self.updated_server_name)
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),

View File

@ -14,48 +14,106 @@ import mock
import six
from openstack.tests.unit import base
from openstack.image.v2 import image
from openstack.compute.v2 import server
IDENTIFIER = 'IDENTIFIER'
EXAMPLE = {
'accessIPv4': '1',
'accessIPv6': '2',
'addresses': {'region': '3'},
'config_drive': True,
'created': '2015-03-09T12:14:57.233772',
'OS-DCF:diskConfig': 'AUTO',
'OS-EXT-AZ:availability_zone': 'us-west',
'OS-EXT-SRV-ATTR:host': 'compute',
'OS-EXT-SRV-ATTR:hostname': 'new-server-test',
'OS-EXT-SRV-ATTR:hypervisor_hostname': 'fake-mini',
'OS-EXT-SRV-ATTR:instance_name': 'instance-00000001',
'OS-EXT-SRV-ATTR:kernel_id': '',
'OS-EXT-SRV-ATTR:launch_index': 0,
'OS-EXT-SRV-ATTR:ramdisk_id': '',
'OS-EXT-SRV-ATTR:reservation_id': 'r-ov3q80zj',
'OS-EXT-SRV-ATTR:root_device_name': '/dev/sda',
'OS-EXT-SRV-ATTR:user_data': 'IyEvYmluL2Jhc2gKL2Jpbi9IHlvdSEiCg==',
'OS-EXT-STS:power_state': 1,
'OS-EXT-STS:task_state': None,
'OS-EXT-STS:vm_state': 'active',
'OS-SRV-USG:launched_at': '2017-02-14T19:23:59.895661',
'OS-SRV-USG:terminated_at': '2015-03-09T12:15:57.233772',
'OS-SCH-HNT:scheduler_hints': {'key': '30'},
'accessIPv4': '1.2.3.4',
'accessIPv6': '80fe::',
'adminPass': '27',
'addresses': {
'private': [
{
'OS-EXT-IPS-MAC:mac_addr': 'aa:bb:cc:dd:ee:ff',
'OS-EXT-IPS:type': 'fixed',
'addr': '192.168.0.3',
'version': 4
}
]
},
'block_device_mapping_v2': {'key': '29'},
'config_drive': '',
'created': '2017-02-14T19:23:58Z',
'description': 'dummy',
'flavorRef': '5',
'flavor': {'id': 'FLAVOR_ID', 'links': {}},
'hostId': '6',
'flavor': {
'disk': 1,
'ephemeral': 0,
'extra_specs': {
'hw:cpu_policy': 'dedicated',
'hw:mem_page_size': '2048'
},
'original_name': 'm1.tiny.specs',
'ram': 512,
'swap': 0,
'vcpus': 1
},
'hostId': '2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6',
'host_status': 'UP',
'id': IDENTIFIER,
'imageRef': '8',
'image': {'id': 'IMAGE_ID', 'links': {}},
'links': '9',
'metadata': {'key': '10'},
'image': {
'id': '70a599e0-31e7-49b7-b260-868f441e862b',
'links': [
{
'href': 'http://openstack.example.com/images/70a599e0',
'rel': 'bookmark'
}
]
},
'key_name': 'dummy',
'links': [
{
'href': 'http://openstack.example.com/v2.1/servers/9168b536',
'rel': 'self'
},
{
'href': 'http://openstack.example.com/servers/9168b536',
'rel': 'bookmark'
}
],
'locked': True,
'metadata': {
'My Server Name': 'Apache1'
},
'name': 'new-server-test',
'networks': 'auto',
'name': '11',
'progress': 12,
'tenant_id': '13',
'status': '14',
'updated': '2015-03-09T12:15:57.233772',
'user_id': '16',
'key_name': '17',
'OS-DCF:diskConfig': '18',
'OS-EXT-AZ:availability_zone': '19',
'OS-EXT-STS:power_state': '20',
'OS-EXT-STS:task_state': '21',
'OS-EXT-STS:vm_state': '22',
'os-extended-volumes:volumes_attached': '23',
'OS-SRV-USG:launched_at': '2015-03-09T12:15:57.233772',
'OS-SRV-USG:terminated_at': '2015-03-09T12:15:57.233772',
'security_groups': '26',
'adminPass': '27',
'os-extended-volumes:volumes_attached': [],
'personality': '28',
'block_device_mapping_v2': {'key': '29'},
'OS-EXT-SRV-ATTR:hypervisor_hostname': 'hypervisor.example.com',
'OS-EXT-SRV-ATTR:instance_name': 'instance-00000001',
'OS-SCH-HNT:scheduler_hints': {'key': '30'},
'OS-EXT-SRV-ATTR:user_data': '31',
'locked': True
'progress': 0,
'security_groups': [
{
'name': 'default'
}
],
'status': 'ACTIVE',
'tags': [],
'tenant_id': '6f70656e737461636b20342065766572',
'trusted_image_certificates': [
'0b5d2c72-12cc-4ba6-a8d7-3ff5cc1d8cb8',
'674736e3-f25c-405c-8362-bbf991e0ce0a'
],
'updated': '2017-02-14T19:24:00Z',
'user_id': 'fake'
}
@ -80,26 +138,51 @@ class TestServer(base.TestCase):
self.assertTrue(sot.allow_delete)
self.assertTrue(sot.allow_list)
self.assertDictEqual({"image": "image",
"flavor": "flavor",
"name": "name",
"status": "status",
"host": "host",
"all_projects": "all_tenants",
self.assertDictEqual({"access_ipv4": "access_ip_v4",
"access_ipv6": "access_ip_v6",
"auto_disk_config": "auto_disk_config",
"availability_zone": "availability_zone",
"changes_before": "changes-before",
"changes_since": "changes-since",
"compute_host": "host",
"has_config_drive": "config_drive",
"created_at": "created_at",
"description": "description",
"flavor": "flavor",
"hostname": "hostname",
"image": "image",
"ipv4_address": "ip",
"ipv6_address": "ip6",
"id": "uuid",
"deleted_only": "deleted",
"is_soft_deleted": "soft_deleted",
"kernel_id": "kernel_id",
"key_name": "key_name",
"launch_index": "launch_index",
"launched_at": "launched_at",
"limit": "limit",
"locked_by": "locked_by",
"marker": "marker",
"sort_key": "sort_key",
"sort_dir": "sort_dir",
"reservation_id": "reservation_id",
"name": "name",
"node": "node",
"power_state": "power_state",
"progress": "progress",
"project_id": "project_id",
"ramdisk_id": "ramdisk_id",
"reservation_id": "reservation_id",
"root_device_name": "root_device_name",
"sort_dir": "sort_dir",
"sort_key": "sort_key",
"status": "status",
"task_state": "task_state",
"terminated_at": "terminated_at",
"user_id": "user_id",
"vm_state": "vm_state",
"all_projects": "all_tenants",
"tags": "tags",
"any_tags": "tags-any",
"not_tags": "not-tags",
"not_any_tags": "not-tags-any",
"is_deleted": "deleted",
"ipv4_address": "ip",
"ipv6_address": "ip6",
},
sot._query_mapping._mapping)
@ -113,9 +196,10 @@ class TestServer(base.TestCase):
self.assertEqual(EXAMPLE['flavorRef'], sot.flavor_id)
self.assertEqual(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)
self.assertEqual(EXAMPLE['imageRef'], sot.image_id)
self.assertEqual(EXAMPLE['image'], sot.image)
self.assertEqual(image.Image(**EXAMPLE['image']), sot.image)
self.assertEqual(EXAMPLE['links'], sot.links)
self.assertEqual(EXAMPLE['metadata'], sot.metadata)
self.assertEqual(EXAMPLE['networks'], sot.networks)
@ -142,14 +226,30 @@ class TestServer(base.TestCase):
self.assertEqual(EXAMPLE['personality'], sot.personality)
self.assertEqual(EXAMPLE['block_device_mapping_v2'],
sot.block_device_mapping)
self.assertEqual(EXAMPLE['OS-EXT-SRV-ATTR:host'],
sot.compute_host)
self.assertEqual(EXAMPLE['OS-EXT-SRV-ATTR:hostname'],
sot.hostname)
self.assertEqual(EXAMPLE['OS-EXT-SRV-ATTR:hypervisor_hostname'],
sot.hypervisor_hostname)
self.assertEqual(EXAMPLE['OS-EXT-SRV-ATTR:instance_name'],
sot.instance_name)
self.assertEqual(EXAMPLE['OS-EXT-SRV-ATTR:kernel_id'],
sot.kernel_id)
self.assertEqual(EXAMPLE['OS-EXT-SRV-ATTR:launch_index'],
sot.launch_index)
self.assertEqual(EXAMPLE['OS-EXT-SRV-ATTR:ramdisk_id'],
sot.ramdisk_id)
self.assertEqual(EXAMPLE['OS-EXT-SRV-ATTR:reservation_id'],
sot.reservation_id)
self.assertEqual(EXAMPLE['OS-EXT-SRV-ATTR:root_device_name'],
sot.root_device_name)
self.assertEqual(EXAMPLE['OS-SCH-HNT:scheduler_hints'],
sot.scheduler_hints)
self.assertEqual(EXAMPLE['OS-EXT-SRV-ATTR:user_data'], sot.user_data)
self.assertEqual(EXAMPLE['locked'], sot.is_locked)
self.assertEqual(EXAMPLE['trusted_image_certificates'],
sot.trusted_image_certificates)
def test__prepare_server(self):
zone = 1

View File

@ -41,6 +41,7 @@ class TestFromSession(base.TestCase):
server_name = self.getUniqueString('name')
fake_server = fakes.make_fake_server(server_id, server_name)
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET',
uri=self.get_mock_url(
'compute', 'public', append=['servers', 'detail']),

View File

@ -209,6 +209,7 @@ class TestStats(base.TestCase):
mock_uri = 'https://compute.example.com/v2.1/servers/detail'
self.register_uris([
self.get_nova_discovery_mock_dict(),
dict(method='GET', uri=mock_uri, status_code=200,
json={'servers': []})])