From 7cee40a47e3bb838fb5d22174e2774347fdb10d2 Mon Sep 17 00:00:00 2001 From: ivan-zhu Date: Thu, 1 Nov 2012 23:04:43 +0800 Subject: Add REST API support for list/enable/disable nova services Implements one workitem of blueprint apis-for-nova-manage This adds an extension that provides REST API for list/enable/ disable nova service. The interface ia accessed via GET /v2/{tenant_id}/os-services PUT /v2/{tenant_id}/os-services/enable PUT /v2/{tenant_id}/os-services/disable And the command:nova host-describe have implemented the functionality of nova-manage service describe_resource. So we needn't add a REST API for it. DocImpact Change-Id: I030a7e00b878d7931456e7e323db37b7c47fce48 --- .../api/openstack/compute/contrib/test_services.py | 198 +++++++++++++++++++++ .../tests/api/openstack/compute/test_extensions.py | 1 + .../all_extensions/extensions-get-resp.json.tpl | 8 + .../all_extensions/extensions-get-resp.xml.tpl | 3 + nova/tests/policy.json | 1 + 5 files changed, 211 insertions(+) create mode 100644 nova/tests/api/openstack/compute/contrib/test_services.py (limited to 'nova/tests') diff --git a/nova/tests/api/openstack/compute/contrib/test_services.py b/nova/tests/api/openstack/compute/contrib/test_services.py new file mode 100644 index 000000000..24f169d98 --- /dev/null +++ b/nova/tests/api/openstack/compute/contrib/test_services.py @@ -0,0 +1,198 @@ +# Copyright 2012 IBM +# 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 datetime import datetime +from nova.api.openstack.compute.contrib import services +from nova import context +from nova import db +from nova import exception +from nova.openstack.common import timeutils +from nova import test +from nova.tests.api.openstack import fakes + + +fake_services_list = [{'binary': 'nova-scheduler', + 'host': 'host1', + 'availability_zone': 'nova', + 'id': 1, + 'disabled': True, + 'updated_at': datetime(2012, 10, 29, 13, 42, 2), + 'created_at': datetime(2012, 9, 18, 2, 46, 27)}, + {'binary': 'nova-compute', + 'host': 'host1', + 'availability_zone': 'nova', + 'id': 2, + 'disabled': True, + 'updated_at': datetime(2012, 10, 29, 13, 42, 5), + 'created_at': datetime(2012, 9, 18, 2, 46, 27)}, + {'binary': 'nova-scheduler', + 'host': 'host2', + 'availability_zone': 'nova', + 'id': 3, + 'disabled': False, + 'updated_at': datetime(2012, 9, 19, 6, 55, 34), + 'created_at': datetime(2012, 9, 18, 2, 46, 28)}, + {'binary': 'nova-compute', + 'host': 'host2', + 'availability_zone': 'nova', + 'id': 4, + 'disabled': True, + 'updated_at': datetime(2012, 9, 18, 8, 3, 38), + 'created_at': datetime(2012, 9, 18, 2, 46, 28)}, + ] + + +class FakeRequest(object): + environ = {"nova.context": context.get_admin_context()} + GET = {} + + +class FakeRequestWithSevice(object): + environ = {"nova.context": context.get_admin_context()} + GET = {"service": "nova-compute"} + + +class FakeRequestWithHost(object): + environ = {"nova.context": context.get_admin_context()} + GET = {"host": "host1"} + + +class FakeRequestWithHostService(object): + environ = {"nova.context": context.get_admin_context()} + GET = {"host": "host1", "service": "nova-compute"} + + +def fake_servcie_get_all(context): + return fake_services_list + + +def fake_service_get_by_host_binary(context, host, binary): + for service in fake_services_list: + if service['host'] == host and service['binary'] == binary: + return service + return None + + +def fake_service_get_by_id(value): + for service in fake_services_list: + if service['id'] == value: + return service + return None + + +def fake_service_update(context, service_id, values): + service = fake_service_get_by_id(service_id) + if service is None: + raise exception.ServiceNotFound(service_id=service_id) + else: + {'host': 'host1', 'service': 'nova-compute', + 'disabled': values['disabled']} + + +def fake_utcnow(): + return datetime(2012, 10, 29, 13, 42, 11) + + +class ServicesTest(test.TestCase): + + def setUp(self): + super(ServicesTest, self).setUp() + + self.stubs.Set(db, "service_get_all", fake_servcie_get_all) + self.stubs.Set(timeutils, "utcnow", fake_utcnow) + self.stubs.Set(db, "service_get_by_args", + fake_service_get_by_host_binary) + self.stubs.Set(db, "service_update", fake_service_update) + + self.context = context.get_admin_context() + self.controller = services.ServiceController() + + def tearDown(self): + super(ServicesTest, self).tearDown() + + def test_services_list(self): + req = FakeRequest() + res_dict = self.controller.index(req) + + response = {'services': [{'binary': 'nova-scheduler', + 'host': 'host1', 'zone': 'nova', + 'status': 'disabled', 'state': 'up', + 'updated_at': datetime(2012, 10, 29, 13, 42, 2)}, + {'binary': 'nova-compute', + 'host': 'host1', 'zone': 'nova', + 'status': 'disabled', 'state': 'up', + 'updated_at': datetime(2012, 10, 29, 13, 42, 5)}, + {'binary': 'nova-scheduler', 'host': 'host2', + 'zone': 'nova', + 'status': 'enabled', 'state': 'down', + 'updated_at': datetime(2012, 9, 19, 6, 55, 34)}, + {'binary': 'nova-compute', 'host': 'host2', + 'zone': 'nova', + 'status': 'disabled', 'state': 'down', + 'updated_at': datetime(2012, 9, 18, 8, 3, 38)}]} + self.assertEqual(res_dict, response) + + def test_services_list_with_host(self): + req = FakeRequestWithHost() + res_dict = self.controller.index(req) + + response = {'services': [{'binary': 'nova-scheduler', 'host': 'host1', + 'zone': 'nova', + 'status': 'disabled', 'state': 'up', + 'updated_at': datetime(2012, 10, 29, 13, 42, 2)}, + {'binary': 'nova-compute', 'host': 'host1', + 'zone': 'nova', + 'status': 'disabled', 'state': 'up', + 'updated_at': datetime(2012, 10, 29, 13, 42, 5)}]} + self.assertEqual(res_dict, response) + + def test_services_list_with_service(self): + req = FakeRequestWithSevice() + res_dict = self.controller.index(req) + + response = {'services': [{'binary': 'nova-compute', 'host': 'host1', + 'zone': 'nova', + 'status': 'disabled', 'state': 'up', + 'updated_at': datetime(2012, 10, 29, 13, 42, 5)}, + {'binary': 'nova-compute', 'host': 'host2', + 'zone': 'nova', + 'status': 'disabled', 'state': 'down', + 'updated_at': datetime(2012, 9, 18, 8, 3, 38)}]} + self.assertEqual(res_dict, response) + + def test_services_list_with_host_service(self): + req = FakeRequestWithHostService() + res_dict = self.controller.index(req) + + response = {'services': [{'binary': 'nova-compute', 'host': 'host1', + 'zone': 'nova', + 'status': 'disabled', 'state': 'up', + 'updated_at': datetime(2012, 10, 29, 13, 42, 5)}]} + self.assertEqual(res_dict, response) + + def test_services_enable(self): + body = {'host': 'host1', 'service': 'nova-compute'} + req = fakes.HTTPRequest.blank('/v2/fake/os-services/enable') + res_dict = self.controller.update(req, "enable", body) + + self.assertEqual(res_dict['disabled'], False) + + def test_services_disable(self): + req = fakes.HTTPRequest.blank('/v2/fake/os-services/disable') + body = {'host': 'host1', 'service': 'nova-compute'} + res_dict = self.controller.update(req, "disable", body) + + self.assertEqual(res_dict['disabled'], True) diff --git a/nova/tests/api/openstack/compute/test_extensions.py b/nova/tests/api/openstack/compute/test_extensions.py index ef2f4eec4..41c28e540 100644 --- a/nova/tests/api/openstack/compute/test_extensions.py +++ b/nova/tests/api/openstack/compute/test_extensions.py @@ -189,6 +189,7 @@ class ExtensionControllerTest(ExtensionTestCase): "SecurityGroups", "ServerDiagnostics", "ServerStartStop", + "Services", "SimpleTenantUsage", "UsedLimits", "UserData", diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl index f566a5020..0086c213f 100644 --- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl +++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.json.tpl @@ -208,6 +208,14 @@ "namespace": "http://docs.openstack.org/compute/ext/hosts/api/v1.1", "updated": "%(timestamp)s" }, + { + "alias": "os-services", + "description": "%(text)s", + "links": [], + "name": "Services", + "namespace": "http://docs.openstack.org/compute/ext/services/api/v2", + "updated": "%(timestamp)s" + }, { "alias": "os-hypervisors", "description": "%(text)s", diff --git a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl index 20e650d7c..c2c856d23 100644 --- a/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl +++ b/nova/tests/integrated/api_samples/all_extensions/extensions-get-resp.xml.tpl @@ -78,6 +78,9 @@ %(text)s + + %(text)s + %(text)s diff --git a/nova/tests/policy.json b/nova/tests/policy.json index efe2724ad..bf94d4e49 100644 --- a/nova/tests/policy.json +++ b/nova/tests/policy.json @@ -117,6 +117,7 @@ "compute_extension:rescue": "", "compute_extension:security_groups": "", "compute_extension:server_diagnostics": "", + "compute_extension:services": "", "compute_extension:simple_tenant_usage:show": "", "compute_extension:simple_tenant_usage:list": "", "compute_extension:users": "", -- cgit