
As these are converted to PoolBackends, we'll move them back into the codebase. Change-Id: Id004c39d92940d706cd8f86ab00bfcac0b0f3098
141 lines
4.9 KiB
Python
141 lines
4.9 KiB
Python
# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
|
|
#
|
|
# Author: Artom Lifshitz <artom.lifshitz@enovance.com>
|
|
#
|
|
# 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 oslo_log import log as logging
|
|
|
|
from designate import exceptions
|
|
from designate import utils
|
|
from designate.backend import base
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
CFG_GROUP = 'backend:nsd4slave'
|
|
DEFAULT_PORT = 8952
|
|
|
|
|
|
class NSD4SlaveBackend(base.Backend):
|
|
__plugin__name__ = 'nsd4slave'
|
|
NSDCT_VERSION = 'NSDCT1'
|
|
|
|
@classmethod
|
|
def get_cfg_opts(cls):
|
|
group = cfg.OptGroup(
|
|
name=CFG_GROUP, title="Configuration for NSD4-slave backend"
|
|
)
|
|
|
|
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 '
|
|
' <host>:<port> format. If <port> 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.'),
|
|
]
|
|
|
|
return [(group, opts)]
|
|
|
|
def __init__(self, central_service):
|
|
self._keyfile = cfg.CONF[CFG_GROUP].keyfile
|
|
self._certfile = cfg.CONF[CFG_GROUP].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_GROUP].pattern
|
|
try:
|
|
self._servers = [self._parse_server(cfg_server)
|
|
for cfg_server in cfg.CONF[CFG_GROUP].servers]
|
|
except TypeError:
|
|
raise exceptions.ConfigurationError('No NSD4 servers defined')
|
|
|
|
def _parse_server(self, cfg_server):
|
|
try:
|
|
(host, port) = utils.split_host_port(cfg_server)
|
|
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 create_recordset(self, context, domain, recordset):
|
|
pass
|
|
|
|
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
|