summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2015-02-09 12:06:13 +0000
committerGerrit Code Review <review@openstack.org>2015-02-09 12:06:13 +0000
commita47351cc834c81cc3b8668da3f86ec6739b34b9a (patch)
treed2ff23f96d4555eaab14ee5c6aaba04c3edb85b3
parentf6d875ae727a58ee9f475b170ca7e61662bc5ae1 (diff)
parent71b8aa127200b104c872be2695e809510963c0b9 (diff)
downloadpython-heatclient-0.3.0.tar.gz
Merge "Adds CLI heat service-list"0.3.0
-rw-r--r--heatclient/tests/test_service.py59
-rw-r--r--heatclient/tests/test_shell.py84
-rw-r--r--heatclient/v1/client.py2
-rw-r--r--heatclient/v1/services.py32
-rw-r--r--heatclient/v1/shell.py8
5 files changed, 185 insertions, 0 deletions
diff --git a/heatclient/tests/test_service.py b/heatclient/tests/test_service.py
new file mode 100644
index 0000000..0646ff3
--- /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 287a0a1..8672939 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 b5e3485..8299d9e 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 0000000..9e77c73
--- /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 "<Service %s>" % 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 5d98256..6d7729a 100644
--- a/heatclient/v1/shell.py
+++ b/heatclient/v1/shell.py
@@ -1170,3 +1170,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)