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:
parent
e045cc4617
commit
f591a86151
|
@ -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)
|
||||
|
|
|
@ -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)
|
|
@ -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"])
|
||||
|
|
|
@ -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)
|
Loading…
Reference in New Issue