diff --git a/nova/db/api.py b/nova/db/api.py index 07eebd017107..7e889c872d5c 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -52,41 +52,46 @@ class NoMoreNetworks(exception.Error): ################### -def daemon_get(context, daemon_id): - """Get an daemon or raise if it does not exist.""" - return IMPL.daemon_get(context, daemon_id) +def service_destroy(context, instance_id): + """Destroy the service or raise if it does not exist.""" + return IMPL.service_destroy(context, instance_id) -def daemon_get_by_args(context, host, binary): - """Get the state of an daemon by node name and binary.""" - return IMPL.daemon_get_by_args(context, host, binary) +def service_get(context, service_id): + """Get an service or raise if it does not exist.""" + return IMPL.service_get(context, service_id) -def daemon_get_all_by_topic(context, topic): - """Get all compute daemons for a given topi """ - return IMPL.daemon_get_all_by_topic(context, topic) +def service_get_all_by_topic(context, topic): + """Get all compute services for a given topic """ + return IMPL.service_get_all_by_topic(context, topic) -def daemon_get_all_compute_sorted(context): - """Get all compute daemons sorted by instance count +def service_get_all_compute_sorted(context): + """Get all compute services sorted by instance count - Returns a list of (Daemon, instance_count) tuples + Returns a list of (Service, instance_count) tuples """ - return IMPL.daemon_get_all_compute_sorted(context) + return IMPL.service_get_all_compute_sorted(context) -def daemon_create(context, values): - """Create a daemon from the values dictionary.""" - return IMPL.daemon_create(context, values) +def service_get_by_args(context, host, binary): + """Get the state of an service by node name and binary.""" + return IMPL.service_get_by_args(context, host, binary) -def daemon_update(context, daemon_id, values): - """Set the given properties on an daemon and update it. +def service_create(context, values): + """Create a service from the values dictionary.""" + return IMPL.service_create(context, values) - Raises NotFound if daemon does not exist. + +def service_update(context, service_id, values): + """Set the given properties on an service and update it. + + Raises NotFound if service does not exist. """ - return IMPL.daemon_update(context, daemon_id, values) + return IMPL.service_update(context, service_id, values) ################### diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 003e47070ecb..e917a395956e 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -36,27 +36,27 @@ FLAGS = flags.FLAGS ################### -def daemon_get(_context, daemon_id): - return models.Daemon.find(daemon_id) +def service_destroy(context, service_id): + service_ref = service_get(context, service_id) + service_ref.delete() + +def service_get(_context, service_id): + return models.Service.find(service_id) -def daemon_get_by_args(_context, host, binary): - return models.Daemon.find_by_args(host, binary) - - -def daemon_get_all_by_topic(context, topic): +def service_get_all_by_topic(context, topic): with managed_session() as session: - return session.query(models.Daemon) \ + return session.query(models.Service) \ .filter_by(deleted=False) \ .filter_by(topic=topic) \ .all() -def daemon_get_all_compute_sorted(_context): +def service_get_all_compute_sorted(_context): with managed_session() as session: # NOTE(vish): The intended query is below - # SELECT daemons.*, inst_count.instance_count - # FROM daemons LEFT OUTER JOIN + # SELECT services.*, inst_count.instance_count + # FROM services LEFT OUTER JOIN # (SELECT host, count(*) AS instance_count # FROM instances GROUP BY host) AS inst_count subq = session.query(models.Instance.host, @@ -65,27 +65,31 @@ def daemon_get_all_compute_sorted(_context): .group_by(models.Instance.host) \ .subquery() topic = 'compute' - return session.query(models.Daemon, subq.c.instance_count) \ + return session.query(models.Service, subq.c.instance_count) \ .filter_by(topic=topic) \ .filter_by(deleted=False) \ - .outerjoin((subq, models.Daemon.host == subq.c.host)) \ + .outerjoin((subq, models.Service.host == subq.c.host)) \ .order_by(subq.c.instance_count) \ .all() -def daemon_create(_context, values): - daemon_ref = models.Daemon() - for (key, value) in values.iteritems(): - daemon_ref[key] = value - daemon_ref.save() - return daemon_ref.id +def service_get_by_args(_context, host, binary): + return models.Service.find_by_args(host, binary) -def daemon_update(context, daemon_id, values): - daemon_ref = daemon_get(context, daemon_id) +def service_create(_context, values): + service_ref = models.Service() for (key, value) in values.iteritems(): - daemon_ref[key] = value - daemon_ref.save() + service_ref[key] = value + service_ref.save() + return service_ref.id + + +def service_update(context, service_id, values): + service_ref = service_get(context, service_id) + for (key, value) in values.iteritems(): + service_ref[key] = value + service_ref.save() ################### diff --git a/nova/db/sqlalchemy/models.py b/nova/db/sqlalchemy/models.py index 8ba252a76b4f..626be87fe89b 100644 --- a/nova/db/sqlalchemy/models.py +++ b/nova/db/sqlalchemy/models.py @@ -160,9 +160,9 @@ class Host(BASE, NovaBase): id = Column(String(255), primary_key=True) -class Daemon(BASE, NovaBase): +class Service(BASE, NovaBase): """Represents a running service on a host""" - __tablename__ = 'daemons' + __tablename__ = 'services' id = Column(Integer, primary_key=True) host = Column(String(255), ForeignKey('hosts.id')) binary = Column(String(255)) @@ -392,7 +392,7 @@ class FloatingIp(BASE, NovaBase): def register_models(): """Register Models and create metadata""" from sqlalchemy import create_engine - models = (Image, Host, Daemon, Instance, Volume, ExportDevice, + models = (Image, Host, Service, Instance, Volume, ExportDevice, FixedIp, FloatingIp, Network, NetworkIndex) engine = create_engine(FLAGS.sql_connection, echo=False) for model in models: diff --git a/nova/endpoint/images.py b/nova/endpoint/images.py index f72c277a05a3..4579cd81ae0c 100644 --- a/nova/endpoint/images.py +++ b/nova/endpoint/images.py @@ -18,7 +18,7 @@ """ Proxy AMI-related calls from the cloud controller, to the running -objectstore daemon. +objectstore service. """ import json diff --git a/nova/server.py b/nova/server.py index c6b60e090969..8cc1e0ffa395 100644 --- a/nova/server.py +++ b/nova/server.py @@ -17,11 +17,11 @@ # under the License. """ -Base functionality for nova daemons - gradually being replaced with twistd.py. +Base functionality for nova services - gradually being replaced with twistd.py. """ -import daemon -from daemon import pidlockfile +import service +from service import pidlockfile import logging import logging.handlers import os @@ -33,14 +33,14 @@ from nova import flags FLAGS = flags.FLAGS -flags.DEFINE_bool('daemonize', False, 'daemonize this process') -# NOTE(termie): right now I am defaulting to using syslog when we daemonize +flags.DEFINE_bool('serviceize', False, 'serviceize this process') +# NOTE(termie): right now I am defaulting to using syslog when we serviceize # it may be better to do something else -shrug- # NOTE(Devin): I think we should let each process have its own log file # and put it in /var/logs/nova/(appname).log # This makes debugging much easier and cuts down on sys log # clutter. -flags.DEFINE_bool('use_syslog', True, 'output to syslog when daemonizing') +flags.DEFINE_bool('use_syslog', True, 'output to syslog when serviceizing') flags.DEFINE_string('logfile', None, 'log file to output to') flags.DEFINE_string('pidfile', None, 'pid file to output to') flags.DEFINE_string('working_directory', './', 'working directory...') @@ -50,17 +50,17 @@ flags.DEFINE_integer('gid', os.getgid(), 'gid under which to run') def stop(pidfile): """ - Stop the daemon + Stop the service """ # Get the pid from the pidfile try: pid = int(open(pidfile,'r').read().strip()) except IOError: - message = "pidfile %s does not exist. Daemon not running?\n" + message = "pidfile %s does not exist. Service not running?\n" sys.stderr.write(message % pidfile) return # not an error in a restart - # Try killing the daemon process + # Try killing the service process try: while 1: os.kill(pid, signal.SIGTERM) @@ -100,13 +100,13 @@ def serve(name, main): else: print 'usage: %s [options] [start|stop|restart]' % argv[0] sys.exit(1) - daemonize(argv, name, main) + serviceize(argv, name, main) -def daemonize(args, name, main): - """Does the work of daemonizing the process""" +def serviceize(args, name, main): + """Does the work of serviceizing the process""" logging.getLogger('amqplib').setLevel(logging.WARN) - if FLAGS.daemonize: + if FLAGS.serviceize: logger = logging.getLogger() formatter = logging.Formatter( name + '(%(name)s): %(levelname)s %(message)s') @@ -129,8 +129,8 @@ def daemonize(args, name, main): else: logging.getLogger().setLevel(logging.WARNING) - with daemon.DaemonContext( - detach_process=FLAGS.daemonize, + with service.ServiceContext( + detach_process=FLAGS.serviceize, working_directory=FLAGS.working_directory, pidfile=pidlockfile.TimeoutPIDLockFile(FLAGS.pidfile, acquire_timeout=1, diff --git a/nova/service.py b/nova/service.py index 198d3e3c6b76..fc188be34b27 100644 --- a/nova/service.py +++ b/nova/service.py @@ -52,6 +52,16 @@ class Service(object, service.Service): self.manager = manager_class(host=host, *args, **kwargs) self.model_disconnected = False super(Service, self).__init__(*args, **kwargs) + try: + service_ref = db.service_get_by_args(None, + self.host, + self.binary) + self.service_id = service_ref['id'] + except exception.NotFound: + self.service_id = db.service_create(None, {'host': self.host, + 'binary': self.binary, + 'topic': self.topic, + 'report_count': 0}) def __getattr__(self, key): try: @@ -110,24 +120,25 @@ class Service(object, service.Service): service_obj.setServiceParent(application) return application + def kill(self, context=None): + """Destroy the service object in the datastore""" + try: + service_ref = db.service_get_by_args(context, + self.host, + self.binary) + service_id = service_ref['id'] + db.service_destroy(context, self.service_id) + except exception.NotFound: + logging.warn("Service killed that has no database entry") + @defer.inlineCallbacks def report_state(self, context=None): - """Update the state of this daemon in the datastore.""" + """Update the state of this service in the datastore.""" try: - try: - daemon_ref = db.daemon_get_by_args(context, - self.host, - self.binary) - daemon_id = daemon_ref['id'] - except exception.NotFound: - daemon_id = db.daemon_create(context, {'host': self.host, - 'binary': self.binary, - 'topic': self.topic, - 'report_count': 0}) - daemon_ref = db.daemon_get(context, daemon_id) - db.daemon_update(context, - daemon_id, - {'report_count': daemon_ref['report_count'] + 1}) + service_ref = db.service_get(context, self.service_id) + db.service_update(context, + self.service_id, + {'report_count': service_ref['report_count'] + 1}) # TODO(termie): make this pattern be more elegant. if getattr(self, "model_disconnected", False): diff --git a/nova/tests/service_unittest.py b/nova/tests/service_unittest.py index 318abe645499..274e74b5b760 100644 --- a/nova/tests/service_unittest.py +++ b/nova/tests/service_unittest.py @@ -84,40 +84,40 @@ class ServiceTestCase(test.BaseTestCase): def test_report_state(self): host = 'foo' binary = 'bar' - daemon_ref = {'host': host, + service_ref = {'host': host, 'binary': binary, 'report_count': 0, 'id': 1} service.db.__getattr__('report_state') - service.db.daemon_get_by_args(None, + service.db.service_get_by_args(None, host, - binary).AndReturn(daemon_ref) - service.db.daemon_update(None, daemon_ref['id'], + binary).AndReturn(service_ref) + service.db.service_update(None, service_ref['id'], mox.ContainsKeyValue('report_count', 1)) self.mox.ReplayAll() s = service.Service() rv = yield s.report_state(host, binary) - def test_report_state_no_daemon(self): + def test_report_state_no_service(self): host = 'foo' binary = 'bar' - daemon_create = {'host': host, + service_create = {'host': host, 'binary': binary, 'report_count': 0} - daemon_ref = {'host': host, + service_ref = {'host': host, 'binary': binary, 'report_count': 0, 'id': 1} service.db.__getattr__('report_state') - service.db.daemon_get_by_args(None, + service.db.service_get_by_args(None, host, binary).AndRaise(exception.NotFound()) - service.db.daemon_create(None, - daemon_create).AndReturn(daemon_ref['id']) - service.db.daemon_get(None, daemon_ref['id']).AndReturn(daemon_ref) - service.db.daemon_update(None, daemon_ref['id'], + service.db.service_create(None, + service_create).AndReturn(service_ref['id']) + service.db.service_get(None, service_ref['id']).AndReturn(service_ref) + service.db.service_update(None, service_ref['id'], mox.ContainsKeyValue('report_count', 1)) self.mox.ReplayAll() @@ -127,13 +127,13 @@ class ServiceTestCase(test.BaseTestCase): def test_report_state_newly_disconnected(self): host = 'foo' binary = 'bar' - daemon_ref = {'host': host, + service_ref = {'host': host, 'binary': binary, 'report_count': 0, 'id': 1} service.db.__getattr__('report_state') - service.db.daemon_get_by_args(None, + service.db.service_get_by_args(None, host, binary).AndRaise(Exception()) @@ -146,16 +146,16 @@ class ServiceTestCase(test.BaseTestCase): def test_report_state_newly_connected(self): host = 'foo' binary = 'bar' - daemon_ref = {'host': host, + service_ref = {'host': host, 'binary': binary, 'report_count': 0, 'id': 1} service.db.__getattr__('report_state') - service.db.daemon_get_by_args(None, + service.db.service_get_by_args(None, host, - binary).AndReturn(daemon_ref) - service.db.daemon_update(None, daemon_ref['id'], + binary).AndReturn(service_ref) + service.db.service_update(None, service_ref['id'], mox.ContainsKeyValue('report_count', 1)) self.mox.ReplayAll()