Convert service and servicegroup to objects

This converts service and servicegroup to use objects instead of
proxying through conductor.

Adds missing object registration to cert and console scripts.

Related to blueprint liberty-objects

Change-Id: I87b077699c2ecbc25a83e5844e8c69fe147cec01
This commit is contained in:
Hans Lindgren 2014-10-13 14:21:07 +02:00
parent 232c7afcf6
commit 19455514d1
9 changed files with 62 additions and 146 deletions

View File

@ -20,6 +20,7 @@ from oslo_config import cfg
from oslo_log import log as logging
from nova import config
from nova import objects
from nova.openstack.common.report import guru_meditation_report as gmr
from nova import service
from nova import utils
@ -33,6 +34,7 @@ def main():
config.parse_args(sys.argv)
logging.setup(CONF, "nova")
utils.monkey_patch()
objects.register_all()
gmr.TextGuruMeditation.setup_autorun(version)

View File

@ -21,6 +21,7 @@ from oslo_config import cfg
from oslo_log import log as logging
from nova import config
from nova import objects
from nova.openstack.common.report import guru_meditation_report as gmr
from nova import service
from nova import version
@ -32,6 +33,7 @@ CONF.import_opt('console_topic', 'nova.console.rpcapi')
def main():
config.parse_args(sys.argv)
logging.setup(CONF, "nova")
objects.register_all()
gmr.TextGuruMeditation.setup_autorun(version)

View File

@ -33,6 +33,7 @@ from nova import context
from nova import debugger
from nova import exception
from nova.i18n import _, _LE, _LI, _LW
from nova import objects
from nova.objects import base as objects_base
from nova.openstack.common import service
from nova import rpc
@ -136,14 +137,7 @@ class Service(service.Service):
self.binary = binary
self.topic = topic
self.manager_class_name = manager
# NOTE(russellb) We want to make sure to create the servicegroup API
# instance early, before creating other things such as the manager,
# that will also create a servicegroup API instance. Internally, the
# servicegroup only allocates a single instance of the driver API and
# we want to make sure that our value of db_allowed is there when it
# gets created. For that to happen, this has to be the first instance
# of the servicegroup API.
self.servicegroup_api = servicegroup.API(db_allowed=db_allowed)
self.servicegroup_api = servicegroup.API()
manager_class = importutils.import_class(self.manager_class_name)
self.manager = manager_class(host=self.host, *args, **kwargs)
self.rpcserver = None
@ -164,21 +158,17 @@ class Service(service.Service):
self.manager.init_host()
self.model_disconnected = False
ctxt = context.get_admin_context()
try:
self.service_ref = (
self.conductor_api.service_get_by_host_and_binary(
ctxt, self.host, self.binary))
self.service_id = self.service_ref['id']
except exception.NotFound:
self.service_ref = objects.Service.get_by_host_and_binary(
ctxt, self.host, self.binary)
if not self.service_ref:
try:
self.service_ref = self._create_service_ref(ctxt)
except (exception.ServiceTopicExists,
exception.ServiceBinaryExists):
# NOTE(danms): If we race to create a record with a sibling
# worker, don't fail here.
self.service_ref = (
self.conductor_api.service_get_by_host_and_binary(
ctxt, self.host, self.binary))
self.service_ref = objects.Service.get_by_host_and_binary(
ctxt, self.host, self.binary)
self.manager.pre_start_hook()
@ -219,14 +209,12 @@ class Service(service.Service):
self.periodic_interval_max)
def _create_service_ref(self, context):
svc_values = {
'host': self.host,
'binary': self.binary,
'topic': self.topic,
'report_count': 0,
}
service = self.conductor_api.service_create(context, svc_values)
self.service_id = service['id']
service = objects.Service(context)
service.host = self.host
service.binary = self.binary
service.topic = self.topic
service.report_count = 0
service.create()
return service
def __getattr__(self, key):
@ -282,8 +270,7 @@ class Service(service.Service):
"""Destroy the service object in the datastore."""
self.stop()
try:
self.conductor_api.service_destroy(context.get_admin_context(),
self.service_id)
self.service_ref.destroy()
except exception.NotFound:
LOG.warning(_LW('Service killed that has no database entry'))

