designate/designate/service.py
Tim Simmons fbdd8e9400 The New Agent
A new Designate service to be run on a DNS master that is the 'reflection' of
MiniDNS. It receives Create/NOTIFY/Delete actions, and calls into a backend
that greatly resembles the style of backends in Designate before Server Pools.

This is a squashed commit that formerly contained the following 'Agent' topics:
Basic Service
Add basic NOTIFY support
Add AXFR Capability
Add Support for Receiving Private CLASS/RRDATA Messages
Add Backend Capabilities
Cleanup (Changes here: http://paste.openstack.org/show/160022/)

Implements: blueprint new-agent
Change-Id: I610687878be9dee8065ebc492f662e86bbeb8ce7
2015-01-23 00:23:47 +00:00

216 lines
6.6 KiB
Python

# Copyright 2010 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# Copyright 2011 Justin Santa Barbara
# All Rights Reserved.
#
# 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 os
import inspect
from oslo import messaging
from oslo.config import cfg
from oslo_log import log as logging
from designate.openstack.common import service
from designate.openstack.deprecated import wsgi
from designate.i18n import _
from designate import rpc
from designate import policy
from designate import version
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
class Service(service.Service):
"""
Service class to be shared among the diverse service inside of Designate.
"""
def __init__(self, threads=1000):
super(Service, self).__init__(threads)
policy.init()
# NOTE(kiall): All services need RPC initialized, as this is used
# for clients AND servers. Hence, this is common to
# all Designate services.
if not rpc.initialized():
rpc.init(CONF)
class RPCService(Service):
"""
Service class to be shared by all Designate RPC Services
"""
def __init__(self, host, binary, topic, service_name=None, endpoints=None):
super(RPCService, self).__init__()
self.host = host
self.binary = binary
self.topic = topic
self.service_name = service_name
# TODO(ekarlso): change this to be loadable via mod import or
# stevedore?
self.endpoints = endpoints or [self]
def start(self):
super(RPCService, self).start()
version_string = version.version_info.version_string()
LOG.info(_('Starting %(topic)s node (version %(version_string)s)') %
{'topic': self.topic, 'version_string': version_string})
LOG.debug(_("Creating RPC server on topic '%s'") % self.topic)
target = messaging.Target(topic=self.topic, server=self.host)
self.rpcserver = rpc.get_server(target, self.endpoints)
self.rpcserver.start()
self.notifier = rpc.get_notifier(self.service_name)
for e in self.endpoints:
if e != self and hasattr(e, 'start'):
e.start()
@classmethod
def create(cls, host=None, binary=None, topic=None, service_name=None,
endpoints=None):
"""Instantiates class and passes back application object.
:param host: defaults to CONF.host
:param binary: defaults to basename of executable
:param topic: defaults to bin_name - 'cinder-' part
"""
if not host:
host = CONF.host
if not binary:
binary = os.path.basename(inspect.stack()[-1][1])
if not topic:
name = "_".join(binary.split('-')[1:]) + '_topic'
topic = CONF.get(name)
service_obj = cls(host, binary, topic, service_name=service_name,
endpoints=endpoints)
return service_obj
def stop(self):
for e in self.endpoints:
if e != self and hasattr(e, 'stop'):
e.stop()
# Try to shut the connection down, but if we get any sort of
# errors, go ahead and ignore them.. as we're shutting down anyway
try:
self.rpcserver.stop()
except Exception:
pass
super(RPCService, self).stop()
def wait(self):
for e in self.endpoints:
if e != self and hasattr(e, 'wait'):
e.wait()
super(RPCService, self).wait()
class TCPService(Service):
"""
Service class to be used for a service that only works in TCP
"""
def __init__(self, host=None, binary=None, service_name=None,
endpoints=None, threads=1000):
super(TCPService, self).__init__(threads)
self.host = host
self.binary = binary
self.service_name = service_name
self.endpoints = endpoints or [self]
@classmethod
def create(cls, host=None, binary=None, service_name=None,
endpoints=None):
"""Instantiates class and passes back application object.
:param host: defaults to CONF.host
:param binary: defaults to basename of executable
"""
if not host:
host = CONF.host
if not binary:
binary = os.path.basename(inspect.stack()[-1][1])
service_obj = cls(host, binary, service_name=service_name,
endpoints=endpoints)
return service_obj
def start(self):
for e in self.endpoints:
if e != self and hasattr(e, 'start'):
e.start()
super(TCPService, self).start()
def stop(self):
for e in self.endpoints:
if e != self and hasattr(e, 'stop'):
e.stop()
super(TCPService, self).stop()
class WSGIService(wsgi.Service, Service):
"""
Service class to be shared by all Designate WSGI Services
"""
def __init__(self, application, port, host='0.0.0.0', backlog=4096,
threads=1000):
# NOTE(kiall): We avoid calling super(cls, self) here, as our parent
# classes have different argspecs. Additionally, if we
# manually call both parent's __init__, the openstack
# common Service class's __init__ method will be called
# twice. As a result, we only call the designate base
# Service's __init__ method, and duplicate the
# wsgi.Service's constructor functionality here.
#
Service.__init__(self, threads)
self.application = application
self._port = port
self._host = host
self._backlog = backlog if backlog else CONF.backlog
_launcher = None
def serve(server, workers=None):
global _launcher
if _launcher:
raise RuntimeError(_('serve() can only be called once'))
_launcher = service.launch(server, workers=workers)
def wait():
try:
_launcher.wait()
except KeyboardInterrupt:
_launcher.stop()
rpc.cleanup()