summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--designate/backend/agent_backend/impl_msdns.py113
-rw-r--r--designate/tests/unit/test_agent/test_backends/test_msdns.py122
-rw-r--r--devstack/designate_plugins/backend-agent-msdns116
-rw-r--r--doc/source/backends/msdns_agent.rst134
-rw-r--r--doc/source/sourcedoc/backend.rst10
-rw-r--r--doc/source/support-matrix.ini5
-rw-r--r--etc/designate/designate.conf.sample3
-rw-r--r--requirements.txt1
-rw-r--r--setup.cfg1
9 files changed, 505 insertions, 0 deletions
diff --git a/designate/backend/agent_backend/impl_msdns.py b/designate/backend/agent_backend/impl_msdns.py
new file mode 100644
index 00000000..949342fa
--- /dev/null
+++ b/designate/backend/agent_backend/impl_msdns.py
@@ -0,0 +1,113 @@
+# Copyright 2016 Cloudbase Solutions Srl
+# All Rights Reserved.
+#
+# Author: Alin Balutoiu <abalutoiu@cloudbasesolutions.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.
+
+from oslo_config import cfg
+from oslo_log import log as logging
+from os_win import utilsfactory
+from os_win import constants
+from os_win import exceptions as os_win_exc
+
+from designate.backend.agent_backend import base
+from designate import exceptions
+from designate.i18n import _LI
+
+
+LOG = logging.getLogger(__name__)
+CFG_GROUP = 'backend:agent:msdns'
+
+GROUP = cfg.OptGroup(
+ name=CFG_GROUP,
+ title="Configuration for Microsoft DNS Server"
+)
+OPTS = []
+
+
+class MSDNSBackend(base.AgentBackend):
+
+ __plugin_name__ = 'msdns'
+ __backend_status__ = 'experimental'
+
+ def __init__(self, agent_service):
+ """Configure the backend"""
+ super(MSDNSBackend, self).__init__(agent_service)
+
+ self._dnsutils = utilsfactory.get_dnsutils()
+
+ masters = cfg.CONF['service:agent'].masters
+ if not masters:
+ raise exceptions.Backend("Missing agent AXFR masters")
+ # Only ip addresses are needed
+ self._masters = [ns.split(":")[0] for ns in masters]
+
+ LOG.info(_LI("AXFR masters: %r"), self._masters)
+
+ @classmethod
+ def get_cfg_opts(cls):
+ return [(GROUP, OPTS)]
+
+ def start(self):
+ """Start the backend"""
+ LOG.info(_LI("Started msdns backend"))
+
+ def find_zone_serial(self, zone_name):
+ """Return the zone's serial"""
+ zone_name = zone_name.rstrip(".")
+ LOG.debug("Finding zone: %s" % zone_name)
+ try:
+ return self._dnsutils.get_zone_serial(zone_name)
+ except os_win_exc.DNSZoneNotFound:
+ # Return None if the zone was not found
+ return None
+
+ def create_zone(self, zone):
+ """Create a new DNS Zone"""
+ zone_name = zone.origin.to_text(omit_final_dot=True)
+ LOG.debug("Creating zone: %s" % zone_name)
+ try:
+ self._dnsutils.zone_create(
+ zone_name=zone_name,
+ zone_type=constants.DNS_ZONE_TYPE_SECONDARY,
+ ds_integrated=False,
+ ip_addrs=self._masters)
+ except os_win_exc.DNSZoneAlreadyExists:
+ # Zone already exists, check its properties to see if the
+ # existing zone is identical to the requested one
+ zone_properties = self._dnsutils.get_zone_properties(zone_name)
+
+ identical_zone_exists = (
+ zone_properties['zone_type'] == (
+ constants.DNS_ZONE_TYPE_SECONDARY) and
+ zone_properties['ds_integrated'] is False and
+ set(zone_properties['master_servers']) == set(self._masters))
+
+ if not identical_zone_exists:
+ raise
+
+ def update_zone(self, zone):
+ """Instruct MSDNS to request an AXFR from MiniDNS.
+ """
+ zone_name = zone.origin.to_text(omit_final_dot=True)
+ LOG.debug("Updating zone: %s" % zone_name)
+ self._dnsutils.zone_update(zone_name)
+
+ def delete_zone(self, zone_name):
+ """Delete a DNS Zone
+ Do not raise exception if the zone does not exist.
+ """
+ LOG.debug('Deleting zone: %s' % zone_name)
+ zone_name = zone_name.rstrip(".")
+ self._dnsutils.zone_delete(zone_name)
diff --git a/designate/tests/unit/test_agent/test_backends/test_msdns.py b/designate/tests/unit/test_agent/test_backends/test_msdns.py
new file mode 100644
index 00000000..ed798e5e
--- /dev/null
+++ b/designate/tests/unit/test_agent/test_backends/test_msdns.py
@@ -0,0 +1,122 @@
+# Copyright 2016 Cloudbase Solutions Srl
+# All Rights Reserved.
+#
+# Author: Alin Balutoiu <abalutoiu@cloudbasesolutions.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.
+
+"""
+ Unit-test the MSDNS agent backend
+"""
+
+import dns
+import mock
+from os_win import constants
+from os_win import exceptions as os_win_exc
+
+from designate.backend.agent_backend import impl_msdns
+from designate.tests import TestCase
+
+
+class MSDNSAgentBackendUnitTestCase(TestCase):
+
+ _FAKE_ZONE_NAME = 'example.com'
+
+ def setUp(self):
+ super(MSDNSAgentBackendUnitTestCase, self).setUp()
+ self.CONF.set_override('masters', ('127.0.0.1:5354',), 'service:agent')
+
+ patcher = mock.patch('os_win.utilsfactory.get_dnsutils')
+ self._dnsutils = patcher.start().return_value
+ self.addCleanup(patcher.stop)
+ self.backend = impl_msdns.MSDNSBackend('foo')
+
+ def _create_dnspy_zone(self, name):
+ zone_text = (
+ '$ORIGIN %(name)s\n%(name)s 3600 IN SOA %(ns)s '
+ 'email.email.com. 1421777854 3600 600 86400 3600\n%(name)s '
+ '3600 IN NS %(ns)s\n') % {'name': name, 'ns': 'ns1.designate.com'}
+
+ return dns.zone.from_text(zone_text, check_origin=False)
+
+ def test_init(self):
+ self.assertEqual(['127.0.0.1'], self.backend._masters)
+ self.assertEqual(self._dnsutils, self.backend._dnsutils)
+
+ def test_find_zone_serial(self):
+ serial = self.backend.find_zone_serial(self._FAKE_ZONE_NAME)
+
+ expected_serial = self._dnsutils.get_zone_serial.return_value
+ self.assertEqual(expected_serial, serial)
+ self._dnsutils.get_zone_serial.assert_called_once_with(
+ self._FAKE_ZONE_NAME)
+
+ def test_find_zone_serial_error(self):
+ self._dnsutils.get_zone_serial.side_effect = (
+ os_win_exc.DNSZoneNotFound(zone_name=self._FAKE_ZONE_NAME))
+
+ serial = self.backend.find_zone_serial(self._FAKE_ZONE_NAME)
+
+ self.assertIsNone(serial)
+ self._dnsutils.get_zone_serial.assert_called_once_with(
+ self._FAKE_ZONE_NAME)
+
+ def test_create_zone(self):
+ zone = self._create_dnspy_zone(self._FAKE_ZONE_NAME)
+
+ self.backend.create_zone(zone)
+
+ self._dnsutils.zone_create.assert_called_once_with(
+ zone_name=self._FAKE_ZONE_NAME,
+ zone_type=constants.DNS_ZONE_TYPE_SECONDARY,
+ ds_integrated=False,
+ ip_addrs=self.backend._masters)
+
+ def test_create_zone_already_existing_diff(self):
+ zone = self._create_dnspy_zone(self._FAKE_ZONE_NAME)
+ self._dnsutils.zone_create.side_effect = (
+ os_win_exc.DNSZoneAlreadyExists(zone_name=self._FAKE_ZONE_NAME))
+
+ self.assertRaises(os_win_exc.DNSZoneAlreadyExists,
+ self.backend.create_zone,
+ zone)
+ self._dnsutils.get_zone_properties.assert_called_once_with(
+ self._FAKE_ZONE_NAME)
+
+ def test_create_zone_already_existing_identical(self):
+ zone = self._create_dnspy_zone(self._FAKE_ZONE_NAME)
+ self._dnsutils.zone_create.side_effect = (
+ os_win_exc.DNSZoneAlreadyExists(zone_name=self._FAKE_ZONE_NAME))
+ mock_zone_properties = {'zone_type': constants.DNS_ZONE_TYPE_SECONDARY,
+ 'ds_integrated': False,
+ 'master_servers': self.backend._masters}
+ self._dnsutils.get_zone_properties.return_value = mock_zone_properties
+
+ self.backend.create_zone(zone)
+
+ self._dnsutils.get_zone_properties.assert_called_once_with(
+ self._FAKE_ZONE_NAME)
+
+ def test_update_zone(self):
+ zone = self._create_dnspy_zone(self._FAKE_ZONE_NAME)
+
+ self.backend.update_zone(zone)
+
+ self._dnsutils.zone_update.assert_called_once_with(
+ self._FAKE_ZONE_NAME)
+
+ def test_delete_zone(self):
+ self.backend.delete_zone(self._FAKE_ZONE_NAME)
+
+ self._dnsutils.zone_delete.assert_called_once_with(
+ self._FAKE_ZONE_NAME)
diff --git a/devstack/designate_plugins/backend-agent-msdns b/devstack/designate_plugins/backend-agent-msdns
new file mode 100644
index 00000000..1d459cef
--- /dev/null
+++ b/devstack/designate_plugins/backend-agent-msdns
@@ -0,0 +1,116 @@
+# Configure the agent backend
+
+# Enable this pluging by adding these line to local.conf:
+#
+# DESIGNATE_BACKEND_DRIVER=agent
+# DESIGNATE_AGENT_BACKEND_DRIVER=msdns
+
+# Dependencies:
+# ``functions`` file
+# ``designate`` configuration
+
+# install_designate_agent_backend - install any external requirements
+# configure_designate_agent_backend - make configuration changes, including those to other services
+# init_designate_agent_backend - initialize databases, etc.
+# start_designate_agent_backend - start any external services
+# stop_designate_agent_backend - stop any external services
+# cleanup_designate_agent_backend - remove transient data and cache
+
+# Save trace setting
+DP_AGENT_MSDNS_XTRACE=$(set +o | grep xtrace)
+set +o xtrace
+
+# Defaults
+# --------
+
+DESIGNATE_MSDNS_MASTERS=${DESIGNATE_MSDNS_MASTERS:-"$DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT_MDNS"}
+DESIGNATE_MSDNS_HOST_IP=${DESIGNATE_MSDNS_HOST_IP:-}
+DESIGNATE_MSDNS_HOST_PORT=${DESIGNATE_MSDNS_HOST_PORT:-}
+
+# Sanity Checks
+# -------------
+if [ -z "$DESIGNATE_MSDNS_MASTERS" ]; then
+ die $LINENO "You must configure DESIGNATE_MSDNS_MASTERS"
+fi
+
+if [ -z "$DESIGNATE_MSDNS_HOST_IP" ]; then
+ die $LINENO "You must configure DESIGNATE_MSDNS_HOST_IP with the IP of the MS DNS host"
+fi
+
+if [ -z "$DESIGNATE_MSDNS_HOST_PORT" ]; then
+ die $LINENO "You must configure DESIGNATE_MSDNS_HOST_PORT with the PORT of the MS DNS host"
+fi
+
+if [ "$DESIGNATE_SERVICE_PORT_MDNS" != "53" ]; then
+ die $LINENO "Microsoft DNS requires DESIGNATE_SERVICE_PORT_MDNS to be set to '53'"
+fi
+
+# Entry Points
+# ------------
+
+# install_designate_agent_backend - install any external requirements
+function install_designate_agent_backend {
+ :
+}
+
+# configure_designate_agent_backend - make configuration changes, including those to other services
+function configure_designate_agent_backend {
+ # Generate Designate pool.yaml file
+ sudo tee $DESIGNATE_CONF_DIR/pools.yaml > /dev/null <<EOF
+---
+- name: default
+ description: DevStack MSDNS Pool
+ attributes: {}
+
+ ns_records:
+ - hostname: $DESIGNATE_DEFAULT_NS_RECORD
+ priority: 1
+
+ nameservers:
+ - host: $DESIGNATE_MSDNS_HOST_IP
+ port: $DESIGNATE_MSDNS_HOST_PORT
+
+ targets:
+ - type: agent
+ description: MSDNS Agent Instance
+
+ masters:
+ - host: $DESIGNATE_SERVICE_HOST
+ port: $DESIGNATE_SERVICE_PORT_MDNS
+
+ options:
+ host: $DESIGNATE_MSDNS_HOST_IP
+ port: $DESIGNATE_MSDNS_HOST_PORT
+EOF
+
+ echo "# Sample Config for Windows Agent service" | sudo tee ${DESIGNATE_CONF}.win
+ echo "# This file should be copied to the Windows DNS server and used as the Designate config file" | sudo tee -a ${DESIGNATE_CONF}.win
+ # Configure Agent Settings
+ iniset ${DESIGNATE_CONF}.win service:agent backend_driver $DESIGNATE_AGENT_BACKEND_DRIVER
+ iniset ${DESIGNATE_CONF}.win service:agent host $DESIGNATE_MSDNS_HOST_IP
+ iniset ${DESIGNATE_CONF}.win service:agent port $DESIGNATE_MSDNS_HOST_PORT
+ iniset ${DESIGNATE_CONF}.win service:agent masters "$DESIGNATE_MSDNS_MASTERS"
+}
+
+# init_designate_agent_backend - initialize databases, etc.
+function init_designate_agent_backend {
+ :
+}
+
+# start_designate_agent_backend - start any external services
+function start_designate_agent_backend {
+ :
+}
+
+# stop_designate_agent_backend - stop any external services
+function stop_designate_agent_backend {
+ :
+}
+
+# cleanup_designate_agent_backend - remove transient data and cache
+function cleanup_designate_agent_backend {
+ :
+}
+
+# Restore xtrace
+$DP_AGENT_MSDNS_XTRACE
diff --git a/doc/source/backends/msdns_agent.rst b/doc/source/backends/msdns_agent.rst
new file mode 100644
index 00000000..3f2976e6
--- /dev/null
+++ b/doc/source/backends/msdns_agent.rst
@@ -0,0 +1,134 @@
+..
+ Copyright 2016 Cloudbase Solutions Srl
+
+ Author: Alin Balutoiu <abalutoiu@cloudbasesolutions.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.
+
+MSDNS Agent Backend
+*******************
+
+MSDNS User Documentation
+========================
+
+This page documents using the MSDNS Agent backend.
+
+The agent runs on the Windows host where the Microsoft DNS Server feature
+is installed. It receives DNS messages from Mini DNS using private
+DNS OPCODEs and classes and creates or deletes zones using WMI calls.
+
+It also instructs MSDNS to request AXFR from MiniDNS when a zone is created
+or updated.
+
+`Microsoft DNS documentation for managing DNS zones
+<https://msdn.microsoft.com/en-us/library/windows/desktop/ms682757.aspx>`_
+
+Setting up the Microsoft DNS server on Windows Server
+-----------------------------------------------------
+
+The DNS Server role can be installed on the system by following the
+documentation available here:
+`How to install the DNS Server role
+<https://technet.microsoft.com/en-us/library/cc725925.aspx>`_
+
+Configuring MSDNS
+-----------------
+
+Assuming the DNS Server role has been installed on the system, follow the
+next steps to complete the configuration.
+
+These steps are for the Windows host which will run the designate agent.
+Make sure that Python 2.7 or Python 3.4 is installed on the system already.
+
+To install Designate, clone the repository from https://github.com/openstack/designate
+and do a pip install. Example:
+
+.. code-block:: powershell
+
+ git clone https://github.com/openstack/designate
+ pip install .\\designate
+
+After that, we need to configure the Designate Agent. Inside the github repository,
+there is a folder named "etc/designate" which can be used as default configuration.
+
+Copy the folder somewhere else, for this example we will copy it to C:\\etc\\designate
+Inside the configuration folder, make a copy of designate.conf.sample and rename
+the copy to designate.conf
+Example:
+
+.. code-block:: powershell
+
+ copy C:\\etc\\designate\\designate.conf.sample C:\\etc\\designate\\designate.conf
+
+
+Configure the "service.agent" and "backend.agent.msdns" sections in
+C:\\etc\\designate\\designate.conf
+
+Look in C:\\etc\\designate\\designate.conf.example for more complete examples.
+
+.. code-block:: ini
+
+ [service:agent]
+ backend_driver = msdns
+ # Place here the MiniDNS ipaddr and port (no the agent itself)
+ masters = <MiniDNS IP addr>:53
+
+Ensure that "policy_file" under the [default] section is set:
+
+.. code-block:: ini
+
+ policy_file = C:\\etc\\designate\\policy.json
+
+Start the designate agent using (Python 2.7 was installed in the default location C:\\Python27):
+
+.. code-block:: powershell
+
+ C:\\Python27\\Scripts\\designate-agent.exe --config-file 'C:\\etc\\designate\\designate.conf'
+
+You should see log messages similar to:
+
+.. code-block:: powershell
+
+ 2016-06-22 02:00:47.177 3436 INFO designate.backend.agent_backend.impl_msdns [-] Started msdns backend
+ 2016-06-22 02:00:47.177 3436 INFO designate.service [-] _handle_tcp thread started
+ 2016-06-22 02:00:47.177 3436 INFO designate.service [-] _handle_udp thread started
+
+
+The following steps are for the system running the Designate controller.
+
+Make sure to set the mDNS port to 53 in the ``[service:mdns]`` section.
+MS DNS does not support Masters that are on any port other than 53.
+
+Create an agent pool:
+
+.. code-block:: bash
+
+ # Fetch the existing pool(s) if needed or start from scratch
+ designate-manage pool generate_file --file /tmp/pool.yaml
+ # Edit the file (see below) and reload it as:
+ designate-manage pool update --file /tmp/pool.yaml
+
+The "targets" section in pool.yaml should look like:
+
+.. code-block:: ini
+
+ targets:
+ - description: Microsoft DNS agent
+ masters:
+ - host: <MiniDNS IP addr>
+ port: 53
+ options: {}
+ options:
+ - host: <Agent IP addr>
+ port: 5358
+ type: agent
diff --git a/doc/source/sourcedoc/backend.rst b/doc/source/sourcedoc/backend.rst
index 4c6594cf..abdc9df1 100644
--- a/doc/source/sourcedoc/backend.rst
+++ b/doc/source/sourcedoc/backend.rst
@@ -106,3 +106,13 @@ Agent Backend Djbdns
:private-members:
:undoc-members:
:show-inheritance:
+
+Agent Backend MSDNS
+====================
+
+.. automodule:: designate.backend.agent_backend.impl_msdns
+ :members:
+ :special-members:
+ :private-members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/doc/source/support-matrix.ini b/doc/source/support-matrix.ini
index da5c3fa9..92c7466b 100644
--- a/doc/source/support-matrix.ini
+++ b/doc/source/support-matrix.ini
@@ -56,6 +56,8 @@ backend-impl-denominator=Denominator
backend-impl-knot2-agent=Knot2 (Agent)
backend-impl-djbdns-agent=Djbdns (Agent)
backend-impl-gdnsd-agent=Gdnsd (Agent)
+backend-impl-msdns-agent=Microsoft DNS (Agent)
+
[backends.backend-impl-bind9]
@@ -95,6 +97,9 @@ maintainers=Infoblox OpenStack Team <openstack-maintainer@infoblox.com>
[backends.backend-impl-denominator]
type=agent
+[backends.backend-impl-msdns-agent]
+type=agent
+
[grades]
valid-grades=integrated,master-compatible,release-compatible,untested,failing,known-broken,experimental
diff --git a/etc/designate/designate.conf.sample b/etc/designate/designate.conf.sample
index 6870f8fc..7ad60f15 100644
--- a/etc/designate/designate.conf.sample
+++ b/etc/designate/designate.conf.sample
@@ -492,6 +492,9 @@ debug = False
#confdir_path = /etc/gdnsd
#query_destination = 127.0.0.1
+[backend:agent:msdns]
+#query_destination = 127.0.0.1
+
########################
## Library Configuration
########################
diff --git a/requirements.txt b/requirements.txt
index 722fdd24..96031f99 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -47,3 +47,4 @@ Werkzeug>=0.7 # BSD License
python-memcached>=1.56 # PSF
tooz>=1.28.0 # Apache-2.0
debtcollector>=1.2.0 # Apache-2.0
+os-win>=0.2.3 # Apache-2.0
diff --git a/setup.cfg b/setup.cfg
index c1db2076..cd7512f5 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -98,6 +98,7 @@ designate.backend.agent_backend =
denominator = designate.backend.agent_backend.impl_denominator:DenominatorBackend
fake = designate.backend.agent_backend.impl_fake:FakeBackend
gdnsd = designate.backend.agent_backend.impl_gdnsd:GdnsdBackend
+ msdns = designate.backend.agent_backend.impl_msdns:MSDNSBackend
designate.network_api =
fake = designate.network_api.fake:FakeNetworkAPI