View File

@ -18,9 +18,9 @@ from oslo_log import log as logging
from oslo_utils import timeutils
import six
from nova import conductor
from nova import context
from nova.i18n import _, _LE
from nova import objects
from nova.servicegroup import api
from nova.servicegroup.drivers import base
@ -34,16 +34,6 @@ LOG = logging.getLogger(__name__)
class DbDriver(base.Driver):
def __init__(self, *args, **kwargs):
"""Creates an instance of the DB-based servicegroup driver.
Valid kwargs are:
db_allowed - Boolean. False if direct db access is not allowed and
alternative data access (conductor) should be used
instead.
"""
self.db_allowed = kwargs.get('db_allowed', True)
self.conductor_api = conductor.API(use_local=self.db_allowed)
self.service_down_time = CONF.service_down_time
def join(self, member, group, service=None):
@ -94,22 +84,17 @@ class DbDriver(base.Driver):
LOG.debug('DB_Driver: get_all members of the %s group', group_id)
rs = []
ctxt = context.get_admin_context()
services = self.conductor_api.service_get_all_by_topic(ctxt, group_id)
services = objects.ServiceList.get_by_topic(ctxt, group_id)
for service in services:
if self.is_up(service):
rs.append(service['host'])
rs.append(service.host)
return rs
def _report_state(self, service):
"""Update the state of this service in the datastore."""
ctxt = context.get_admin_context()
state_catalog = {}
try:
report_count = service.service_ref['report_count'] + 1
state_catalog['report_count'] = report_count
service.service_ref = self.conductor_api.service_update(ctxt,
service.service_ref, state_catalog)
service.service_ref.report_count += 1
service.service_ref.save()
# TODO(termie): make this pattern be more elegant.
if getattr(service, 'model_disconnected', False):

View File

@ -21,9 +21,9 @@ from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import timeutils
from nova import conductor
from nova import context
from nova.i18n import _, _LE
from nova import objects
from nova.openstack.common import memorycache
from nova.servicegroup import api
from nova.servicegroup.drivers import base
@ -42,8 +42,6 @@ class MemcachedDriver(base.Driver):
if not CONF.memcached_servers:
raise RuntimeError(_('memcached_servers not defined'))
self.mc = memorycache.get_client()
self.db_allowed = kwargs.get('db_allowed', True)
self.conductor_api = conductor.API(use_local=self.db_allowed)
def join(self, member_id, group_id, service=None):
"""Join the given service with its group."""
@ -80,10 +78,10 @@ class MemcachedDriver(base.Driver):
group_id)
rs = []
ctxt = context.get_admin_context()
services = self.conductor_api.service_get_all_by_topic(ctxt, group_id)
services = objects.ServiceList.get_by_topic(ctxt, group_id)
for service in services:
if self.is_up(service):
rs.append(service['host'])
rs.append(service.host)
return rs
def _report_state(self, service):

View File

@ -2782,6 +2782,11 @@ class ServiceTestCase(test.TestCase, ModelsObjectComparatorMixin):
for key, value in self._get_base_values().iteritems():
self.assertEqual(value, service[key])
def test_service_create_disabled(self):
self.flags(enable_new_services=False)
service = self._create_service({})
self.assertTrue(service['disabled'])
def test_service_destroy(self):
service1 = self._create_service({})
service2 = self._create_service({'host': 'fake_host2'})

View File

