Merge extended_volumes extension response into server view builder
As nova extensions have been deprecated already, the goal is to merge all scattered code into main controller side. Currently schema and request/response extended code are there among all extensions. This commit merges the extended_volumes extension response into server view builder. Partially implements: blueprint api-extensions-merge-stein Change-Id: I412ccfd5495b088c941a819b5946dc56ed86ae22
This commit is contained in:
parent
a899e09cfe
commit
c5788293aa
@ -1,94 +0,0 @@
|
||||
# Copyright 2013 OpenStack Foundation
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""The Extended Volumes API extension."""
|
||||
from oslo_log import log as logging
|
||||
|
||||
from nova.api.openstack import api_version_request
|
||||
from nova.api.openstack import wsgi
|
||||
from nova import context
|
||||
from nova import objects
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ExtendedVolumesController(wsgi.Controller):
|
||||
def _extend_server(self, server, req, bdms):
|
||||
volumes_attached = []
|
||||
for bdm in bdms:
|
||||
if bdm.get('volume_id'):
|
||||
volume_attached = {'id': bdm['volume_id']}
|
||||
if api_version_request.is_supported(req, min_version='2.3'):
|
||||
volume_attached['delete_on_termination'] = (
|
||||
bdm['delete_on_termination'])
|
||||
volumes_attached.append(volume_attached)
|
||||
# NOTE(mriedem): The os-extended-volumes prefix should not be used for
|
||||
# new attributes after v2.1. They are only in v2.1 for backward compat
|
||||
# with v2.0.
|
||||
key = "os-extended-volumes:volumes_attached"
|
||||
server[key] = volumes_attached
|
||||
|
||||
@wsgi.extends
|
||||
def show(self, req, resp_obj, id):
|
||||
context = req.environ['nova.context']
|
||||
server = resp_obj.obj['server']
|
||||
bdms = objects.BlockDeviceMappingList.bdms_by_instance_uuid(
|
||||
context, [server['id']])
|
||||
instance_bdms = self._get_instance_bdms(bdms, server)
|
||||
self._extend_server(server, req, instance_bdms)
|
||||
|
||||
@staticmethod
|
||||
def _get_instance_bdms_in_multiple_cells(ctxt, servers):
|
||||
instance_uuids = [server['id'] for server in servers]
|
||||
inst_maps = objects.InstanceMappingList.get_by_instance_uuids(
|
||||
ctxt, instance_uuids)
|
||||
|
||||
cell_mappings = {}
|
||||
for inst_map in inst_maps:
|
||||
if (inst_map.cell_mapping is not None and
|
||||
inst_map.cell_mapping.uuid not in cell_mappings):
|
||||
cell_mappings.update(
|
||||
{inst_map.cell_mapping.uuid: inst_map.cell_mapping})
|
||||
|
||||
bdms = {}
|
||||
results = context.scatter_gather_cells(
|
||||
ctxt, cell_mappings.values(), context.CELL_TIMEOUT,
|
||||
objects.BlockDeviceMappingList.bdms_by_instance_uuid,
|
||||
instance_uuids)
|
||||
for cell_uuid, result in results.items():
|
||||
if result is context.raised_exception_sentinel:
|
||||
LOG.warning('Failed to get block device mappings for cell %s',
|
||||
cell_uuid)
|
||||
elif result is context.did_not_respond_sentinel:
|
||||
LOG.warning('Timeout getting block device mappings for cell '
|
||||
'%s', cell_uuid)
|
||||
else:
|
||||
bdms.update(result)
|
||||
return bdms
|
||||
|
||||
@wsgi.extends
|
||||
def detail(self, req, resp_obj):
|
||||
context = req.environ['nova.context']
|
||||
servers = list(resp_obj.obj['servers'])
|
||||
bdms = self._get_instance_bdms_in_multiple_cells(context, servers)
|
||||
for server in servers:
|
||||
instance_bdms = self._get_instance_bdms(bdms, server)
|
||||
self._extend_server(server, req, instance_bdms)
|
||||
|
||||
def _get_instance_bdms(self, bdms, server):
|
||||
# server['id'] is guaranteed to be in the cache due to
|
||||
# the core API adding it in the 'detail' or 'show' method.
|
||||
# If that instance has since been deleted, it won't be in the
|
||||
# 'bdms' dictionary though, so use 'get' to avoid KeyErrors.
|
||||
return bdms.get(server['id'], [])
|
@ -35,7 +35,6 @@ from nova.api.openstack.compute import consoles
|
||||
from nova.api.openstack.compute import create_backup
|
||||
from nova.api.openstack.compute import deferred_delete
|
||||
from nova.api.openstack.compute import evacuate
|
||||
from nova.api.openstack.compute import extended_volumes
|
||||
from nova.api.openstack.compute import extension_info
|
||||
from nova.api.openstack.compute import fixed_ips
|
||||
from nova.api.openstack.compute import flavor_access
|
||||
@ -265,7 +264,6 @@ security_group_rules_controller = functools.partial(_create_controller,
|
||||
server_controller = functools.partial(_create_controller,
|
||||
servers.ServersController,
|
||||
[
|
||||
extended_volumes.ExtendedVolumesController,
|
||||
hide_server_addresses.Controller,
|
||||
],
|
||||
[
|
||||
|
@ -725,7 +725,8 @@ class ServersController(wsgi.Controller):
|
||||
show_keypair=False,
|
||||
show_srv_usg=False,
|
||||
show_sec_grp=False,
|
||||
show_extended_status=False)
|
||||
show_extended_status=False,
|
||||
show_extended_volumes=False)
|
||||
except exception.InstanceNotFound:
|
||||
msg = _("Instance could not be found")
|
||||
raise exc.HTTPNotFound(explanation=msg)
|
||||
@ -1001,7 +1002,8 @@ class ServersController(wsgi.Controller):
|
||||
show_keypair=show_keypair,
|
||||
show_srv_usg=False,
|
||||
show_sec_grp=False,
|
||||
show_extended_status=False)
|
||||
show_extended_status=False,
|
||||
show_extended_volumes=False)
|
||||
|
||||
# Add on the admin_password attribute since the view doesn't do it
|
||||
# unless instance passwords are disabled
|
||||
|
@ -92,7 +92,7 @@ class ViewBuilder(common.ViewBuilder):
|
||||
|
||||
def basic(self, request, instance, show_extra_specs=False,
|
||||
show_extended_attr=None, show_host_status=None,
|
||||
show_sec_grp=None):
|
||||
show_sec_grp=None, bdms=None):
|
||||
"""Generic, non-detailed view of an instance."""
|
||||
return {
|
||||
"server": {
|
||||
@ -128,7 +128,8 @@ class ViewBuilder(common.ViewBuilder):
|
||||
show_extra_specs=None, show_AZ=True, show_config_drive=True,
|
||||
show_extended_attr=None, show_host_status=None,
|
||||
show_keypair=True, show_srv_usg=True, show_sec_grp=True,
|
||||
show_extended_status=True):
|
||||
show_extended_status=True, show_extended_volumes=True,
|
||||
bdms=None):
|
||||
"""Detailed view of a single instance."""
|
||||
ip_v4 = instance.get('access_ip_v4')
|
||||
ip_v6 = instance.get('access_ip_v6')
|
||||
@ -239,6 +240,18 @@ class ViewBuilder(common.ViewBuilder):
|
||||
# compat with v2.0.
|
||||
key = "%s:%s" % ('OS-EXT-STS', state)
|
||||
server["server"][key] = instance[state]
|
||||
if show_extended_volumes:
|
||||
# NOTE(mriedem): The os-extended-volumes prefix should not be used
|
||||
# for new attributes after v2.1. They are only in v2.1 for backward
|
||||
# compat with v2.0.
|
||||
add_delete_on_termination = api_version_request.is_supported(
|
||||
request, min_version='2.3')
|
||||
if bdms is None:
|
||||
bdms = objects.BlockDeviceMappingList.bdms_by_instance_uuid(
|
||||
context, [instance["uuid"]])
|
||||
self._add_volumes_attachments(server["server"],
|
||||
bdms,
|
||||
add_delete_on_termination)
|
||||
if (api_version_request.is_supported(request, min_version='2.16')):
|
||||
if show_host_status is None:
|
||||
show_host_status = context.can(
|
||||
@ -292,6 +305,11 @@ class ViewBuilder(common.ViewBuilder):
|
||||
if (api_version_request.is_supported(request, min_version='2.16')):
|
||||
show_host_status = context.can(
|
||||
servers_policies.SERVERS % 'show:host_status', fatal=False)
|
||||
|
||||
instance_uuids = [inst['uuid'] for inst in instances]
|
||||
bdms = self._get_instance_bdms_in_multiple_cells(context,
|
||||
instance_uuids)
|
||||
|
||||
# NOTE(gmann): pass show_sec_grp=False in _list_view() because
|
||||
# security groups for detail method will be added by separate
|
||||
# call to self._add_security_grps by passing the all servers
|
||||
@ -300,7 +318,8 @@ class ViewBuilder(common.ViewBuilder):
|
||||
coll_name, show_extra_specs,
|
||||
show_extended_attr=show_extended_attr,
|
||||
show_host_status=show_host_status,
|
||||
show_sec_grp=False)
|
||||
show_sec_grp=False,
|
||||
bdms=bdms)
|
||||
|
||||
self._add_security_grps(request, list(servers_dict["servers"]),
|
||||
instances)
|
||||
@ -308,7 +327,7 @@ class ViewBuilder(common.ViewBuilder):
|
||||
|
||||
def _list_view(self, func, request, servers, coll_name, show_extra_specs,
|
||||
show_extended_attr=None, show_host_status=None,
|
||||
show_sec_grp=False):
|
||||
show_sec_grp=False, bdms=None):
|
||||
"""Provide a view for a list of servers.
|
||||
|
||||
:param func: Function used to format the server data
|
||||
@ -322,13 +341,14 @@ class ViewBuilder(common.ViewBuilder):
|
||||
the response dict.
|
||||
:param show_sec_grp: If the security group should be included in
|
||||
the response dict.
|
||||
:param bdms: Instances bdms info from multiple cells.
|
||||
:returns: Server data in dictionary format
|
||||
"""
|
||||
server_list = [func(request, server,
|
||||
show_extra_specs=show_extra_specs,
|
||||
show_extended_attr=show_extended_attr,
|
||||
show_host_status=show_host_status,
|
||||
show_sec_grp=show_sec_grp)["server"]
|
||||
show_sec_grp=show_sec_grp, bdms=bdms)["server"]
|
||||
for server in servers]
|
||||
servers_links = self._get_collection_links(request,
|
||||
servers,
|
||||
@ -496,3 +516,53 @@ class ViewBuilder(common.ViewBuilder):
|
||||
# request add default since that is the group it is part of
|
||||
servers[0]['security_groups'] = req_obj['server'].get(
|
||||
'security_groups', [{'name': 'default'}])
|
||||
|
||||
@staticmethod
|
||||
def _get_instance_bdms_in_multiple_cells(ctxt, instance_uuids):
|
||||
inst_maps = objects.InstanceMappingList.get_by_instance_uuids(
|
||||
ctxt, instance_uuids)
|
||||
|
||||
cell_mappings = {}
|
||||
for inst_map in inst_maps:
|
||||
if (inst_map.cell_mapping is not None and
|
||||
inst_map.cell_mapping.uuid not in cell_mappings):
|
||||
cell_mappings.update(
|
||||
{inst_map.cell_mapping.uuid: inst_map.cell_mapping})
|
||||
|
||||
bdms = {}
|
||||
results = nova_context.scatter_gather_cells(
|
||||
ctxt, cell_mappings.values(),
|
||||
nova_context.CELL_TIMEOUT,
|
||||
objects.BlockDeviceMappingList.bdms_by_instance_uuid,
|
||||
instance_uuids)
|
||||
for cell_uuid, result in results.items():
|
||||
if result is nova_context.raised_exception_sentinel:
|
||||
LOG.warning('Failed to get block device mappings for cell %s',
|
||||
cell_uuid)
|
||||
elif result is nova_context.did_not_respond_sentinel:
|
||||
LOG.warning('Timeout getting block device mappings for cell '
|
||||
'%s', cell_uuid)
|
||||
else:
|
||||
bdms.update(result)
|
||||
return bdms
|
||||
|
||||
def _add_volumes_attachments(self, server, bdms,
|
||||
add_delete_on_termination):
|
||||
# server['id'] is guaranteed to be in the cache due to
|
||||
# the core API adding it in the 'detail' or 'show' method.
|
||||
# If that instance has since been deleted, it won't be in the
|
||||
# 'bdms' dictionary though, so use 'get' to avoid KeyErrors.
|
||||
instance_bdms = bdms.get(server['id'], [])
|
||||
volumes_attached = []
|
||||
for bdm in instance_bdms:
|
||||
if bdm.get('volume_id'):
|
||||
volume_attached = {'id': bdm['volume_id']}
|
||||
if add_delete_on_termination:
|
||||
volume_attached['delete_on_termination'] = (
|
||||
bdm['delete_on_termination'])
|
||||
volumes_attached.append(volume_attached)
|
||||
# NOTE(mriedem): The os-extended-volumes prefix should not be used for
|
||||
# new attributes after v2.1. They are only in v2.1 for backward compat
|
||||
# with v2.0.
|
||||
key = "os-extended-volumes:volumes_attached"
|
||||
server[key] = volumes_attached
|
||||
|
@ -1,222 +0,0 @@
|
||||
# Copyright 2013 OpenStack Foundation
|
||||
# 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 mock
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils.fixture import uuidsentinel as uuids
|
||||
|
||||
from nova.api.openstack.compute import (extended_volumes
|
||||
as extended_volumes_v21)
|
||||
from nova.api.openstack import wsgi as os_wsgi
|
||||
from nova import context as nova_context
|
||||
from nova import objects
|
||||
from nova.objects import instance as instance_obj
|
||||
from nova import test
|
||||
from nova.tests.unit.api.openstack import fakes
|
||||
from nova.tests.unit import fake_block_device
|
||||
from nova.tests.unit import fake_instance
|
||||
|
||||
|
||||
UUID1 = '00000000-0000-0000-0000-000000000001'
|
||||
UUID2 = '00000000-0000-0000-0000-000000000002'
|
||||
UUID3 = '00000000-0000-0000-0000-000000000003'
|
||||
|
||||
|
||||
def fake_compute_get(*args, **kwargs):
|
||||
inst = fakes.stub_instance(1, uuid=UUID1)
|
||||
return fake_instance.fake_instance_obj(args[1], **inst)
|
||||
|
||||
|
||||
def fake_compute_get_all(*args, **kwargs):
|
||||
db_list = [
|
||||
fakes.stub_instance(1, uuid=UUID1),
|
||||
fakes.stub_instance(2, uuid=UUID2),
|
||||
]
|
||||
fields = instance_obj.INSTANCE_DEFAULT_FIELDS
|
||||
return instance_obj._make_instance_list(args[1],
|
||||
objects.InstanceList(),
|
||||
db_list, fields)
|
||||
|
||||
|
||||
def fake_bdms_get_all_by_instance_uuids(*args, **kwargs):
|
||||
return [
|
||||
fake_block_device.FakeDbBlockDeviceDict({
|
||||
'id': 1,
|
||||
'volume_id': 'some_volume_1',
|
||||
'instance_uuid': UUID1,
|
||||
'source_type': 'volume',
|
||||
'destination_type': 'volume',
|
||||
'delete_on_termination': True,
|
||||
}),
|
||||
fake_block_device.FakeDbBlockDeviceDict({
|
||||
'id': 2,
|
||||
'volume_id': 'some_volume_2',
|
||||
'instance_uuid': UUID2,
|
||||
'source_type': 'volume',
|
||||
'destination_type': 'volume',
|
||||
'delete_on_termination': False,
|
||||
}),
|
||||
fake_block_device.FakeDbBlockDeviceDict({
|
||||
'id': 3,
|
||||
'volume_id': 'some_volume_3',
|
||||
'instance_uuid': UUID2,
|
||||
'source_type': 'volume',
|
||||
'destination_type': 'volume',
|
||||
'delete_on_termination': False,
|
||||
}),
|
||||
]
|
||||
|
||||
|
||||
class ExtendedVolumesTestV21(test.TestCase):
|
||||
content_type = 'application/json'
|
||||
prefix = 'os-extended-volumes:'
|
||||
exp_volumes_show = [{'id': 'some_volume_1'}]
|
||||
exp_volumes_detail = [
|
||||
[{'id': 'some_volume_1'}],
|
||||
[{'id': 'some_volume_2'}, {'id': 'some_volume_3'}],
|
||||
]
|
||||
wsgi_api_version = os_wsgi.DEFAULT_API_VERSION
|
||||
|
||||
def setUp(self):
|
||||
super(ExtendedVolumesTestV21, self).setUp()
|
||||
fakes.stub_out_nw_api(self)
|
||||
fakes.stub_out_secgroup_api(self)
|
||||
self.stub_out('nova.compute.api.API.get', fake_compute_get)
|
||||
self.stub_out('nova.compute.api.API.get_all', fake_compute_get_all)
|
||||
self.stub_out(
|
||||
'nova.db.api.block_device_mapping_get_all_by_instance_uuids',
|
||||
fake_bdms_get_all_by_instance_uuids)
|
||||
self._setUp()
|
||||
self.app = self._setup_app()
|
||||
return_server = fakes.fake_instance_get()
|
||||
self.stub_out('nova.db.api.instance_get_by_uuid', return_server)
|
||||
|
||||
def _setup_app(self):
|
||||
return fakes.wsgi_app_v21()
|
||||
|
||||
def _setUp(self):
|
||||
self.Controller = extended_volumes_v21.ExtendedVolumesController()
|
||||
self.stub_out('nova.volume.cinder.API.get', lambda *a, **k: None)
|
||||
|
||||
def _make_request(self, url, body=None):
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/servers' + url)
|
||||
req.headers['Accept'] = self.content_type
|
||||
req.headers = {os_wsgi.API_VERSION_REQUEST_HEADER:
|
||||
'compute %s' % self.wsgi_api_version}
|
||||
if body:
|
||||
req.body = jsonutils.dump_as_bytes(body)
|
||||
req.method = 'POST'
|
||||
req.content_type = self.content_type
|
||||
res = req.get_response(self.app)
|
||||
return res
|
||||
|
||||
def _get_server(self, body):
|
||||
return jsonutils.loads(body).get('server')
|
||||
|
||||
def _get_servers(self, body):
|
||||
return jsonutils.loads(body).get('servers')
|
||||
|
||||
def test_show(self):
|
||||
res = self._make_request('/%s' % UUID1)
|
||||
|
||||
self.assertEqual(200, res.status_int)
|
||||
server = self._get_server(res.body)
|
||||
actual = server.get('%svolumes_attached' % self.prefix)
|
||||
self.assertEqual(self.exp_volumes_show, actual)
|
||||
|
||||
@mock.patch.object(objects.InstanceMappingList, 'get_by_instance_uuids')
|
||||
def test_detail(self, mock_get_by_instance_uuids):
|
||||
mock_get_by_instance_uuids.return_value = [
|
||||
objects.InstanceMapping(
|
||||
instance_uuid=UUID1,
|
||||
cell_mapping=objects.CellMapping(
|
||||
uuid=uuids.cell1,
|
||||
transport_url='fake://nowhere/',
|
||||
database_connection=uuids.cell1)),
|
||||
objects.InstanceMapping(
|
||||
instance_uuid=UUID2,
|
||||
cell_mapping=objects.CellMapping(
|
||||
uuid=uuids.cell1,
|
||||
transport_url='fake://nowhere/',
|
||||
database_connection=uuids.cell1))]
|
||||
|
||||
res = self._make_request('/detail')
|
||||
mock_get_by_instance_uuids.assert_called_once_with(
|
||||
test.MatchType(nova_context.RequestContext), [UUID1, UUID2])
|
||||
|
||||
self.assertEqual(200, res.status_int)
|
||||
for i, server in enumerate(self._get_servers(res.body)):
|
||||
actual = server.get('%svolumes_attached' % self.prefix)
|
||||
self.assertEqual(self.exp_volumes_detail[i], actual)
|
||||
|
||||
@mock.patch.object(objects.InstanceMappingList, 'get_by_instance_uuids')
|
||||
@mock.patch('nova.context.scatter_gather_cells')
|
||||
def test_detail_with_cell_failures(self, mock_sg,
|
||||
mock_get_by_instance_uuids):
|
||||
|
||||
mock_get_by_instance_uuids.return_value = [
|
||||
objects.InstanceMapping(
|
||||
instance_uuid=UUID1,
|
||||
cell_mapping=objects.CellMapping(
|
||||
uuid=uuids.cell1,
|
||||
transport_url='fake://nowhere/',
|
||||
database_connection=uuids.cell1)),
|
||||
objects.InstanceMapping(
|
||||
instance_uuid=UUID2,
|
||||
cell_mapping=objects.CellMapping(
|
||||
uuid=uuids.cell2,
|
||||
transport_url='fake://nowhere/',
|
||||
database_connection=uuids.cell2))
|
||||
]
|
||||
bdm = fake_bdms_get_all_by_instance_uuids()
|
||||
fake_bdm = fake_block_device.fake_bdm_object(
|
||||
nova_context.RequestContext, bdm[0])
|
||||
mock_sg.return_value = {
|
||||
uuids.cell1: {UUID1: [fake_bdm]},
|
||||
uuids.cell2: nova_context.raised_exception_sentinel
|
||||
}
|
||||
|
||||
res = self._make_request('/detail')
|
||||
mock_get_by_instance_uuids.assert_called_once_with(
|
||||
test.MatchType(nova_context.RequestContext), [UUID1, UUID2])
|
||||
|
||||
self.assertEqual(200, res.status_int)
|
||||
|
||||
# we would get an empty list for the second instance
|
||||
# which is in the down cell, however this would printed
|
||||
# in the logs.
|
||||
for i, server in enumerate(self._get_servers(res.body)):
|
||||
actual = server.get('%svolumes_attached' % self.prefix)
|
||||
if i == 0:
|
||||
self.assertEqual(self.exp_volumes_detail[i], actual)
|
||||
else:
|
||||
self.assertEqual([], actual)
|
||||
|
||||
|
||||
class ExtendedVolumesTestV23(ExtendedVolumesTestV21):
|
||||
|
||||
exp_volumes_show = [
|
||||
{'id': 'some_volume_1', 'delete_on_termination': True},
|
||||
]
|
||||
exp_volumes_detail = [
|
||||
[
|
||||
{'id': 'some_volume_1', 'delete_on_termination': True},
|
||||
],
|
||||
[
|
||||
{'id': 'some_volume_2', 'delete_on_termination': False},
|
||||
{'id': 'some_volume_3', 'delete_on_termination': False},
|
||||
],
|
||||
]
|
||||
wsgi_api_version = '2.3'
|
@ -63,6 +63,7 @@ from nova import policy
|
||||
from nova import test
|
||||
from nova.tests import fixtures as nova_fixtures
|
||||
from nova.tests.unit.api.openstack import fakes
|
||||
from nova.tests.unit import fake_block_device
|
||||
from nova.tests.unit import fake_flavor
|
||||
from nova.tests.unit import fake_instance
|
||||
from nova.tests.unit import fake_network
|
||||
@ -147,6 +148,40 @@ def fake_compute_get_empty_az(*args, **kwargs):
|
||||
return fake_instance.fake_instance_obj(args[1], **inst)
|
||||
|
||||
|
||||
def fake_bdms_get_all_by_instance_uuids(*args, **kwargs):
|
||||
return [
|
||||
fake_block_device.FakeDbBlockDeviceDict({
|
||||
'id': 1,
|
||||
'volume_id': 'some_volume_1',
|
||||
'instance_uuid': FAKE_UUID,
|
||||
'source_type': 'volume',
|
||||
'destination_type': 'volume',
|
||||
'delete_on_termination': True,
|
||||
}),
|
||||
fake_block_device.FakeDbBlockDeviceDict({
|
||||
'id': 2,
|
||||
'volume_id': 'some_volume_2',
|
||||
'instance_uuid': FAKE_UUID,
|
||||
'source_type': 'volume',
|
||||
'destination_type': 'volume',
|
||||
'delete_on_termination': False,
|
||||
}),
|
||||
]
|
||||
|
||||
|
||||
def fake_get_inst_mappings_by_instance_uuids_from_db(*args, **kwargs):
|
||||
return [{
|
||||
'id': 1,
|
||||
'instance_uuid': UUID1,
|
||||
'cell_mapping': {
|
||||
'id': 1, 'uuid': uuids.cell1, 'name': 'fake',
|
||||
'transport_url': 'fake://nowhere/', 'updated_at': None,
|
||||
'database_connection': uuids.cell1, 'created_at': None,
|
||||
'disabled': False},
|
||||
'project_id': 'fake-project'
|
||||
}]
|
||||
|
||||
|
||||
class MockSetAdminPassword(object):
|
||||
def __init__(self):
|
||||
self.instance_id = None
|
||||
@ -190,6 +225,12 @@ class ControllerTest(test.TestCase):
|
||||
compute_api.API, 'get', side_effect=return_server)).mock
|
||||
self.stub_out('nova.db.api.instance_update_and_get_original',
|
||||
instance_update_and_get_original)
|
||||
self.stub_out('nova.db.api.'
|
||||
'block_device_mapping_get_all_by_instance_uuids',
|
||||
fake_bdms_get_all_by_instance_uuids)
|
||||
self.stub_out('nova.objects.InstanceMappingList.'
|
||||
'_get_by_instance_uuids_from_db',
|
||||
fake_get_inst_mappings_by_instance_uuids_from_db)
|
||||
self.flags(group='glance', api_servers=['http://localhost:9292'])
|
||||
|
||||
self.controller = servers.ServersController()
|
||||
@ -410,7 +451,11 @@ class ServersControllerTest(ControllerTest):
|
||||
{'name': 'fake-0-1'}],
|
||||
"OS-EXT-STS:task_state": None,
|
||||
"OS-EXT-STS:vm_state": vm_states.ACTIVE,
|
||||
"OS-EXT-STS:power_state": 1
|
||||
"OS-EXT-STS:power_state": 1,
|
||||
"os-extended-volumes:volumes_attached": [
|
||||
{'id': 'some_volume_1'},
|
||||
{'id': 'some_volume_2'},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -1560,6 +1605,9 @@ class ServersControllerTestV23(ServersControllerTest):
|
||||
server_dict['server']["OS-EXT-STS:task_state"] = None
|
||||
server_dict['server']["OS-EXT-STS:vm_state"] = vm_states.ACTIVE
|
||||
server_dict['server']["OS-EXT-STS:power_state"] = 1
|
||||
server_dict['server']["os-extended-volumes:volumes_attached"] = [
|
||||
{'id': 'some_volume_1', 'delete_on_termination': True},
|
||||
{'id': 'some_volume_2', 'delete_on_termination': False}]
|
||||
return server_dict
|
||||
|
||||
def test_show(self):
|
||||
@ -1674,6 +1722,9 @@ class ServersControllerTestV29(ServersControllerTest):
|
||||
server_dict['server']["OS-EXT-STS:task_state"] = None
|
||||
server_dict['server']["OS-EXT-STS:vm_state"] = vm_states.ACTIVE
|
||||
server_dict['server']["OS-EXT-STS:power_state"] = 1
|
||||
server_dict['server']["os-extended-volumes:volumes_attached"] = [
|
||||
{'id': 'some_volume_1', 'delete_on_termination': True},
|
||||
{'id': 'some_volume_2', 'delete_on_termination': False}]
|
||||
return server_dict
|
||||
|
||||
def _test_get_server_with_lock(self, locked_by):
|
||||
@ -1845,6 +1896,9 @@ class ServersControllerTestV216(ServersControllerTest):
|
||||
server_dict['server']["OS-EXT-STS:task_state"] = None
|
||||
server_dict['server']["OS-EXT-STS:vm_state"] = vm_states.ACTIVE
|
||||
server_dict['server']["OS-EXT-STS:power_state"] = 1
|
||||
server_dict['server']["os-extended-volumes:volumes_attached"] = [
|
||||
{'id': 'some_volume_1', 'delete_on_termination': True},
|
||||
{'id': 'some_volume_2', 'delete_on_termination': False}]
|
||||
|
||||
return server_dict
|
||||
|
||||
@ -1963,6 +2017,9 @@ class ServersControllerTestV219(ServersControllerTest):
|
||||
server_dict['server']["OS-EXT-STS:task_state"] = None
|
||||
server_dict['server']["OS-EXT-STS:vm_state"] = vm_states.ACTIVE
|
||||
server_dict['server']["OS-EXT-STS:power_state"] = 1
|
||||
server_dict['server']["os-extended-volumes:volumes_attached"] = [
|
||||
{'id': 'some_volume_1', 'delete_on_termination': True},
|
||||
{'id': 'some_volume_2', 'delete_on_termination': False}]
|
||||
|
||||
return server_dict
|
||||
|
||||
@ -6309,7 +6366,7 @@ class ServersViewBuilderTest(test.TestCase):
|
||||
db_inst = fakes.stub_instance(
|
||||
id=1,
|
||||
image_ref="5",
|
||||
uuid="deadbeef-feed-edee-beef-d0ea7beefedd",
|
||||
uuid=FAKE_UUID,
|
||||
display_name="test_server",
|
||||
include_fake_metadata=False,
|
||||
availability_zone='nova',
|
||||
@ -6339,6 +6396,12 @@ class ServersViewBuilderTest(test.TestCase):
|
||||
'ips': [dict(ip=ip) for ip in privates]})]
|
||||
|
||||
fakes.stub_out_nw_api_get_instance_nw_info(self, nw_info)
|
||||
self.stub_out('nova.db.api.'
|
||||
'block_device_mapping_get_all_by_instance_uuids',
|
||||
fake_bdms_get_all_by_instance_uuids)
|
||||
self.stub_out('nova.objects.InstanceMappingList.'
|
||||
'_get_by_instance_uuids_from_db',
|
||||
fake_get_inst_mappings_by_instance_uuids_from_db)
|
||||
|
||||
self.uuid = db_inst['uuid']
|
||||
self.view_builder = views.servers.ViewBuilder()
|
||||
@ -6393,6 +6456,21 @@ class ServersViewBuilderTest(test.TestCase):
|
||||
False)
|
||||
self.assertEqual(result, expected)
|
||||
|
||||
@mock.patch('nova.context.scatter_gather_cells')
|
||||
def test_get_volumes_attached_with_faily_cells(self, mock_sg):
|
||||
bdms = fake_bdms_get_all_by_instance_uuids()
|
||||
# just faking a nova list scenario
|
||||
mock_sg.return_value = {
|
||||
uuids.cell1: bdms[0],
|
||||
uuids.cell2: context.raised_exception_sentinel
|
||||
}
|
||||
ctxt = context.RequestContext('fake', 'fake')
|
||||
result = self.view_builder._get_instance_bdms_in_multiple_cells(
|
||||
ctxt, [self.instance.uuid])
|
||||
# will get the result from cell1
|
||||
self.assertEqual(result, bdms[0])
|
||||
mock_sg.assert_called_once()
|
||||
|
||||
def test_build_server(self):
|
||||
expected_server = {
|
||||
"server": {
|
||||
@ -6511,7 +6589,11 @@ class ServersViewBuilderTest(test.TestCase):
|
||||
{'name': 'fake-0-1'}],
|
||||
"OS-EXT-STS:task_state": None,
|
||||
"OS-EXT-STS:vm_state": vm_states.ACTIVE,
|
||||
"OS-EXT-STS:power_state": 1
|
||||
"OS-EXT-STS:power_state": 1,
|
||||
"os-extended-volumes:volumes_attached": [
|
||||
{'id': 'some_volume_1'},
|
||||
{'id': 'some_volume_2'},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -6603,7 +6685,11 @@ class ServersViewBuilderTest(test.TestCase):
|
||||
{'name': 'fake-0-1'}],
|
||||
"OS-EXT-STS:task_state": None,
|
||||
"OS-EXT-STS:vm_state": vm_states.ERROR,
|
||||
"OS-EXT-STS:power_state": 1
|
||||
"OS-EXT-STS:power_state": 1,
|
||||
"os-extended-volumes:volumes_attached": [
|
||||
{'id': 'some_volume_1'},
|
||||
{'id': 'some_volume_2'},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -6794,7 +6880,11 @@ class ServersViewBuilderTest(test.TestCase):
|
||||
{'name': 'fake-0-1'}],
|
||||
"OS-EXT-STS:task_state": None,
|
||||
"OS-EXT-STS:vm_state": vm_states.ACTIVE,
|
||||
"OS-EXT-STS:power_state": 1
|
||||
"OS-EXT-STS:power_state": 1,
|
||||
"os-extended-volumes:volumes_attached": [
|
||||
{'id': 'some_volume_1'},
|
||||
{'id': 'some_volume_2'},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -6883,7 +6973,11 @@ class ServersViewBuilderTest(test.TestCase):
|
||||
{'name': 'fake-0-1'}],
|
||||
"OS-EXT-STS:task_state": None,
|
||||
"OS-EXT-STS:vm_state": vm_states.ACTIVE,
|
||||
"OS-EXT-STS:power_state": 1
|
||||
"OS-EXT-STS:power_state": 1,
|
||||
"os-extended-volumes:volumes_attached": [
|
||||
{'id': 'some_volume_1'},
|
||||
{'id': 'some_volume_2'},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user