Add services operations into compute service

Nova has allowed to enable/disable/force_down services. This patch
is to add these interfaces into compute services. One direct use case
is in Senlin for fencing purpose.

Change-Id: I180be0e7af2859a355a6fc067c1fc66fe72ed01e
This commit is contained in:
Cindia-blue 2016-08-04 16:27:36 +08:00
parent e045cc4617
commit f591a86151
4 changed files with 294 additions and 0 deletions

View File

@ -21,6 +21,7 @@ from openstack.compute.v2 import server as _server
from openstack.compute.v2 import server_group as _server_group
from openstack.compute.v2 import server_interface as _server_interface
from openstack.compute.v2 import server_ip
from openstack.compute.v2 import service as _service
from openstack import proxy2
from openstack import resource2
@ -828,3 +829,69 @@ class Proxy(proxy2.BaseProxy):
when no resource can be found.
"""
return self._get(_hypervisor.Hypervisor, hypervisor)
def get_service(self, service):
"""Get a single service
:param service: The value can be the ID of a serivce or a
:class:`~openstack.compute.v2.service.Service`
instance.
:returns:
A :class:`~openstack.compute.v2.serivce.Service` object.
:raises: :class:`~openstack.exceptions.ResourceNotFound`
when no resource can be found.
"""
return self._get(_service.Service, service)
def force_service_down(self, service, host, binary):
"""Force a service down
:param service: Either the ID of a service or a
:class:`~openstack.compute.v2.server.Service` instance.
:param str host: The host where service runs.
:param str binary: The name of service.
:returns: None
"""
service = self._get_resource(_service.Service, service)
service.force_down(self.session, host, binary)
def disable_service(self, service, host, binary, disabled_reason=None):
"""Disable a service
:param service: Either the ID of a service or a
:class:`~openstack.compute.v2.server.Service` instance.
:param str host: The host where service runs.
:param str binary: The name of service.
:param str disabled_reason: The reason of force down a service.
:returns: None
"""
service = self._get_resource(_service.Service, service)
service.disable(self.session,
host, binary,
disabled_reason)
def enable_service(self, service, host, binary):
"""Enable a service
:param service: Either the ID of a service or a
:class:`~openstack.compute.v2.server.Service` instance.
:param str host: The host where service runs.
:param str binary: The name of service.
:returns: None
"""
service = self._get_resource(_service.Service, service)
service.enable(self.session, host, binary)
def services(self):
"""Return a generator of service
:returns: A generator of service
:rtype: class: `~openstack.compute.v2.service.Service`
"""
return self._list(_service.Service, paginated=False)

View File

@ -0,0 +1,83 @@
# 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 openstack.compute import compute_service
from openstack import resource2
from openstack import utils
class Service(resource2.Resource):
resource_key = 'service'
resources_key = 'services'
base_path = '/os-services'
service = compute_service.ComputeService()
# capabilities
allow_get = True
allow_list = True
allow_update = True
# Properties
#: Status of service
status = resource2.Body('status')
#: State of service
state = resource2.Body('state')
#: Name of service
binary = resource2.Body('binary')
#: Id of service
id = resource2.Body('id')
#: Disabled reason of service
disables_reason = resource2.Body('disabled_reason')
#: Host where service runs
host = resource2.Body('host')
#: The availability zone of service
zone = resource2.Body("zone")
def _action(self, session, action, body):
url = utils.urljoin(Service.base_path, action)
return session.put(url, endpoint_filter=self.service, json=body)
def force_down(self, session, host, binary):
"""Force a service down."""
body = {
'host': host,
'binary': binary,
'forced_down': True,
}
return self._action(session, 'force-down', body)
def enable(self, session, host, binary):
"""Enable service."""
body = {
'host': host,
'binary': binary,
}
return self._action(session, 'enable', body)
def disable(self, session, host, binary, reason=None):
"""Disable service."""
body = {
'host': host,
'binary': binary,
}
if not reason:
action = 'disable'
else:
body['disabled_reason'] = reason
action = 'disable-log-reason'
return self._action(session, action, body)

View File

@ -22,6 +22,7 @@ from openstack.compute.v2 import server
from openstack.compute.v2 import server_group
from openstack.compute.v2 import server_interface
from openstack.compute.v2 import server_ip
from openstack.compute.v2 import service
from openstack.tests.unit import test_proxy_base2
@ -349,3 +350,30 @@ class TestComputeProxy(test_proxy_base2.TestProxyBase):
def test_get_hypervisor(self):
self.verify_get(self.proxy.get_hypervisor,
hypervisor.Hypervisor)
def test_get_service(self):
self.verify_get(self.proxy.get_service,
service.Service)
def test_services(self):
self.verify_list_no_kwargs(self.proxy.services,
service.Service,
paginated=False)
def test_enable_service(self):
self._verify('openstack.compute.v2.service.Service.enable',
self.proxy.enable_service,
method_args=["value", "host1", "nova-compute"],
expected_args=["host1", "nova-compute"])
def test_disable_service(self):
self._verify('openstack.compute.v2.service.Service.disable',
self.proxy.disable_service,
method_args=["value", "host1", "nova-compute"],
expected_args=["host1", "nova-compute", None])
def test_force_service_down(self):
self._verify('openstack.compute.v2.service.Service.force_down',
self.proxy.force_service_down,
method_args=["value", "host1", "nova-compute"],
expected_args=["host1", "nova-compute"])

View File

@ -0,0 +1,116 @@
# 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 mock
import testtools
from openstack.compute.v2 import service
IDENTIFIER = 'IDENTIFIER'
EXAMPLE = {
'id': IDENTIFIER,
'binary': 'nova-compute',
'host': 'host1',
'status': 'enabled',
'state': 'up',
'zone': 'nova'
}
class TestService(testtools.TestCase):
def setUp(self):
super(TestService, self).setUp()
self.resp = mock.Mock()
self.resp.body = None
self.resp.json = mock.Mock(return_value=self.resp.body)
self.sess = mock.Mock()
self.sess.put = mock.Mock(return_value=self.resp)
def test_basic(self):
sot = service.Service()
self.assertEqual('service', sot.resource_key)
self.assertEqual('services', sot.resources_key)
self.assertEqual('/os-services', sot.base_path)
self.assertEqual('compute', sot.service.service_type)
self.assertTrue(sot.allow_get)
self.assertTrue(sot.allow_update)
self.assertTrue(sot.allow_list)
def test_make_it(self):
sot = service.Service(**EXAMPLE)
self.assertEqual(EXAMPLE['host'], sot.host)
self.assertEqual(EXAMPLE['binary'], sot.binary)
self.assertEqual(EXAMPLE['status'], sot.status)
self.assertEqual(EXAMPLE['state'], sot.state)
self.assertEqual(EXAMPLE['zone'], sot.zone)
self.assertEqual(EXAMPLE['id'], sot.id)
def test_force_down(self):
sot = service.Service(**EXAMPLE)
res = sot.force_down(self.sess, 'host1', 'nova-compute')
self.assertIsNone(res.body)
url = 'os-services/force-down'
body = {
'binary': 'nova-compute',
'host': 'host1',
'forced_down': True,
}
self.sess.put.assert_called_with(
url, endpoint_filter=sot.service, json=body)
def test_enable(self):
sot = service.Service(**EXAMPLE)
res = sot.enable(self.sess, 'host1', 'nova-compute')
self.assertIsNone(res.body)
url = 'os-services/enable'
body = {
'binary': 'nova-compute',
'host': 'host1',
}
self.sess.put.assert_called_with(
url, endpoint_filter=sot.service, json=body)
def test_disable(self):
sot = service.Service(**EXAMPLE)
res = sot.disable(self.sess, 'host1', 'nova-compute')
self.assertIsNone(res.body)
url = 'os-services/disable'
body = {
'binary': 'nova-compute',
'host': 'host1',
}
self.sess.put.assert_called_with(
url, endpoint_filter=sot.service, json=body)
def test_disable_with_reason(self):
sot = service.Service(**EXAMPLE)
reason = 'fencing'
res = sot.disable(self.sess, 'host1', 'nova-compute', reason=reason)
self.assertIsNone(res.body)
url = 'os-services/disable-log-reason'
body = {
'binary': 'nova-compute',
'host': 'host1',
'disabled_reason': reason
}
self.sess.put.assert_called_with(
url, endpoint_filter=sot.service, json=body)