Add new live_migration case to support block_migration=auto

Compute microversion 2.25 supports auto block_migration
and also the disk_over_commit flag has been removed.

Details: http://docs.openstack.org/developer/nova/api_microversion_history.html#maximum-in-mitaka

This commit adds tests for the same.
Also adds the below required schema for version 2.25 tests.

- 2.3 Schema. Details:
http://docs.openstack.org/developer/nova/api_microversion_history.html#maximum-in-kilo

- 2.16 Schema. Details:
http://docs.openstack.org/developer/nova/api_microversion_history.html#id14

- 2.23 Schema. Details:
http://docs.openstack.org/developer/nova/api_microversion_history.html#id21

Co-Authored-By: ghanshyam <ghanshyam.mann@nectechnologies.in>

Change-Id: I0fb5567cb4f7363465b68b86174b2df039f183d9
This commit is contained in:
Eli Qiao 2016-03-03 13:49:37 +08:00 committed by ghanshyam
parent 5e930c2d8a
commit e07eaccf84
12 changed files with 429 additions and 10 deletions

View File

@ -217,3 +217,7 @@ Microversion tests implemented in Tempest
* `2.20`_
.. _2.20: http://docs.openstack.org/developer/nova/api_microversion_history.html#id18
* `2.25`_
.. _2.25: http://docs.openstack.org/developer/nova/api_microversion_history.html#maximum-in-mitaka

View File

@ -27,6 +27,8 @@ CONF = config.CONF
class LiveBlockMigrationTestJSON(base.BaseV2ComputeAdminTest):
_host_key = 'OS-EXT-SRV-ATTR:host'
max_microversion = '2.24'
block_migration = None
@classmethod
def skip_checks(cls):
@ -64,12 +66,16 @@ class LiveBlockMigrationTestJSON(base.BaseV2ComputeAdminTest):
return self._get_server_details(server_id)[self._host_key]
def _migrate_server_to(self, server_id, dest_host, volume_backed=False):
block_migration = (CONF.compute_feature_enabled.
block_migration_for_live_migration and
not volume_backed)
kwargs = dict()
block_migration = getattr(self, 'block_migration', None)
if self.block_migration is None:
kwargs['disk_over_commit'] = False
block_migration = (CONF.compute_feature_enabled.
block_migration_for_live_migration and
not volume_backed)
body = self.admin_servers_client.live_migrate_server(
server_id, host=dest_host, block_migration=block_migration,
disk_over_commit=False)
**kwargs)
return body
def _get_host_other_than(self, host):
@ -167,3 +173,9 @@ class LiveBlockMigrationTestJSON(base.BaseV2ComputeAdminTest):
waiters.wait_for_server_status(self.servers_client,
server_id, 'ACTIVE')
self.assertEqual(target_host, self._get_host_for_server(server_id))
class LiveAutoBlockMigrationV225TestJSON(LiveBlockMigrationTestJSON):
min_microversion = '2.25'
max_microversion = 'latest'
block_migration = 'auto'

View File