@ -15,6 +15,7 @@
import datetime
import mock
from nova import objects
from nova import servicegroup
from nova import test
@ -57,22 +58,11 @@ class DBServiceGroupTestCase(test.NoDBTestCase):
result = self.servicegroup_api.service_is_up(service_ref)
self.assertFalse(result)
@mock.patch('nova.conductor.api.LocalAPI.service_get_all_by_topic')
@mock.patch.object(objects.ServiceList, 'get_by_topic')
def test_get_all(self, ga_mock):
service_refs = [
{
'host': 'fake-host1',
'topic': 'compute'
},
{
'host': 'fake-host2',
'topic': 'compute'
},
{
'host': 'fake-host3',
'topic': 'compute'
},
]
hosts = ['fake-host1', 'fake-host2', 'fake-host3']
service_refs = objects.ServiceList(objects=[
objects.Service(host=host, topic='compute') for host in hosts])
ga_mock.return_value = service_refs
with mock.patch.object(self.servicegroup_api._driver,
'is_up', side_effect=[
@ -91,17 +81,13 @@ class DBServiceGroupTestCase(test.NoDBTestCase):
fn = self.servicegroup_api._driver._report_state
service.tg.add_timer.assert_called_once_with(1, fn, 5, service)
@mock.patch('nova.conductor.api.LocalAPI.service_update')
@mock.patch.object(objects.Service, 'save')
def test_report_state(self, upd_mock):
service_ref = {
'host': 'fake-host',
'topic': 'compute',
'report_count': 10
}
service_ref = objects.Service(host='fake-host', topic='compute',
report_count=10)
service = mock.MagicMock(model_disconnected=False,
service_ref=service_ref)
fn = self.servicegroup_api._driver._report_state
fn(service)
upd_mock.assert_called_once_with(mock.ANY,
service_ref,
dict(report_count=11))
upd_mock.assert_called_once_with()
self.assertEqual(11, service_ref.report_count)

View File

@ -17,6 +17,7 @@
import mock
from nova import objects
from nova import servicegroup
from nova import test
@ -46,22 +47,11 @@ class MemcachedServiceGroupTestCase(test.NoDBTestCase):
self.assertTrue(self.servicegroup_api.service_is_up(service_ref))
self.mc_client.get.assert_called_once_with('compute:fake-host')
@mock.patch('nova.conductor.api.LocalAPI.service_get_all_by_topic')
@mock.patch.object(objects.ServiceList, 'get_by_topic')
def test_get_all(self, ga_mock):
service_refs = [
{
'host': 'fake-host1',
'topic': 'compute'
},
{
'host': 'fake-host2',
'topic': 'compute'
},
{
'host': 'fake-host3',
'topic': 'compute'
},
]
hosts = ['fake-host1', 'fake-host2', 'fake-host3']
service_refs = objects.ServiceList(objects=[
objects.Service(host=host, topic='compute') for host in hosts])
ga_mock.return_value = service_refs
self.mc_client.get.side_effect = [
None,

View File

@ -26,10 +26,9 @@ from oslo_concurrency import processutils
from oslo_config import cfg
import testtools
from nova import context
from nova import db
from nova import exception
from nova import manager
from nova import objects
from nova.openstack.common import service as _service
from nova import rpc
from nova import service
@ -94,31 +93,7 @@ class ServiceManagerTestCase(test.TestCase):
self.assertEqual(CONF.service_down_time, 25)
class ServiceFlagsTestCase(test.TestCase):
def test_service_enabled_on_create_based_on_flag(self):
self.flags(enable_new_services=True)
host = 'foo'
binary = 'nova-fake'
app = service.Service.create(host=host, binary=binary)
app.start()
app.stop()
ref = db.service_get(context.get_admin_context(), app.service_id)
db.service_destroy(context.get_admin_context(), app.service_id)
self.assertFalse(ref['disabled'])
def test_service_disabled_on_create_based_on_flag(self):
self.flags(enable_new_services=False)
host = 'foo'
binary = 'nova-fake'
app = service.Service.create(host=host, binary=binary)
app.start()
app.stop()
ref = db.service_get(context.get_admin_context(), app.service_id)
db.service_destroy(context.get_admin_context(), app.service_id)
self.assertTrue(ref['disabled'])
class ServiceTestCase(test.TestCase):
class ServiceTestCase(test.NoDBTestCase):
"""Test cases for Services."""
def setUp(self):
@ -126,8 +101,6 @@ class ServiceTestCase(test.TestCase):
self.host = 'foo'
self.binary = 'nova-fake'
self.topic = 'fake'
self.mox.StubOutWithMock(db, 'service_create')
self.mox.StubOutWithMock(db, 'service_get_by_host_and_binary')
self.flags(use_local=True, group='conductor')
def test_create(self):
@ -140,21 +113,11 @@ class ServiceTestCase(test.TestCase):
self.assertTrue(app)
def _service_start_mocks(self):
service_create = {'host': self.host,
'binary': self.binary,
'topic': self.topic,
'report_count': 0}
service_ref = {'host': self.host,
'binary': self.binary,
'topic': self.topic,
'report_count': 0,
'id': 1}
db.service_get_by_host_and_binary(mox.IgnoreArg(),
self.host, self.binary).AndRaise(exception.NotFound())
db.service_create(mox.IgnoreArg(),
service_create).AndReturn(service_ref)
return service_ref
self.mox.StubOutWithMock(objects.Service, 'create')
self.mox.StubOutWithMock(objects.Service, 'get_by_host_and_binary')
objects.Service.get_by_host_and_binary(mox.IgnoreArg(), self.host,
self.binary)
objects.Service.create()
def test_init_and_start_hooks(self):
self.manager_mock = self.mox.CreateMock(FakeManager)
@ -193,23 +156,23 @@ class ServiceTestCase(test.TestCase):
self.mox.StubOutWithMock(self.manager_mock, 'init_host')
self.mox.StubOutWithMock(self.manager_mock, 'pre_start_hook')
self.mox.StubOutWithMock(self.manager_mock, 'post_start_hook')
self.mox.StubOutWithMock(objects.Service, 'create')
self.mox.StubOutWithMock(objects.Service, 'get_by_host_and_binary')
FakeManager(host=self.host).AndReturn(self.manager_mock)
# init_host is called before any service record is created
self.manager_mock.init_host()
db.service_get_by_host_and_binary(
mox.IgnoreArg(), self.host, self.binary).AndRaise(
exception.NotFound)
db.service_create(mox.IgnoreArg(), mox.IgnoreArg()
).AndRaise(ex)
objects.Service.get_by_host_and_binary(mox.IgnoreArg(), self.host,
self.binary)
objects.Service.create().AndRaise(ex)
class TestException(Exception):
pass
db.service_get_by_host_and_binary(
mox.IgnoreArg(), self.host, self.binary).AndRaise(TestException)
objects.Service.get_by_host_and_binary(
mox.IgnoreArg(), self.host, self.binary).AndRaise(TestException())
self.mox.ReplayAll()
@ -264,10 +227,9 @@ class ServiceTestCase(test.TestCase):
serv.stop()
@mock.patch('nova.servicegroup.API')
@mock.patch('nova.conductor.api.LocalAPI.service_get_by_host_and_binary')
@mock.patch('nova.objects.service.Service.get_by_host_and_binary')
def test_parent_graceful_shutdown_with_cleanup_host(
self, mock_svc_get_by_host_and_binary, mock_API):
mock_svc_get_by_host_and_binary.return_value = {'id': 'some_value'}
mock_manager = mock.Mock()
serv = service.Service(self.host,
@ -285,11 +247,10 @@ class ServiceTestCase(test.TestCase):
serv.manager.cleanup_host.assert_called_with()
@mock.patch('nova.servicegroup.API')
@mock.patch('nova.conductor.api.LocalAPI.service_get_by_host_and_binary')
@mock.patch('nova.objects.service.Service.get_by_host_and_binary')
@mock.patch.object(rpc, 'get_server')
def test_service_stop_waits_for_rpcserver(
self, mock_rpc, mock_svc_get_by_host_and_binary, mock_API):
mock_svc_get_by_host_and_binary.return_value = {'id': 'some_value'}
serv = service.Service(self.host,
self.binary,
self.topic,