Merge server usage extension response into server view builder

As nova extensions has been deprecated already and 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 merge the server usage extension resposne into server
view builder.

Partially implements: blueprint api-extensions-merge-stein

Change-Id: Id14b60e5ad48a20c8d441f7c686a6cc0c30f7f6a
This commit is contained in:
ghanshyam 2018-08-15 12:58:19 +00:00 committed by Matt Riedemann
parent 5dd8622f92
commit 2318118dba
6 changed files with 129 additions and 200 deletions

View File

@ -78,7 +78,6 @@ from nova.api.openstack.compute import server_metadata
from nova.api.openstack.compute import server_migrations
from nova.api.openstack.compute import server_password
from nova.api.openstack.compute import server_tags
from nova.api.openstack.compute import server_usage
from nova.api.openstack.compute import servers
from nova.api.openstack.compute import services
from nova.api.openstack.compute import shelve
@ -270,7 +269,6 @@ server_controller = functools.partial(_create_controller,
extended_volumes.ExtendedVolumesController,
hide_server_addresses.Controller,
security_groups.SecurityGroupsOutputController,
server_usage.ServerUsageController,
],
[
admin_actions.AdminActionsController,

View File

@ -1,48 +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.
from nova.api.openstack import wsgi
resp_topic = "OS-SRV-USG"
class ServerUsageController(wsgi.Controller):
def _extend_server(self, server, instance):
for k in ['launched_at', 'terminated_at']:
key = "%s:%s" % (resp_topic, k)
# NOTE(danms): Historically, this timestamp has been generated
# merely by grabbing str(datetime) of a TZ-naive object. The
# only way we can keep that with instance objects is to strip
# the tzinfo from the stamp and str() it.
server[key] = (instance[k].replace(tzinfo=None)
if instance[k] else None)
@wsgi.extends
def show(self, req, resp_obj, id):
server = resp_obj.obj['server']
db_instance = req.get_db_instance(server['id'])
# server['id'] is guaranteed to be in the cache due to
# the core API adding it in its 'show' method.
self._extend_server(server, db_instance)
@wsgi.extends
def detail(self, req, resp_obj):
servers = list(resp_obj.obj['servers'])
for server in servers:
db_instance = req.get_db_instance(server['id'])
# server['id'] is guaranteed to be in the cache due to
# the core API adding it in its 'detail' method.
self._extend_server(server, db_instance)

View File

@ -722,7 +722,8 @@ class ServersController(wsgi.Controller):
show_config_drive=False,
show_extended_attr=False,
show_host_status=False,
show_keypair=False)
show_keypair=False,
show_srv_usg=False)
except exception.InstanceNotFound:
msg = _("Instance could not be found")
raise exc.HTTPNotFound(explanation=msg)
@ -995,7 +996,8 @@ class ServersController(wsgi.Controller):
show_config_drive=False,
show_extended_attr=False,
show_host_status=False,
show_keypair=show_keypair)
show_keypair=show_keypair,
show_srv_usg=False)
# Add on the admin_password attribute since the view doesn't do it
# unless instance passwords are disabled

View File

@ -118,7 +118,7 @@ class ViewBuilder(common.ViewBuilder):
def show(self, request, instance, extend_address=True,
show_extra_specs=None, show_AZ=True, show_config_drive=True,
show_extended_attr=None, show_host_status=None,
show_keypair=True):
show_keypair=True, show_srv_usg=True):
"""Detailed view of a single instance."""
ip_v4 = instance.get('access_ip_v4')
ip_v6 = instance.get('access_ip_v6')
@ -182,6 +182,16 @@ class ViewBuilder(common.ViewBuilder):
if show_keypair:
server["server"]["key_name"] = instance["key_name"]
if show_srv_usg:
for k in ['launched_at', 'terminated_at']:
key = "OS-SRV-USG:" + k
# NOTE(danms): Historically, this timestamp has been generated
# merely by grabbing str(datetime) of a TZ-naive object. The
# only way we can keep that with instance objects is to strip
# the tzinfo from the stamp and str() it.
server["server"][key] = (instance[k].replace(tzinfo=None)
if instance[k] else None)
if show_extended_attr is None:
show_extended_attr = context.can(
esa_policies.BASE_POLICY_NAME, fatal=False)

View File