@ -0,0 +1,160 @@
# Copyright 2014 NEC Corporation. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import copy
from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
from tempest.lib.api_schema.response.compute.v2_9 import servers
# Compute microversion 2.16:
# 1. New attributes in 'server' dict.
# 'host_status'
server_detail = {
'type': 'object',
'properties': {
'id': {'type': 'string'},
'name': {'type': 'string'},
'status': {'type': 'string'},
'image': {'oneOf': [
{'type': 'object',
'properties': {
'id': {'type': 'string'},
'links': parameter_types.links
},
'additionalProperties': False,
'required': ['id', 'links']},
{'type': ['string', 'null']}
]},
'flavor': {
'type': 'object',
'properties': {
'id': {'type': 'string'},
'links': parameter_types.links
},
'additionalProperties': False,
'required': ['id', 'links']
},
'fault': {
'type': 'object',
'properties': {
'code': {'type': 'integer'},
'created': {'type': 'string'},
'message': {'type': 'string'},
'details': {'type': 'string'},
},
'additionalProperties': False,
# NOTE(gmann): 'details' is not necessary to be present
# in the 'fault'. So it is not defined as 'required'.
'required': ['code', 'created', 'message']
},
'user_id': {'type': 'string'},
'tenant_id': {'type': 'string'},
'created': {'type': 'string'},
'updated': {'type': 'string'},
'progress': {'type': 'integer'},
'metadata': {'type': 'object'},
'links': parameter_types.links,
'addresses': parameter_types.addresses,
'hostId': {'type': 'string'},
'OS-DCF:diskConfig': {'type': 'string'},
'accessIPv4': parameter_types.access_ip_v4,
'accessIPv6': parameter_types.access_ip_v6,
'key_name': {'type': ['string', 'null']},
'security_groups': {'type': 'array'},
'OS-SRV-USG:launched_at': {'type': ['string', 'null']},
'OS-SRV-USG:terminated_at': {'type': ['string', 'null']},
'OS-EXT-AZ:availability_zone': {'type': 'string'},
'OS-EXT-STS:task_state': {'type': ['string', 'null']},
'OS-EXT-STS:vm_state': {'type': 'string'},
'OS-EXT-STS:power_state': {'type': 'integer'},
'OS-EXT-SRV-ATTR:host': {'type': ['string', 'null']},
'OS-EXT-SRV-ATTR:instance_name': {'type': 'string'},
'OS-EXT-SRV-ATTR:hypervisor_hostname': {'type': ['string', 'null']},
'config_drive': {'type': 'string'},
'os-extended-volumes:volumes_attached': {
'type': 'array',
'items': {
'type': 'object',
'properties': {
'id': {'type': 'string'},
'delete_on_termination': {'type': 'boolean'}
},
'additionalProperties': False,
},
},
'OS-EXT-SRV-ATTR:reservation_id': {'type': ['string', 'null']},
'OS-EXT-SRV-ATTR:launch_index': {'type': 'integer'},
'OS-EXT-SRV-ATTR:kernel_id': {'type': ['string', 'null']},
'OS-EXT-SRV-ATTR:ramdisk_id': {'type': ['string', 'null']},
'OS-EXT-SRV-ATTR:hostname': {'type': 'string'},
'OS-EXT-SRV-ATTR:root_device_name': {'type': ['string', 'null']},
'OS-EXT-SRV-ATTR:user_data': {'type': ['string', 'null']},
'locked': {'type': 'boolean'},
# NOTE(gmann): new attributes in version 2.16
'host_status': {'type': 'string'}
},
'additionalProperties': False,
# NOTE(gmann): 'progress' attribute is present in the response
# only when server's status is one of the progress statuses
# ("ACTIVE","BUILD", "REBUILD", "RESIZE","VERIFY_RESIZE")
# 'fault' attribute is present in the response
# only when server's status is one of the "ERROR", "DELETED".
# OS-DCF:diskConfig and accessIPv4/v6 are API
# extensions, and some environments return a response
# without these attributes.So these are not defined as 'required'.
'required': ['id', 'name', 'status', 'image', 'flavor',
'user_id', 'tenant_id', 'created', 'updated',
'metadata', 'links', 'addresses', 'hostId']
}
server_detail['properties']['addresses']['patternProperties'][
'^[a-zA-Z0-9-_.]+$']['items']['properties'].update({
'OS-EXT-IPS:type': {'type': 'string'},
'OS-EXT-IPS-MAC:mac_addr': parameter_types.mac_address})
# NOTE(gmann)dd: Update OS-EXT-IPS:type and OS-EXT-IPS-MAC:mac_addr
# attributes in server address. Those are API extension,
# and some environments return a response without
# these attributes. So they are not 'required'.
get_server = {
'status_code': [200],
'response_body': {
'type': 'object',
'properties': {
'server': server_detail
},
'additionalProperties': False,
'required': ['server']
}
}
list_servers_detail = {
'status_code': [200],
'response_body': {
'type': 'object',
'properties': {
'servers': {
'type': 'array',
'items': server_detail
},
'servers_links': parameter_types.links
},
'additionalProperties': False,
# NOTE(gmann): servers_links attribute is not necessary to be
# present always So it is not 'required'.
'required': ['servers']
}
}
list_servers = copy.deepcopy(servers.list_servers)

View File

