# Copyright (C) 2013 eNovance SAS # # Author: Artom Lifshitz # # 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 socket import ssl import eventlet from oslo.config import cfg from designate import exceptions from designate.backend import base from designate.openstack.common import log as logging LOG = logging.getLogger(__name__) CFG_GRP = 'backend:nsd4slave' cfg.CONF.register_group( cfg.OptGroup(name=CFG_GRP, title='Configuration for NSD4-slave backend') ) cfg.CONF.register_opts([ cfg.StrOpt('keyfile', default='/etc/nsd/nsd_control.key', help='Keyfile to use when connecting to the NSD4 servers over ' 'SSL'), cfg.StrOpt('certfile', default='/etc/nsd/nsd_control.pem', help='Certfile to use when connecting to the NSD4 servers over ' 'SSL'), cfg.ListOpt('servers', help='Comma-separated list of servers to control, in ' ' : format. If is omitted, ' ' the default 8952 is used.'), cfg.StrOpt('pattern', default='slave', help='Pattern to use when creating zones on the NSD4 servers. ' 'This pattern must be identically configured on all NSD4 ' 'servers.'), ], group=CFG_GRP) DEFAULT_PORT = 8952 class NSD4SlaveBackend(base.Backend): __plugin__name__ = 'nsd4slave' NSDCT_VERSION = 'NSDCT1' def __init__(self, central_service): self._keyfile = cfg.CONF[CFG_GRP].keyfile self._certfile = cfg.CONF[CFG_GRP].certfile # Make sure keyfile and certfile are readable to avoid cryptic SSL # errors later if not os.access(self._keyfile, os.R_OK): raise exceptions.NSD4SlaveBackendError( 'Keyfile %s missing or permission denied' % self._keyfile) if not os.access(self._certfile, os.R_OK): raise exceptions.NSD4SlaveBackendError( 'Certfile %s missing or permission denied' % self._certfile) self._pattern = cfg.CONF[CFG_GRP].pattern try: self._servers = [self._parse_server(cfg_server) for cfg_server in cfg.CONF[CFG_GRP].servers] except TypeError: raise exceptions.ConfigurationError('No NSD4 servers defined') def _parse_server(self, cfg_server): try: (host, port) = cfg_server.split(':') port = int(port) except ValueError: host = str(cfg_server) port = DEFAULT_PORT return {'host': host, 'port': port} def create_domain(self, context, domain): command = 'addzone %s %s' % (domain['name'], self._pattern) self._all_servers(command) def update_domain(self, context, domain): pass def delete_domain(self, context, domain): command = 'delzone %s' % domain['name'] self._all_servers(command) def _all_servers(self, command): for server in self._servers: try: result = self._command(command, server['host'], server['port']) except (ssl.SSLError, socket.error) as e: raise exceptions.NSD4SlaveBackendError(e) if result != 'ok': raise exceptions.NSD4SlaveBackendError(result) def _command(self, command, host, port): sock = eventlet.wrap_ssl(eventlet.connect((host, port)), keyfile=self._keyfile, certfile=self._certfile) stream = sock.makefile() stream.write('%s %s\n' % (self.NSDCT_VERSION, command)) stream.flush() result = stream.read() stream.close() sock.close() return result.rstrip() def update_recordset(self, context, domain, recordset): pass def delete_recordset(self, context, domain, recordset): pass def create_record(self, context, domain, recordset, record): pass def update_record(self, context, domain, recordset, record): pass def delete_record(self, context, domain, recordset, record): pass def create_server(self, context, server): pass def update_server(self, context, server): pass def delete_server(self, context, server): pass