summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Sherborne <msherborne@gmail.com>2013-03-15 13:46:12 +1000
committerMatthew Sherborne <msherborne@gmail.com>2013-04-23 22:04:01 +1000
commit732bcdb9502aca5c6b38966bd1e53c79236300da (patch)
treee7a5ab2c4fd2fad84c66d64548833f3bc2309236
parentbfc3a3ccb2811cc8a96a15987528e6639ec029bf (diff)
Make os.services.update work with cells
In the nova.api.openstack.compute.contrib.services: * Make update (enable/disable) service work In nova.compute.api.api.HostAPI: Add - service_update - Used by openstack api's services.py In nova.compute.api.cells_api.HostAPI: Add - service_update - Used by openstack api's services.py In cells: * Increase API version from 1.6 to 1.7 * Add service_update Fixes bug #1150499 Change-Id: I5651bd5bc328692df82f4d9da27d390a8c95e03f
-rw-r--r--nova/api/openstack/compute/contrib/services.py18
-rw-r--r--nova/cells/manager.py20
-rw-r--r--nova/cells/messaging.py35
-rw-r--r--nova/cells/rpcapi.py16
-rw-r--r--nova/compute/api.py9
-rw-r--r--nova/compute/cells_api.py13
-rw-r--r--nova/tests/cells/test_cells_manager.py20
-rw-r--r--nova/tests/cells/test_cells_messaging.py37
-rw-r--r--nova/tests/cells/test_cells_rpcapi.py14
-rw-r--r--nova/tests/compute/test_host_api.py39
10 files changed, 210 insertions, 11 deletions
diff --git a/nova/api/openstack/compute/contrib/services.py b/nova/api/openstack/compute/contrib/services.py
index d948c8bc5..9952484f7 100644
--- a/nova/api/openstack/compute/contrib/services.py
+++ b/nova/api/openstack/compute/contrib/services.py
@@ -21,7 +21,6 @@ from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api.openstack import xmlutil
from nova import compute
-from nova import db
from nova import exception
from nova.openstack.common import timeutils
from nova import utils
@@ -121,7 +120,10 @@ class ServiceController(object):
elif id == "disable":
disabled = True
else:
- raise webob.exc.HTTPNotFound("Unknown action")
+ raise webob.exc.HTTPNotFound(_("Unknown action"))
+
+ status = id + 'd'
+
try:
host = body['host']
binary = body['binary']
@@ -129,15 +131,11 @@ class ServiceController(object):
raise webob.exc.HTTPUnprocessableEntity()
try:
- svc = db.service_get_by_args(context, host, binary)
- if not svc:
- raise webob.exc.HTTPNotFound('Unknown service')
+ svc = self.host_api.service_update(context, host, binary,
+ {'disabled': disabled})
+ except exception.ServiceNotFound as exc:
+ raise webob.exc.HTTPNotFound(_("Unknown service"))
- db.service_update(context, svc['id'], {'disabled': disabled})
- except exception.ServiceNotFound:
- raise webob.exc.HTTPNotFound("service not found")
-
- status = id + 'd'
return {'service': {'host': host, 'binary': binary, 'status': status}}
diff --git a/nova/cells/manager.py b/nova/cells/manager.py
index 51d2f7cac..f536d270c 100644
--- a/nova/cells/manager.py
+++ b/nova/cells/manager.py
@@ -63,7 +63,7 @@ class CellsManager(manager.Manager):
Scheduling requests get passed to the scheduler class.
"""
- RPC_API_VERSION = '1.6'
+ RPC_API_VERSION = '1.7'
def __init__(self, *args, **kwargs):
# Mostly for tests.
@@ -250,6 +250,24 @@ class CellsManager(manager.Manager):
cells_utils.add_cell_to_service(service, response.cell_name)
return service
+ def service_update(self, ctxt, host_name, binary, params_to_update):
+ """
+ Used to enable/disable a service. For compute services, setting to
+ disabled stops new builds arriving on that host.
+
+ :param host_name: the name of the host machine that the service is
+ running
+ :param binary: The name of the executable that the service runs as
+ :param params_to_update: eg. {'disabled': True}
+ :returns: the service reference
+ """
+ cell_name, host_name = cells_utils.split_cell_and_item(host_name)
+ response = self.msg_runner.service_update(
+ ctxt, cell_name, host_name, binary, params_to_update)
+ service = response.value_or_raise()
+ cells_utils.add_cell_to_service(service, response.cell_name)
+ return service
+
def proxy_rpc_to_manager(self, ctxt, topic, rpc_message, call, timeout):
"""Proxy an RPC message as-is to a manager."""
compute_topic = CONF.compute_topic
diff --git a/nova/cells/messaging.py b/nova/cells/messaging.py
index 02044ffd5..2e2fa735a 100644
--- a/nova/cells/messaging.py
+++ b/nova/cells/messaging.py
@@ -603,6 +603,7 @@ class _BaseMessageMethods(base.Base):
self.compute_api = compute.API()
self.compute_rpcapi = compute_rpcapi.ComputeAPI()
self.consoleauth_rpcapi = consoleauth_rpcapi.ConsoleAuthAPI()
+ self.host_api = compute.HostAPI()
def task_log_get_all(self, message, task_name, period_beginning,
period_ending, host, state):
@@ -705,6 +706,20 @@ class _TargetedMessageMethods(_BaseMessageMethods):
host_name)
return jsonutils.to_primitive(service)
+ def service_update(self, message, host_name, binary, params_to_update):
+ """
+ Used to enable/disable a service. For compute services, setting to
+ disabled stops new builds arriving on that host.
+
+ :param host_name: the name of the host machine that the service is
+ running
+ :param binary: The name of the executable that the service runs as
+ :param params_to_update: eg. {'disabled': True}
+ """
+ return jsonutils.to_primitive(
+ self.host_api.service_update(message.ctxt, host_name, binary,
+ params_to_update))
+
def proxy_rpc_to_manager(self, message, host_name, rpc_message,
topic, timeout):
"""Proxy RPC to the given compute topic."""
@@ -1168,6 +1183,26 @@ class MessageRunner(object):
need_response=True)
return message.process()
+ def service_update(self, ctxt, cell_name, host_name, binary,
+ params_to_update):
+ """
+ Used to enable/disable a service. For compute services, setting to
+ disabled stops new builds arriving on that host.
+
+ :param host_name: the name of the host machine that the service is
+ running
+ :param binary: The name of the executable that the service runs as
+ :param params_to_update: eg. {'disabled': True}
+ :returns: the update service object
+ """
+ method_kwargs = dict(host_name=host_name, binary=binary,
+ params_to_update=params_to_update)
+ message = _TargetedMessage(self, ctxt,
+ 'service_update',
+ method_kwargs, 'down', cell_name,
+ need_response=True)
+ return message.process()
+
def proxy_rpc_to_manager(self, ctxt, cell_name, host_name, topic,
rpc_message, call, timeout):
method_kwargs = {'host_name': host_name,
diff --git a/nova/cells/rpcapi.py b/nova/cells/rpcapi.py
index ca6e23fb1..c8b7c680f 100644
--- a/nova/cells/rpcapi.py
+++ b/nova/cells/rpcapi.py
@@ -49,6 +49,7 @@ class CellsAPI(rpc_proxy.RpcProxy):
1.5 - Adds actions_get(), action_get_by_request_id(), and
action_events_get()
1.6 - Adds consoleauth_delete_tokens() and validate_console_port()
+ 1.7 - Adds service_update()
'''
BASE_RPC_API_VERSION = '1.0'
@@ -179,6 +180,21 @@ class CellsAPI(rpc_proxy.RpcProxy):
host_name=host_name),
version='1.2')
+ def service_update(self, ctxt, host_name, binary, params_to_update):
+ """
+ Used to enable/disable a service. For compute services, setting to
+ disabled stops new builds arriving on that host.
+
+ :param host_name: the name of the host machine that the service is
+ running
+ :param binary: The name of the executable that the service runs as
+ :param params_to_update: eg. {'disabled': True}
+ """
+ return self.call(ctxt, self.make_msg(
+ 'service_update', host_name=host_name,
+ binary=binary, params_to_update=params_to_update),
+ version='1.7')
+
def proxy_rpc_to_manager(self, ctxt, rpc_message, topic, call=False,
timeout=None):
"""Proxy RPC to a compute manager. The host in the topic
diff --git a/nova/compute/api.py b/nova/compute/api.py
index 1b1a3c506..73d9a652c 100644
--- a/nova/compute/api.py
+++ b/nova/compute/api.py
@@ -41,6 +41,7 @@ from nova.compute import utils as compute_utils
from nova.compute import vm_states
from nova.consoleauth import rpcapi as consoleauth_rpcapi
from nova import crypto
+from nova import db
from nova.db import base
from nova import exception
from nova import hooks
@@ -2564,6 +2565,14 @@ class HostAPI(base.Base):
"""Get service entry for the given compute hostname."""
return self.db.service_get_by_compute_host(context, host_name)
+ def service_update(self, context, host_name, binary, params_to_update):
+ """
+ Enable / Disable a service.
+ For compute services, this stops new builds and migrations going to
+ the host."""
+ service = db.service_get_by_args(context, host_name, binary)
+ return db.service_update(context, service['id'], params_to_update)
+
def instance_get_all_by_host(self, context, host_name):
"""Return all instances on the given host."""
return self.db.instance_get_all_by_host(context, host_name)
diff --git a/nova/compute/cells_api.py b/nova/compute/cells_api.py
index f5ded45ec..9c0f72c97 100644
--- a/nova/compute/cells_api.py
+++ b/nova/compute/cells_api.py
@@ -603,6 +603,19 @@ class HostAPI(compute_api.HostAPI):
return self.cells_rpcapi.service_get_by_compute_host(context,
host_name)
+ def service_update(self, context, host_name, binary, params_to_update):
+ """
+ Used to enable/disable a service. For compute services, setting to
+ disabled stops new builds arriving on that host.
+
+ :param host_name: the name of the host machine that the service is
+ running
+ :param binary: The name of the executable that the service runs as
+ :param params_to_update: eg. {'disabled': True}
+ """
+ return self.cells_rpcapi.service_update(
+ context, host_name, binary, params_to_update)
+
def instance_get_all_by_host(self, context, host_name):
"""Get all instances by host. Host might have a cell prepended
to it, so we'll need to strip it out. We don't need to proxy
diff --git a/nova/tests/cells/test_cells_manager.py b/nova/tests/cells/test_cells_manager.py
index 74a7e9834..137d48ff6 100644
--- a/nova/tests/cells/test_cells_manager.py
+++ b/nova/tests/cells/test_cells_manager.py
@@ -294,6 +294,26 @@ class CellsManagerClassTestCase(test.TestCase):
host_name=cell_and_host)
self.assertEqual(expected_response, response)
+ def test_service_update(self):
+ fake_cell = 'fake-cell'
+ fake_response = messaging.Response(
+ fake_cell, FAKE_SERVICES[0], False)
+ expected_response = copy.deepcopy(FAKE_SERVICES[0])
+ cells_utils.add_cell_to_service(expected_response, fake_cell)
+ cell_and_host = cells_utils.cell_with_item('fake-cell', 'fake-host')
+ params_to_update = {'disabled': True}
+
+ self.mox.StubOutWithMock(self.msg_runner, 'service_update')
+ self.msg_runner.service_update(self.ctxt,
+ fake_cell, 'fake-host', 'nova-api',
+ params_to_update).AndReturn(fake_response)
+ self.mox.ReplayAll()
+
+ response = self.cells_manager.service_update(
+ self.ctxt, host_name=cell_and_host, binary='nova-api',
+ params_to_update=params_to_update)
+ self.assertEqual(expected_response, response)
+
def test_proxy_rpc_to_manager(self):
self.mox.StubOutWithMock(self.msg_runner,
'proxy_rpc_to_manager')
diff --git a/nova/tests/cells/test_cells_messaging.py b/nova/tests/cells/test_cells_messaging.py
index bed27085f..728856006 100644
--- a/nova/tests/cells/test_cells_messaging.py
+++ b/nova/tests/cells/test_cells_messaging.py
@@ -20,6 +20,7 @@ from oslo.config import cfg
from nova.cells import messaging
from nova.cells import utils as cells_utils
from nova import context
+from nova import db
from nova import exception
from nova.openstack.common import rpc
from nova.openstack.common import timeutils
@@ -745,6 +746,42 @@ class CellsTargetedMethodsTestCase(test.TestCase):
result = response.value_or_raise()
self.assertEqual('fake-service', result)
+ def test_service_update(self):
+ binary = 'nova-compute'
+ fake_service = dict(id=42, host='fake_host', binary='nova-compute',
+ topic='compute')
+ fake_compute = dict(
+ id=7116, service_id=42, host='fake_host', vcpus=0, memory_mb=0,
+ local_gb=0, vcpus_used=0, memory_mb_used=0, local_gb_used=0,
+ hypervisor_type=0, hypervisor_version=0, hypervisor_hostname=0,
+ free_ram_mb=0, free_disk_gb=0, current_workload=0, running_vms=0,
+ cpu_info='HAL', disk_available_least=0)
+ params_to_update = {'disabled': True, 'report_count': 13}
+
+ ctxt = context.RequestContext('fake_user', 'fake_project',
+ is_admin=True)
+ # We use the real DB for this test, as it's too hard to reach the
+ # host_api to mock out its DB methods
+ db.service_create(ctxt, fake_service)
+ db.compute_node_create(ctxt, fake_compute)
+
+ self.mox.ReplayAll()
+
+ response = self.src_msg_runner.service_update(
+ ctxt, self.tgt_cell_name,
+ 'fake_host', binary, params_to_update)
+ result = response.value_or_raise()
+ result.pop('created_at', None)
+ result.pop('updated_at', None)
+ expected_result = dict(
+ deleted=0, deleted_at=None,
+ binary=fake_service['binary'],
+ disabled=True, # We just updated this..
+ report_count=13, # ..and this
+ host='fake_host', id=42,
+ topic='compute')
+ self.assertEqual(expected_result, result)
+
def test_proxy_rpc_to_manager_call(self):
fake_topic = 'fake-topic'
fake_rpc_message = 'fake-rpc-message'
diff --git a/nova/tests/cells/test_cells_rpcapi.py b/nova/tests/cells/test_cells_rpcapi.py
index 0a5c6a71b..76c9f05d3 100644
--- a/nova/tests/cells/test_cells_rpcapi.py
+++ b/nova/tests/cells/test_cells_rpcapi.py
@@ -248,6 +248,20 @@ class CellsAPITestCase(test.TestCase):
version='1.2')
self.assertEqual(result, 'fake_response')
+ def test_service_update(self):
+ call_info = self._stub_rpc_method('call', 'fake_response')
+ result = self.cells_rpcapi.service_update(
+ self.fake_context, host_name='fake-host-name',
+ binary='nova-api', params_to_update={'disabled': True})
+ expected_args = {
+ 'host_name': 'fake-host-name',
+ 'binary': 'nova-api',
+ 'params_to_update': {'disabled': True}}
+ self._check_result(call_info, 'service_update',
+ expected_args,
+ version='1.7')
+ self.assertEqual(result, 'fake_response')
+
def test_proxy_rpc_to_manager(self):
call_info = self._stub_rpc_method('call', 'fake_response')
result = self.cells_rpcapi.proxy_rpc_to_manager(
diff --git a/nova/tests/compute/test_host_api.py b/nova/tests/compute/test_host_api.py
index 66dd1d739..6a87205ae 100644
--- a/nova/tests/compute/test_host_api.py
+++ b/nova/tests/compute/test_host_api.py
@@ -205,6 +205,27 @@ class ComputeHostAPITestCase(test.TestCase):
'fake-host')
self.assertEqual('fake-response', result)
+ def test_service_update(self):
+ host_name = 'fake-host'
+ binary = 'nova-compute'
+ params_to_update = dict(disabled=True)
+ service_id = 42
+ expected_result = {'id': service_id}
+
+ self.mox.StubOutWithMock(self.host_api.db, 'service_get_by_args')
+ self.host_api.db.service_get_by_args(self.ctxt,
+ host_name, binary).AndReturn({'id': service_id})
+
+ self.mox.StubOutWithMock(self.host_api.db, 'service_update')
+ self.host_api.db.service_update(
+ self.ctxt, service_id, params_to_update).AndReturn(expected_result)
+
+ self.mox.ReplayAll()
+
+ result = self.host_api.service_update(
+ self.ctxt, host_name, binary, params_to_update)
+ self.assertEqual(expected_result, result)
+
def test_instance_get_all_by_host(self):
self.mox.StubOutWithMock(self.host_api.db,
'instance_get_all_by_host')
@@ -312,6 +333,24 @@ class ComputeHostAPICellsTestCase(ComputeHostAPITestCase):
'fake-host')
self.assertEqual('fake-response', result)
+ def test_service_update(self):
+ host_name = 'fake-host'
+ binary = 'nova-compute'
+ params_to_update = dict(disabled=True)
+ service_id = 42
+ expected_result = {'id': service_id}
+
+ self.mox.StubOutWithMock(self.host_api.cells_rpcapi, 'service_update')
+ self.host_api.cells_rpcapi.service_update(
+ self.ctxt, host_name,
+ binary, params_to_update).AndReturn(expected_result)
+
+ self.mox.ReplayAll()
+
+ result = self.host_api.service_update(
+ self.ctxt, host_name, binary, params_to_update)
+ self.assertEqual(expected_result, result)
+
def test_instance_get_all_by_host(self):
instances = [dict(id=1, cell_name='cell1', host='host1'),
dict(id=2, cell_name='cell2', host='host1'),