@ -15,15 +15,18 @@
import copy
from tempest.lib.api_schema.response.compute.v2_1 import servers as serversv21
from tempest.lib.api_schema.response.compute.v2_9 import servers as serversv29
from tempest.lib.api_schema.response.compute.v2_16 import servers \
as serversv216
get_server = copy.deepcopy(serversv29.get_server)
list_servers = copy.deepcopy(serversv216.list_servers)
get_server = copy.deepcopy(serversv216.get_server)
get_server['response_body']['properties']['server'][
'properties'].update({'description': {'type': ['string', 'null']}})
get_server['response_body']['properties']['server'][
'required'].append('description')
list_servers_detail = copy.deepcopy(serversv29.list_servers_detail)
list_servers_detail = copy.deepcopy(serversv216.list_servers_detail)
list_servers_detail['response_body']['properties']['servers']['items'][
'properties'].update({'description': {'type': ['string', 'null']}})
list_servers_detail['response_body']['properties']['servers']['items'][

View File

@ -0,0 +1,62 @@
# Copyright 2014 NEC Corporation. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
# Compute microversion 2.23:
# New attributes in 'migrations' list.
# 'migration_type'
# 'links'
list_migrations = {
'status_code': [200],
'response_body': {
'type': 'object',
'properties': {
'migrations': {
'type': 'array',
'items': {
'type': 'object',
'properties': {
'id': {'type': 'integer'},
'status': {'type': ['string', 'null']},
'instance_uuid': {'type': ['string', 'null']},
'source_node': {'type': ['string', 'null']},
'source_compute': {'type': ['string', 'null']},
'dest_node': {'type': ['string', 'null']},
'dest_compute': {'type': ['string', 'null']},
'dest_host': {'type': ['string', 'null']},
'old_instance_type_id': {'type': ['integer', 'null']},
'new_instance_type_id': {'type': ['integer', 'null']},
'created_at': {'type': 'string'},
'updated_at': {'type': ['string', 'null']},
# New attributes in version 2.23
'migration_type': {'type': ['string', 'null']},
'links': parameter_types.links
},
'additionalProperties': False,
'required': [
'id', 'status', 'instance_uuid', 'source_node',
'source_compute', 'dest_node', 'dest_compute',
'dest_host', 'old_instance_type_id',
'new_instance_type_id', 'created_at', 'updated_at',
'migration_type'
]
}
}
},
'additionalProperties': False,
'required': ['migrations']
}
}

View File

@ -0,0 +1,166 @@
# Copyright 2014 NEC Corporation. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import copy
from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
from tempest.lib.api_schema.response.compute.v2_1 import servers
# Compute microversion 2.3:
# 1. New attributes in 'os-extended-volumes:volumes_attached' dict.
# 'delete_on_termination'
# 2. New attributes in 'server' dict.
# 'OS-EXT-SRV-ATTR:reservation_id'
# 'OS-EXT-SRV-ATTR:launch_index'
# 'OS-EXT-SRV-ATTR:kernel_id'
# 'OS-EXT-SRV-ATTR:ramdisk_id'
# 'OS-EXT-SRV-ATTR:hostname'
# 'OS-EXT-SRV-ATTR:root_device_name'
# 'OS-EXT-SRV-ATTR:user_data'
server_detail = {
'type': 'object',
'properties': {
'id': {'type': 'string'},
'name': {'type': 'string'},
'status': {'type': 'string'},
'image': {'oneOf': [
{'type': 'object',
'properties': {
'id': {'type': 'string'},
'links': parameter_types.links
},
'additionalProperties': False,
'required': ['id', 'links']},
{'type': ['string', 'null']}
]},
'flavor': {
'type': 'object',
'properties': {
'id': {'type': 'string'},
'links': parameter_types.links
},
'additionalProperties': False,
'required': ['id', 'links']
},
'fault': {
'type': 'object',
'properties': {
'code': {'type': 'integer'},
'created': {'type': 'string'},
'message': {'type': 'string'},
'details': {'type': 'string'},
},
'additionalProperties': False,
# NOTE(gmann): 'details' is not necessary to be present
# in the 'fault'. So it is not defined as 'required'.
'required': ['code', 'created', 'message']
},
'user_id': {'type': 'string'},
'tenant_id': {'type': 'string'},
'created': {'type': 'string'},
'updated': {'type': 'string'},
'progress': {'type': 'integer'},
'metadata': {'type': 'object'},
'links': parameter_types.links,
'addresses': parameter_types.addresses,
'hostId': {'type': 'string'},
'OS-DCF:diskConfig': {'type': 'string'},
'accessIPv4': parameter_types.access_ip_v4,
'accessIPv6': parameter_types.access_ip_v6,
'key_name': {'type': ['string', 'null']},
'security_groups': {'type': 'array'},
'OS-SRV-USG:launched_at': {'type': ['string', 'null']},
'OS-SRV-USG:terminated_at': {'type': ['string', 'null']},
'OS-EXT-AZ:availability_zone': {'type': 'string'},
'OS-EXT-STS:task_state': {'type': ['string', 'null']},
'OS-EXT-STS:vm_state': {'type': 'string'},
'OS-EXT-STS:power_state': {'type': 'integer'},
'OS-EXT-SRV-ATTR:host': {'type': ['string', 'null']},
'OS-EXT-SRV-ATTR:instance_name': {'type': 'string'},
'OS-EXT-SRV-ATTR:hypervisor_hostname': {'type': ['string', 'null']},
'config_drive': {'type': 'string'},
# NOTE(gmann): new attributes in version 2.3
'os-extended-volumes:volumes_attached': {
'type': 'array',
'items': {
'type': 'object',
'properties': {
'id': {'type': 'string'},
'delete_on_termination': {'type': 'boolean'}
},
'additionalProperties': False,
},
},
'OS-EXT-SRV-ATTR:reservation_id': {'type': ['string', 'null']},
'OS-EXT-SRV-ATTR:launch_index': {'type': 'integer'},
'OS-EXT-SRV-ATTR:kernel_id': {'type': ['string', 'null']},
'OS-EXT-SRV-ATTR:ramdisk_id': {'type': ['string', 'null']},
'OS-EXT-SRV-ATTR:hostname': {'type': 'string'},
'OS-EXT-SRV-ATTR:root_device_name': {'type': ['string', 'null']},
'OS-EXT-SRV-ATTR:user_data': {'type': ['string', 'null']},
},
'additionalProperties': False,
# NOTE(gmann): 'progress' attribute is present in the response
# only when server's status is one of the progress statuses
# ("ACTIVE","BUILD", "REBUILD", "RESIZE","VERIFY_RESIZE")
# 'fault' attribute is present in the response
# only when server's status is one of the "ERROR", "DELETED".
# OS-DCF:diskConfig and accessIPv4/v6 are API
# extensions, and some environments return a response
# without these attributes.So these are not defined as 'required'.
'required': ['id', 'name', 'status', 'image', 'flavor',
'user_id', 'tenant_id', 'created', 'updated',
'metadata', 'links', 'addresses', 'hostId']
}
server_detail['properties']['addresses']['patternProperties'][
'^[a-zA-Z0-9-_.]+$']['items']['properties'].update({
'OS-EXT-IPS:type': {'type': 'string'},
'OS-EXT-IPS-MAC:mac_addr': parameter_types.mac_address})
# NOTE(gmann)dd: Update OS-EXT-IPS:type and OS-EXT-IPS-MAC:mac_addr
# attributes in server address. Those are API extension,
# and some environments return a response without
# these attributes. So they are not 'required'.
get_server = {
'status_code': [200],
'response_body': {
'type': 'object',
'properties': {
'server': server_detail
},
'additionalProperties': False,
'required': ['server']
}
}
list_servers_detail = {
'status_code': [200],
'response_body': {
'type': 'object',
'properties': {
'servers': {
'type': 'array',
'items': server_detail
},
'servers_links': parameter_types.links
},
'additionalProperties': False,
# NOTE(gmann): servers_links attribute is not necessary to be
# present always So it is not 'required'.
'required': ['servers']
}
}
list_servers = copy.deepcopy(servers.list_servers)

View File

@ -14,7 +14,9 @@
import copy
from tempest.lib.api_schema.response.compute.v2_1 import servers
from tempest.lib.api_schema.response.compute.v2_3 import servers
list_servers = copy.deepcopy(servers.list_servers)
get_server = copy.deepcopy(servers.get_server)
get_server['response_body']['properties']['server'][

View File

@ -16,11 +16,16 @@ from oslo_serialization import jsonutils as json
from six.moves.urllib import parse as urllib
from tempest.lib.api_schema.response.compute.v2_1 import migrations as schema
from tempest.lib.api_schema.response.compute.v2_23 import migrations \
as schemav223
from tempest.lib.common import rest_client
from tempest.lib.services.compute import base_compute_client
class MigrationsClient(base_compute_client.BaseComputeClient):
schema_versions_info = [
{'min': None, 'max': '2.22', 'schema': schema},
{'min': '2.23', 'max': None, 'schema': schemav223}]
def list_migrations(self, **params):
"""List all migrations.
@ -35,5 +40,6 @@ class MigrationsClient(base_compute_client.BaseComputeClient):
resp, body = self.get(url)
body = json.loads(body)
schema = self.get_schema(self.schema_versions_info)
self.validate_response(schema.list_migrations, resp, body)
return rest_client.ResponseBody(resp, body)

View File

@ -20,7 +20,9 @@ from oslo_serialization import jsonutils as json
from six.moves.urllib import parse as urllib
from tempest.lib.api_schema.response.compute.v2_1 import servers as schema
from tempest.lib.api_schema.response.compute.v2_16 import servers as schemav216
from tempest.lib.api_schema.response.compute.v2_19 import servers as schemav219
from tempest.lib.api_schema.response.compute.v2_3 import servers as schemav23
from tempest.lib.api_schema.response.compute.v2_9 import servers as schemav29
from tempest.lib.common import rest_client
from tempest.lib.services.compute import base_compute_client
@ -28,8 +30,10 @@ from tempest.lib.services.compute import base_compute_client
class ServersClient(base_compute_client.BaseComputeClient):
schema_versions_info = [
{'min': None, 'max': '2.8', 'schema': schema},
{'min': '2.9', 'max': '2.18', 'schema': schemav29},
{'min': None, 'max': '2.2', 'schema': schema},
{'min': '2.3', 'max': '2.8', 'schema': schemav23},
{'min': '2.9', 'max': '2.15', 'schema': schemav29},
{'min': '2.16', 'max': '2.18', 'schema': schemav216},
{'min': '2.19', 'max': None, 'schema': schemav219}]
def __init__(self, auth_provider, service, region,