@ -1,128 +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 datetime
from oslo_serialization import jsonutils
from oslo_utils import fixture as utils_fixture
from oslo_utils import timeutils
from nova import exception
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_instance
UUID1 = '00000000-0000-0000-0000-000000000001'
UUID2 = '00000000-0000-0000-0000-000000000002'
UUID3 = '00000000-0000-0000-0000-000000000003'
DATE1 = datetime.datetime(year=2013, month=4, day=5, hour=12)
DATE2 = datetime.datetime(year=2013, month=4, day=5, hour=13)
DATE3 = datetime.datetime(year=2013, month=4, day=5, hour=14)
def fake_compute_get(*args, **kwargs):
inst = fakes.stub_instance(1, uuid=UUID3, launched_at=DATE1,
terminated_at=DATE2)
return fake_instance.fake_instance_obj(args[1], **inst)
def fake_compute_get_all(*args, **kwargs):
db_list = [
fakes.stub_instance(2, uuid=UUID1, launched_at=DATE2,
terminated_at=DATE3),
fakes.stub_instance(3, uuid=UUID2, launched_at=DATE1,
terminated_at=DATE3),
]
fields = instance_obj.INSTANCE_DEFAULT_FIELDS
return instance_obj._make_instance_list(args[1],
objects.InstanceList(),
db_list, fields)
class ServerUsageTestV21(test.TestCase):
content_type = 'application/json'
prefix = 'OS-SRV-USG:'
_prefix = "/v2/fake"
def setUp(self):
super(ServerUsageTestV21, 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)
return_server = fakes.fake_instance_get()
self.stub_out('nova.db.api.instance_get_by_uuid', return_server)
def _make_request(self, url):
req = fakes.HTTPRequest.blank(url)
req.accept = self.content_type
res = req.get_response(self._get_app())
return res
def _get_app(self):
return fakes.wsgi_app_v21()
def _get_server(self, body):
return jsonutils.loads(body).get('server')
def _get_servers(self, body):
return jsonutils.loads(body).get('servers')
def assertServerUsage(self, server, launched_at, terminated_at):
resp_launched_at = timeutils.parse_isotime(
server.get('%slaunched_at' % self.prefix))
self.assertEqual(timeutils.normalize_time(resp_launched_at),
launched_at)
resp_terminated_at = timeutils.parse_isotime(
server.get('%sterminated_at' % self.prefix))
self.assertEqual(timeutils.normalize_time(resp_terminated_at),
terminated_at)
def test_show(self):
url = self._prefix + ('/servers/%s' % UUID3)
res = self._make_request(url)
self.assertEqual(res.status_int, 200)
self.useFixture(utils_fixture.TimeFixture())
self.assertServerUsage(self._get_server(res.body),
launched_at=DATE1,
terminated_at=DATE2)
def test_detail(self):
url = self._prefix + '/servers/detail'
res = self._make_request(url)
self.assertEqual(res.status_int, 200)
servers = self._get_servers(res.body)
self.assertServerUsage(servers[0],
launched_at=DATE2,
terminated_at=DATE3)
self.assertServerUsage(servers[1],
launched_at=DATE1,
terminated_at=DATE3)
def test_no_instance_passthrough_404(self):
def fake_compute_get(*args, **kwargs):
raise exception.InstanceNotFound(instance_id='fake')
self.stub_out('nova.compute.api.API.get', fake_compute_get)
url = self._prefix + '/servers/70f6db34-de8d-4fbd-aafb-4065bdfa6115'
res = self._make_request(url)
self.assertEqual(res.status_int, 404)

View File

