diff --git a/heatclient/tests/test_service.py b/heatclient/tests/test_service.py new file mode 100644 index 00000000..0646ff3b --- /dev/null +++ b/heatclient/tests/test_service.py @@ -0,0 +1,59 @@ +# Copyright 2012 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. + +from heatclient import exc +import testtools + + +from heatclient.v1 import services + + +class ManageServiceTest(testtools.TestCase): + def setUp(self): + super(ManageServiceTest, self).setUp() + + def test_service_list(self): + class FakeResponse(object): + def json(self): + return {'services': []} + + class FakeClient(object): + def get(self, *args, **kwargs): + assert args[0] == ('/services') + return FakeResponse() + + manager = services.ServiceManager(FakeClient()) + self.assertEqual(manager.list(), []) + + def test_service_list_403(self): + class FakeClient403(object): + + def get(self, *args, **kwargs): + assert args[0] == ('/services') + raise exc.HTTPForbidden() + + manager = services.ServiceManager(FakeClient403()) + self.assertRaises(exc.HTTPForbidden, + manager.list) + + def test_service_list_503(self): + class FakeClient503(object): + def get(self, *args, **kwargs): + assert args[0] == ('/services') + raise exc.HTTPServiceUnavailable() + + manager = services.ServiceManager(FakeClient503()) + self.assertRaises(exc.HTTPServiceUnavailable, + manager.list) diff --git a/heatclient/tests/test_shell.py b/heatclient/tests/test_shell.py index 287a0a16..86729397 100644 --- a/heatclient/tests/test_shell.py +++ b/heatclient/tests/test_shell.py @@ -2958,3 +2958,87 @@ class MockShellTestStandaloneToken(MockShellTestUserPass): 'OS_PASSWORD': 'password' } self.set_fake_env(fake_env) + + +class ShellTestManageService(ShellBase): + + def setUp(self): + super(ShellTestManageService, self).setUp() + self.set_fake_env(FAKE_ENV_KEYSTONE_V2) + + def _set_fake_env(self): + '''Patch os.environ to avoid required auth info.''' + self.set_fake_env(FAKE_ENV_KEYSTONE_V2) + + def _test_error_case(self, code, message): + self.register_keystone_auth_fixture() + + resp_dict = { + 'explanation': '', + 'code': code, + 'error': { + 'message': message, + 'type': '', + 'traceback': '', + }, + 'title': 'test title' + } + resp_string = jsonutils.dumps(resp_dict) + resp = fakes.FakeHTTPResponse( + code, + 'test reason', + {'content-type': 'application/json'}, + resp_string) + (http.HTTPClient.json_request('GET', '/services'). + AndRaise(exc.from_response(resp))) + + exc.verbose = 1 + + self.m.ReplayAll() + e = self.assertRaises(exc.HTTPException, + self.shell, "service-list") + self.m.VerifyAll() + self.assertIn(message, str(e)) + + def test_service_list(self): + self.register_keystone_auth_fixture() + resp_dict = { + 'services': [ + { + "status": "up", + "binary": "heat-engine", + "engine_id": "9d9242c3-4b9e-45e1-9e74-7615fbf20e5d", + "hostname": "mrkanag", + "updated_at": "2015-02-03T05:57:59.000000", + "topic": "engine", + "host": "engine-1" + } + ] + } + resp_string = jsonutils.dumps(resp_dict) + headers = {} + http_resp = fakes.FakeHTTPResponse(200, 'OK', headers, resp_string) + response = (http_resp, resp_dict) + http.HTTPClient.json_request('GET', '/services').AndReturn(response) + + self.m.ReplayAll() + services_text = self.shell('service-list') + self.m.VerifyAll() + + required = [ + 'hostname', 'binary', 'engine_id', 'host', + 'topic', 'updated_at', 'status' + ] + for r in required: + self.assertRegexpMatches(services_text, r) + + def test_service_list_503(self): + self._test_error_case( + message='All heat engines are down', + code=503) + + def test_service_list_403(self): + self._test_error_case( + message=('You are not authorized to ' + 'complete this action'), + code=403) diff --git a/heatclient/v1/client.py b/heatclient/v1/client.py index b5e34858..8299d9ed 100644 --- a/heatclient/v1/client.py +++ b/heatclient/v1/client.py @@ -19,6 +19,7 @@ from heatclient.v1 import build_info from heatclient.v1 import events from heatclient.v1 import resource_types from heatclient.v1 import resources +from heatclient.v1 import services from heatclient.v1 import software_configs from heatclient.v1 import software_deployments from heatclient.v1 import stacks @@ -49,3 +50,4 @@ class Client(object): self.http_client) self.software_configs = software_configs.SoftwareConfigManager( self.http_client) + self.services = services.ServiceManager(self.http_client) diff --git a/heatclient/v1/services.py b/heatclient/v1/services.py new file mode 100644 index 00000000..9e77c733 --- /dev/null +++ b/heatclient/v1/services.py @@ -0,0 +1,32 @@ +# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. +# +# 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 heatclient.openstack.common.apiclient import base + + +class Service(base.Resource): + def __repr__(self): + return "" % self._info + + +class ServiceManager(base.BaseManager): + resource_class = Service + + def list(self): + """Get a list of services. + :rtype: list of :class:`Service` + """ + url = '/services' + return self._list(url, "services") diff --git a/heatclient/v1/shell.py b/heatclient/v1/shell.py index 444642c7..c71f214e 100644 --- a/heatclient/v1/shell.py +++ b/heatclient/v1/shell.py @@ -1169,3 +1169,11 @@ def do_snapshot_list(hc, args): 'creation_time': lambda x: x['creation_time'], } utils.print_list(snapshots["snapshots"], fields, formatters=formatters) + + +def do_service_list(hc, args=None): + '''List the Heat engines.''' + fields = ['hostname', 'binary', 'engine_id', 'host', + 'topic', 'updated_at', 'status'] + services = hc.services.list() + utils.print_list(services, fields, sortby_index=1)