Support /ping and /health for v2

Now Zaqar supports /ping and /health API, but they're missing
in zaqar client. This patch will fix it.

Change-Id: I34b454c486a7b4c693a540890eee48f162a07605
This commit is contained in:
Fei Long Wang 2016-03-10 09:18:30 +13:00
parent 3152321c7a
commit 15ef3386c0
9 changed files with 203 additions and 16 deletions

View File

@ -94,6 +94,8 @@ openstack.messaging.v2 =
subscription_show = zaqarclient.queues.v2.cli:ShowSubscription
subscription_list = zaqarclient.queues.v2.cli:ListSubscriptions
queue_signed_url = zaqarclient.queues.v2.cli:CreateSignedUrl
messaging_ping = zaqarclient.queues.v2.cli:Ping
messaging_health = zaqarclient.queues.v2.cli:Health
openstack.cli.extension =
messaging = zaqarclient.queues.cli

View File

@ -0,0 +1,27 @@
# Copyright (c) 2016 Catalyst IT Ltd.
#
# 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 zaqarclient.tests.queues import health
from zaqarclient.transport import http
class QueuesV2HealthHttpFunctionalTest(
health.QueuesV2HealthFunctionalTest):
is_functional = True
transport_cls = http.HttpTransport
url = 'http://127.0.0.1:8888'
version = 2

View File

@ -18,15 +18,18 @@ import mock
import ddt
from zaqarclient.queues import client
from zaqarclient.queues.v1 import core
from zaqarclient.tests import base
from zaqarclient.tests.queues import base
from zaqarclient.transport import errors
from zaqarclient.transport import http
VERSIONS = [2]
@ddt.ddt
class TestClient(base.TestBase):
class TestClient(base.QueuesTestBase):
transport_cls = http.HttpTransport
url = 'http://127.0.0.1:8888/v2'
version = VERSIONS[0]
@ddt.data(*VERSIONS)
def test_transport(self, version):
@ -35,21 +38,18 @@ class TestClient(base.TestBase):
self.assertIsNotNone(cli.transport())
@ddt.data(*VERSIONS)
def test_health_ok(self, version):
cli = client.Client('http://example.com',
version, {"auth_opts": {'backend': 'noauth'}})
with mock.patch.object(core, 'health', autospec=True) as core_health:
core_health.return_value = None
self.assertTrue(cli.health())
def test_ping_ok(self, version):
with mock.patch.object(self.transport, 'send',
autospec=True) as send_method:
send_method.return_value = None
self.assertTrue(self.client.ping())
@ddt.data(*VERSIONS)
def test_health_bad(self, version):
cli = client.Client('http://example.com',
version, {"auth_opts": {'backend': 'noauth'}})
def test_ping_bad(self, version):
def raise_error(*args, **kwargs):
raise errors.ServiceUnavailableError()
with mock.patch.object(core, 'health', autospec=True) as core_health:
core_health.side_effect = raise_error
self.assertFalse(cli.health())
with mock.patch.object(self.transport, 'send',
autospec=True) as send_method:
send_method.side_effect = raise_error
self.assertFalse(self.client.ping())

View File

@ -0,0 +1,24 @@
# Copyright (c) 2016 Catalyst IT Ltd.
#
# 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 zaqarclient.tests.queues import health
from zaqarclient.transport import http
class QueuesV2HealthHttpUnitTest(health.QueuesV2HealthUnitTest):
transport_cls = http.HttpTransport
url = 'http://127.0.0.1:8888/v2'
version = 2

View File

@ -74,4 +74,14 @@ V2.schema.update({
'detailed': {'type': 'boolean'}
}
},
'ping': {
'ref': 'ping',
'method': 'GET',
},
'health': {
'ref': 'health',
'method': 'GET',
},
})

View File

@ -393,3 +393,26 @@ class CreateSignedUrl(show.ShowOne):
data['signature'],
data['project']
)
class Ping(show.ShowOne):
"""Check if Zaqar server is alive or not"""
log = logging.getLogger(__name__ + ".Ping")
def take_action(self, parsed_args):
client = _get_client(self, parsed_args)
columns = ('Pingable', )
return columns, utils.get_dict_properties({'pingable': client.ping()},
columns)
class Health(command.Command):
"""Display detailed health status of Zaqar server"""
log = logging.getLogger(__name__ + ".Health")
def take_action(self, parsed_args):
client = _get_client(self, parsed_args)
health = client.health()
print(json.dumps(health, indent=4, sort_keys=True))

View File

@ -92,3 +92,14 @@ class Client(client.Client):
subscription_list,
'subscriptions',
subscription.create_object(self))
def ping(self):
"""Gets the health status of Zaqar server."""
req, trans = self._request_and_transport()
return core.ping(trans, req)
@decorators.version(min_version=1.1)
def health(self):
"""Gets the detailed health status of Zaqar server."""
req, trans = self._request_and_transport()
return core.health(trans, req)

View File

@ -220,3 +220,42 @@ def subscription_list(transport, request, queue_name, **kwargs):
return {'links': [], 'subscriptions': []}
return resp.deserialized_content
def ping(transport, request, callback=None):
"""Check the health of web head for load balancing
:param transport: Transport instance to use
:type transport: `transport.base.Transport`
:param request: Request instance ready to be sent.
:type request: `transport.request.Request`
:param callback: Optional callable to use as callback.
If specified, this request will be sent asynchronously.
(IGNORED UNTIL ASYNC SUPPORT IS COMPLETE)
:type callback: Callable object.
"""
request.operation = 'ping'
try:
transport.send(request)
return True
except Exception:
return False
def health(transport, request, callback=None):
"""Get detailed health status of Zaqar server
:param transport: Transport instance to use
:type transport: `transport.base.Transport`
:param request: Request instance ready to be sent.
:type request: `transport.request.Request`
:param callback: Optional callable to use as callback.
If specified, this request will be sent asynchronously.
(IGNORED UNTIL ASYNC SUPPORT IS COMPLETE)
:type callback: Callable object.
"""
request.operation = 'health'
resp = transport.send(request)
return resp.deserialized_content

View File

@ -0,0 +1,51 @@
# Copyright (c) 2016 Catalyst IT Ltd.
#
# 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 json
import mock
from zaqarclient.tests.queues import base
from zaqarclient.transport import response
class QueuesV2HealthUnitTest(base.QueuesTestBase):
def test_health(self):
expect_health = {u'catalog_reachable': True,
u'redis': {u'operation_status': {},
u'storage_reachable': True}
}
with mock.patch.object(self.transport, 'send',
autospec=True) as send_method:
health_content = json.dumps(expect_health)
health_resp = response.Response(None, health_content)
send_method.side_effect = iter([health_resp])
health = self.client.health()
self.assertEqual(expect_health, health)
class QueuesV2HealthFunctionalTest(base.QueuesTestBase):
def test_ping(self):
# NOTE(flwang): If test env is not pingable, then the test should fail
self.assertTrue(self.client.ping())
def test_health(self):
health = self.client.health()
# NOTE(flwang): If everything is ok, then zaqar server will return a
# JSON(dict).
self.assertTrue(isinstance(health, dict))