@ -25,6 +25,7 @@ from oslo_policy import policy as oslo_policy
from oslo_serialization import base64
from oslo_serialization import jsonutils
from oslo_utils import encodeutils
from oslo_utils import fixture as utils_fixture
from oslo_utils import timeutils
from oslo_utils import uuidutils
import six
@ -162,7 +163,9 @@ class ControllerTest(test.TestCase):
self.flags(use_ipv6=False)
fakes.stub_out_key_pair_funcs(self)
fake.stub_out_image_service(self)
return_server = fakes.fake_compute_get(id=2, availability_zone='nova')
return_server = fakes.fake_compute_get(id=2, availability_zone='nova',
launched_at=None,
terminated_at=None)
return_servers = fakes.fake_compute_get_all()
# Server sort keys extension is enabled in v21 so sort data is passed
# to the instance API and the sorted DB API is invoked
@ -385,7 +388,9 @@ class ServersControllerTest(ControllerTest):
"OS-EXT-SRV-ATTR:host": None,
"OS-EXT-SRV-ATTR:hypervisor_hostname": None,
"OS-EXT-SRV-ATTR:instance_name": "instance-00000002",
"key_name": ''
"key_name": '',
"OS-SRV-USG:launched_at": None,
"OS-SRV-USG:terminated_at": None
}
}
@ -1345,6 +1350,62 @@ class ServersControllerTest(ControllerTest):
self.assertEqual(1, len(servers))
self.assertEqual(uuids.fake, servers[0]['id'])
def _assertServerUsage(self, server, launched_at, terminated_at):
resp_launched_at = timeutils.parse_isotime(
server.get('OS-SRV-USG:launched_at'))
self.assertEqual(timeutils.normalize_time(resp_launched_at),
launched_at)
resp_terminated_at = timeutils.parse_isotime(
server.get('OS-SRV-USG:terminated_at'))
self.assertEqual(timeutils.normalize_time(resp_terminated_at),
terminated_at)
def test_show_server_usage(self):
DATE1 = datetime.datetime(year=2013, month=4, day=5, hour=12)
DATE2 = datetime.datetime(year=2013, month=4, day=5, hour=13)
self.mock_get.side_effect = fakes.fake_compute_get(
id=1, uuid=FAKE_UUID, launched_at=DATE1, terminated_at=DATE2)
fakes.stub_out_secgroup_api(self)
req = self.req('/fake/servers/%s' % FAKE_UUID)
req.accept = 'application/json'
req.method = 'GET'
res = req.get_response(compute.APIRouterV21())
self.assertEqual(res.status_int, 200)
self.useFixture(utils_fixture.TimeFixture())
self._assertServerUsage(jsonutils.loads(res.body).get('server'),
launched_at=DATE1,
terminated_at=DATE2)
def test_detail_server_usage(self):
DATE1 = datetime.datetime(year=2013, month=4, day=5, hour=12)
DATE2 = datetime.datetime(year=2013, month=4, day=5, hour=13)
DATE3 = datetime.datetime(year=2013, month=4, day=5, hour=14)
def fake_compute_get_all(*args, **kwargs):
db_list = [
fakes.stub_instance_obj(context, id=2, uuid=FAKE_UUID,
launched_at=DATE2,
terminated_at=DATE3),
fakes.stub_instance_obj(context, id=3, uuid=FAKE_UUID,
launched_at=DATE1,
terminated_at=DATE3),
]
return objects.InstanceList(objects=db_list)
self.mock_get_all.side_effect = fake_compute_get_all
fakes.stub_out_secgroup_api(self)
req = self.req('/fake/servers/detail')
req.accept = 'application/json'
servers = req.get_response(compute.APIRouterV21())
self.assertEqual(servers.status_int, 200)
self._assertServerUsage(jsonutils.loads(
servers.body).get('servers')[0],
launched_at=DATE2,
terminated_at=DATE3)
self._assertServerUsage(jsonutils.loads(
servers.body).get('servers')[1],
launched_at=DATE1,
terminated_at=DATE3)
def test_get_all_server_details(self):
expected_flavor = {
"id": "2",
@ -1445,7 +1506,9 @@ class ServersControllerTestV23(ServersControllerTest):
root_device_name="/dev/vda",
user_data="userdata",
metadata={"seq": "2"},
availability_zone='nova')
availability_zone='nova',
launched_at=None,
terminated_at=None)
def _get_server_data_dict(self, uuid, image_bookmark, flavor_bookmark,
status="ACTIVE", progress=100):
@ -1494,7 +1557,9 @@ class ServersControllerTestV23(ServersControllerTest):
root_device_name="/dev/vda",
user_data="userdata",
metadata={"seq": "2"},
availability_zone='nova')
availability_zone='nova',
launched_at=None,
terminated_at=None)
obj_list.append(server)
return objects.InstanceList(objects=obj_list)
@ -1527,7 +1592,9 @@ class ServersControllerTestV29(ServersControllerTest):
root_device_name="/dev/vda",
user_data="userdata",
metadata={"seq": "2"},
availability_zone='nova')
availability_zone='nova',
launched_at=None,
terminated_at=None)
def _get_server_data_dict(self, uuid, image_bookmark, flavor_bookmark,
status="ACTIVE", progress=100):
@ -1561,7 +1628,9 @@ class ServersControllerTestV29(ServersControllerTest):
root_device_name="/dev/vda",
user_data="userdata",
metadata={"seq": "2"},
availability_zone='nova')
availability_zone='nova',
launched_at=None,
terminated_at=None)
req = self.req('/fake/servers/%s' % FAKE_UUID)
res_dict = self.controller.show(req, FAKE_UUID)
@ -1599,7 +1668,9 @@ class ServersControllerTestV29(ServersControllerTest):
root_device_name="/dev/vda",
user_data="userdata",
metadata={"seq": "2"},
availability_zone='nova')
availability_zone='nova',
launched_at=None,
terminated_at=None)
req = self.req('/fake/servers/detail')
servers_list = self.controller.detail(req)
@ -1655,7 +1726,9 @@ class ServersControllerTestV216(ServersControllerTest):
root_device_name="/dev/vda",
user_data="userdata",
metadata={"seq": "2"},
availability_zone='nova')
availability_zone='nova',
launched_at=None,
terminated_at=None)
self.useFixture(fixtures.MockPatchObject(
compute_api.API, 'get_instance_host_status',
return_value='UP')).mock
@ -1708,7 +1781,9 @@ class ServersControllerTestV216(ServersControllerTest):
root_device_name="/dev/vda",
user_data="userdata",
metadata={"seq": "2"},
availability_zone='nova')
availability_zone='nova',
launched_at=None,
terminated_at=None)
obj_list.append(server)
return objects.InstanceList(objects=obj_list)
@ -1741,7 +1816,9 @@ class ServersControllerTestV219(ServersControllerTest):
root_device_name="/dev/vda",
user_data="userdata",
metadata={"seq": "2"},
availability_zone='nova')
availability_zone='nova',
launched_at=None,
terminated_at=None)
self.useFixture(fixtures.MockPatchObject(
compute_api.API, 'get_instance_host_status',
return_value='UP')).mock
@ -1781,7 +1858,9 @@ class ServersControllerTestV219(ServersControllerTest):
root_device_name="/dev/vda",
user_data="userdata",
metadata={"seq": "2"},
availability_zone='nova')
availability_zone='nova',
launched_at=None,
terminated_at=None)
req = self.req('/fake/servers/%s' % FAKE_UUID)
res_dict = self.controller.show(req, FAKE_UUID)
@ -1800,7 +1879,9 @@ class ServersControllerTestV219(ServersControllerTest):
self.mock_get_all.side_effect = None
self.mock_get_all.return_value = (
fake_instance_get_all_with_description(context,
[s1_desc, s2_desc]))
[s1_desc, s2_desc],
launched_at=None,
terminated_at=None))
req = self.req('/fake/servers/detail')
servers_list = self.controller.detail(req)
# Check that each returned server has the same 'description' value
@ -2335,7 +2416,9 @@ class ServersControllerRebuildInstanceTest(ControllerTest):
'OS-EXT-SRV-ATTR:ramdisk_id',
'OS-EXT-SRV-ATTR:reservation_id',
'OS-EXT-SRV-ATTR:root_device_name',
'OS-EXT-SRV-ATTR:user_data', 'host_status']
'OS-EXT-SRV-ATTR:user_data', 'host_status',
'OS-SRV-USG:launched_at',
'OS-SRV-USG:terminated_at']
if not self.expected_key_name:
get_only_fields.append('key_name')
for field in get_only_fields:
@ -2946,7 +3029,8 @@ class ServersControllerUpdateTest(ControllerTest):
'OS-EXT-SRV-ATTR:reservation_id',
'OS-EXT-SRV-ATTR:root_device_name',
'OS-EXT-SRV-ATTR:user_data', 'host_status',
'key_name']
'key_name', 'OS-SRV-USG:launched_at',
'OS-SRV-USG:terminated_at']
for field in get_only_fields:
self.assertNotIn(field, res_dict['server'])
@ -6083,7 +6167,9 @@ class ServersViewBuilderTest(test.TestCase):
display_name="test_server",
include_fake_metadata=False,
availability_zone='nova',
nw_cache=nw_cache_info)
nw_cache=nw_cache_info,
launched_at=None,
terminated_at=None)
privates = ['172.19.0.1']
publics = ['192.168.0.3']
@ -6262,7 +6348,9 @@ class ServersViewBuilderTest(test.TestCase):
"OS-EXT-SRV-ATTR:host": None,
"OS-EXT-SRV-ATTR:hypervisor_hostname": None,
"OS-EXT-SRV-ATTR:instance_name": "instance-00000001",
"key_name": ''
"key_name": '',
"OS-SRV-USG:launched_at": None,
"OS-SRV-USG:terminated_at": None
}
}
@ -6347,7 +6435,10 @@ class ServersViewBuilderTest(test.TestCase):
"OS-EXT-SRV-ATTR:host": None,
"OS-EXT-SRV-ATTR:hypervisor_hostname": None,
"OS-EXT-SRV-ATTR:instance_name": "instance-00000001",
"key_name": ''
"key_name": '',
"OS-SRV-USG:launched_at": None,
"OS-SRV-USG:terminated_at": None
}
}
@ -6531,7 +6622,9 @@ class ServersViewBuilderTest(test.TestCase):
"OS-EXT-SRV-ATTR:host": None,
"OS-EXT-SRV-ATTR:hypervisor_hostname": None,
"OS-EXT-SRV-ATTR:instance_name": "instance-00000001",
"key_name": ''
"key_name": '',
"OS-SRV-USG:launched_at": None,
"OS-SRV-USG:terminated_at": None
}
}
@ -6613,7 +6706,9 @@ class ServersViewBuilderTest(test.TestCase):
"OS-EXT-SRV-ATTR:host": None,
"OS-EXT-SRV-ATTR:hypervisor_hostname": None,
"OS-EXT-SRV-ATTR:instance_name": "instance-00000001",
"key_name": ''
"key_name": '',
"OS-SRV-USG:launched_at": None,
"OS-SRV-USG:terminated_at": None
}
}