Browse Source

Enable use of Pools YAML

This change adds the tooling to use the DB Tables created for pool
config data and the tooling to migrate the config info itself.

Change-Id: If99dbf527ef1ac0f05f15fe77f68f64e357fe0a5
Kiall Mac Innes 3 years ago
parent
commit
e612a3974f
44 changed files with 1970 additions and 306 deletions
  1. 16
    0
      designate/api/v2/controllers/pools.py
  2. 156
    8
      designate/manage/pool.py
  3. 36
    17
      designate/manage/powerdns.py
  4. 11
    0
      designate/objects/adapters/__init__.py
  5. 0
    0
      designate/objects/adapters/yaml/__init__.py
  6. 81
    0
      designate/objects/adapters/yaml/base.py
  7. 59
    0
      designate/objects/adapters/yaml/pool.py
  8. 41
    0
      designate/objects/adapters/yaml/pool_also_notify.py
  9. 86
    0
      designate/objects/adapters/yaml/pool_attribute.py
  10. 41
    0
      designate/objects/adapters/yaml/pool_nameserver.py
  11. 41
    0
      designate/objects/adapters/yaml/pool_ns_record.py
  12. 50
    0
      designate/objects/adapters/yaml/pool_target.py
  13. 41
    0
      designate/objects/adapters/yaml/pool_target_master.py
  14. 86
    0
      designate/objects/adapters/yaml/pool_target_option.py
  15. 26
    3
      designate/objects/pool_also_notify.py
  16. 26
    3
      designate/objects/pool_nameserver.py
  17. 25
    4
      designate/objects/pool_target.py
  18. 26
    3
      designate/objects/pool_target_master.py
  19. 25
    3
      designate/objects/pool_target_option.py
  20. 30
    9
      designate/pool_manager/service.py
  21. 8
    3
      designate/tests/__init__.py
  22. 63
    0
      designate/tests/resources/pools_yaml/multiple-pools.yaml
  23. 32
    0
      designate/tests/resources/pools_yaml/pools.yaml
  24. 25
    0
      designate/tests/resources/pools_yaml/sample_output.yaml
  25. 43
    0
      designate/tests/test_pool_manager/__init__.py
  26. 17
    57
      designate/tests/test_pool_manager/test_service.py
  27. 25
    13
      designate/tests/test_storage/__init__.py
  28. 156
    0
      designate/tests/unit/test_objects/test_yaml_adapters.py
  29. 58
    7
      designate/tests/unit/test_pool_manager/test_service.py
  30. 58
    24
      devstack/designate_plugins/backend-akamai
  31. 31
    9
      devstack/designate_plugins/backend-bind9
  32. 58
    32
      devstack/designate_plugins/backend-dynect
  33. 15
    1
      devstack/designate_plugins/backend-fake
  34. 28
    9
      devstack/designate_plugins/backend-infoblox
  35. 0
    77
      devstack/designate_plugins/backend-ipa
  36. 34
    10
      devstack/designate_plugins/backend-powerdns
  37. 12
    13
      devstack/plugin.sh
  38. 0
    1
      devstack/settings
  39. 61
    0
      doc/source/pools.rst
  40. 94
    0
      doc/source/upgrade/mitaka.rst
  41. 54
    0
      etc/designate/pools.yaml.sample
  42. 66
    0
      etc/designate/pools.yaml.sample-bind
  43. 115
    0
      etc/designate/pools.yaml.sample-multiple-pools
  44. 14
    0
      releasenotes/notes/pool-config-db-45a2cad74e22d95e.yaml

+ 16
- 0
designate/api/v2/controllers/pools.py View File

@@ -16,6 +16,7 @@ import pecan
16 16
 from oslo_log import log as logging
17 17
 
18 18
 from designate import utils
19
+from designate.i18n import _LW
19 20
 from designate.api.v2.controllers import rest
20 21
 from designate.objects import Pool
21 22
 from designate.objects.adapters import DesignateAdapter
@@ -63,6 +64,11 @@ class PoolsController(rest.RestController):
63 64
     @pecan.expose(template='json:', content_type='application/json')
64 65
     def post_all(self):
65 66
         """Create a Pool"""
67
+
68
+        LOG.warning(_LW("Use of this API Method is DEPRICATED. This will have "
69
+                        "unforseen side affects when used with the "
70
+                        "designate-manage pool commands"))
71
+
66 72
         request = pecan.request
67 73
         response = pecan.response
68 74
         context = request.environ['context']
@@ -86,6 +92,11 @@ class PoolsController(rest.RestController):
86 92
     @utils.validate_uuid('pool_id')
87 93
     def patch_one(self, pool_id):
88 94
         """Update the specific pool"""
95
+
96
+        LOG.warning(_LW("Use of this API Method is DEPRICATED. This will have "
97
+                        "unforseen side affects when used with the "
98
+                        "designate-manage pool commands"))
99
+
89 100
         request = pecan.request
90 101
         context = request.environ['context']
91 102
         body = request.body_dict
@@ -111,6 +122,11 @@ class PoolsController(rest.RestController):
111 122
     @utils.validate_uuid('pool_id')
112 123
     def delete_one(self, pool_id):
113 124
         """Delete the specific pool"""
125
+
126
+        LOG.warning(_LW("Use of this API Method is DEPRICATED. This will have "
127
+                        "unforseen side affects when used with the "
128
+                        "designate-manage pool commands"))
129
+
114 130
         request = pecan.request
115 131
         response = pecan.response
116 132
         context = request.environ['context']

+ 156
- 8
designate/manage/pool.py View File

@@ -13,24 +13,172 @@
13 13
 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 14
 # License for the specific language governing permissions and limitations
15 15
 # under the License.
16
-import pprint
17
-
16
+import yaml
18 17
 from oslo_config import cfg
19 18
 from oslo_log import log as logging
19
+import oslo_messaging as messaging
20 20
 
21
-from designate.manage import base
21
+from designate import exceptions
22
+from designate import rpc
23
+from designate.i18n import _LI
24
+from designate.i18n import _LC
22 25
 from designate import objects
26
+from designate.central import rpcapi as central_rpcapi
27
+from designate.manage import base
28
+from designate.objects.adapters import DesignateAdapter
23 29
 
24 30
 LOG = logging.getLogger(__name__)
31
+
32
+
25 33
 CONF = cfg.CONF
26 34
 
27 35
 
28 36
 class PoolCommands(base.Commands):
37
+    def __init__(self):
38
+        super(PoolCommands, self).__init__()
39
+        rpc.init(cfg.CONF)
40
+        self.central_api = central_rpcapi.CentralAPI()
41
+
42
+    @base.args('--file', help='The path to the file the yaml output should be '
43
+               'writen to',
44
+               default='/etc/designate/pools.yaml')
45
+    def generate_file(self, file):
46
+        try:
47
+            pools = self.central_api.find_pools(self.context)
48
+        except messaging.exceptions.MessagingTimeout:
49
+            LOG.critical(_LC("No response recieved from designate-central. "
50
+                             "Check it is running, and retry"))
51
+        with open(file, 'w') as stream:
52
+            yaml.dump(
53
+                DesignateAdapter.render('YAML', pools),
54
+                stream,
55
+                default_flow_style=False
56
+            )
57
+
58
+    @base.args('--file', help='The path to the file the yaml output should be '
59
+               'writen to',
60
+               default='/etc/designate/pools.yaml')
61
+    def export_from_config(self, file):
62
+        try:
63
+            pools = self.central_api.find_pools(self.context)
64
+        except messaging.exceptions.MessagingTimeout:
65
+            LOG.critical(_LC("No response recieved from designate-central. "
66
+                             "Check it is running, and retry"))
67
+        r_pools = objects.PoolList()
68
+        for pool in pools:
69
+            r_pool = objects.Pool.from_config(CONF, pool.id)
70
+            r_pool.id = pool.id
71
+            r_pool.ns_records = pool.ns_records
72
+            r_pool.attributes = pool.attributes
73
+            r_pools.append(r_pool)
74
+        with open(file, 'w') as stream:
75
+            yaml.dump(
76
+                DesignateAdapter.render('YAML', r_pools),
77
+                stream,
78
+                default_flow_style=False
79
+            )
29 80
 
30 81
     @base.args('--pool_id', help='ID of the pool to be examined',
31
-        default=CONF['service:central'].default_pool_id)
82
+               default=CONF['service:central'].default_pool_id)
32 83
     def show_config(self, pool_id):
33
-        print('*' * 100)
34
-        print('Pool Configuration:')
35
-        print('*' * 100)
36
-        pprint.pprint(objects.Pool.from_config(CONF, pool_id).to_dict())
84
+        try:
85
+            pool = self.central_api.find_pool(self.context, {"id": pool_id})
86
+
87
+            print('Pool Configuration:')
88
+            print('-------------------')
89
+
90
+            print(yaml.dump(DesignateAdapter.render('YAML', pool),
91
+                  default_flow_style=False))
92
+
93
+        except messaging.exceptions.MessagingTimeout:
94
+            LOG.critical(_LC("No response recieved from designate-central. "
95
+                             "Check it is running, and retry"))
96
+
97
+    @base.args('--file', help='The path to the yaml file describing the pools',
98
+               default='/etc/designate/pools.yaml')
99
+    @base.args(
100
+        '--delete',
101
+        help='Any Pools not listed in the config file will be deleted. '
102
+             ' WARNING: This will delete any zones left in this pool',
103
+        default=False)
104
+    @base.args(
105
+        '--dry_run',
106
+        help='This will simulate what will happen when you run this command',
107
+        default=False)
108
+    def update(self, file, delete, dry_run):
109
+        print('Updating Pools Configuration')
110
+        print('****************************')
111
+
112
+        output_msg = ['']
113
+
114
+        with open(file, 'r') as stream:
115
+            xpools = yaml.safe_load(stream)
116
+
117
+        if dry_run:
118
+            output_msg.append("The following changes will occur:")
119
+            output_msg.append("*********************************")
120
+
121
+        for xpool in xpools:
122
+            try:
123
+                if 'id' in xpool:
124
+                    try:
125
+                        pool = self.central_api.get_pool(
126
+                            self.context, xpool['id'])
127
+                    except Exception:
128
+                        LOG.critical(
129
+                            _LC("Bad ID Supplied for pool %s"), xpool['name'])
130
+                        continue
131
+                else:
132
+                    pool = self.central_api.find_pool(
133
+                        self.context, {"name": xpool['name']})
134
+
135
+                LOG.info(_LI('Updating existing pool: %s'), pool)
136
+
137
+                # TODO(kiall): Move the below into the pool object
138
+
139
+                pool = DesignateAdapter.parse('YAML', xpool, pool)
140
+
141
+                if dry_run:
142
+                    output_msg.append("Update Pool: %s" % pool)
143
+                else:
144
+                    pool = self.central_api.update_pool(self.context, pool)
145
+
146
+            except exceptions.PoolNotFound:
147
+                pool = DesignateAdapter.parse('YAML', xpool, objects.Pool())
148
+                # pool = objects.Pool.from_dict(xpool)
149
+                if dry_run:
150
+                    output_msg.append("Create Pool: %s" % pool)
151
+                else:
152
+                    LOG.info(_LI('Creating new pool: %s'), pool)
153
+                    self.central_api.create_pool(self.context, pool)
154
+            except messaging.exceptions.MessagingTimeout:
155
+                LOG.critical(_LC("No response recieved from designate-central."
156
+                                 " Check it is running, and retry"))
157
+
158
+        if delete:
159
+            pools = self.central_api.find_pools(self.context)
160
+            pools_in_db = {pool.name for pool in pools}
161
+            pools_in_yaml = {xpool['name'] for xpool in xpools}
162
+
163
+            pools_to_delete = pools_in_db - pools_in_yaml
164
+
165
+            for pool in pools_to_delete:
166
+                try:
167
+                    p = self.central_api.find_pool(
168
+                        self.context,
169
+                        criterion={'name': pool})
170
+
171
+                    if dry_run:
172
+                        output_msg.append("Delete Pool: %s" % p)
173
+
174
+                    else:
175
+                        LOG.info(_LI('Deleting %s'), p)
176
+                        self.central_api.delete_pool(self.context, p.id)
177
+
178
+                except messaging.exceptions.MessagingTimeout:
179
+                    LOG.critical(_LC("No response recieved from "
180
+                                     "designate-central. "
181
+                                     "Check it is running, and retry"))
182
+
183
+        for line in output_msg:
184
+            print(line)

+ 36
- 17
designate/manage/powerdns.py View File

@@ -21,7 +21,9 @@ from oslo_db.sqlalchemy.migration_cli import manager as migration_manager
21 21
 from oslo_log import log as logging
22 22
 
23 23
 from designate.manage import base
24
+from designate import rpc
24 25
 from designate import utils
26
+from designate.central import rpcapi as central_rpcapi
25 27
 
26 28
 LOG = logging.getLogger(__name__)
27 29
 
@@ -32,33 +34,50 @@ CONF = cfg.CONF
32 34
 utils.register_plugin_opts()
33 35
 
34 36
 
35
-def get_manager(pool_target_id):
36
-    pool_target_options = CONF['pool_target:%s' % pool_target_id].options
37
-    connection = pool_target_options['connection']
37
+def get_manager(pool_target):
38
+    connection = pool_target.options.get('connection', None)
38 39
 
39 40
     migration_config = {
40 41
         'migration_repo_path': REPOSITORY,
41 42
         'db_url': connection}
43
+
42 44
     return migration_manager.MigrationManager(migration_config)
43 45
 
44 46
 
45 47
 class DatabaseCommands(base.Commands):
46
-    @base.args('pool-target-id', help="Pool Target to Migrate", type=str)
47
-    def version(self, pool_target_id):
48
-        current = get_manager(pool_target_id).version()
49
-        latest = versioning_api.version(repository=REPOSITORY).value
50
-        print("Current: %s Latest: %s" % (current, latest))
48
+    def __init__(self):
49
+        super(DatabaseCommands, self).__init__()
50
+        rpc.init(cfg.CONF)
51
+        self.central_api = central_rpcapi.CentralAPI()
52
+
53
+    @base.args('pool-id', help="Pool to Migrate", type=str)
54
+    def version(self, pool_id):
55
+        pool = self.central_api.find_pool(self.context, {"id": pool_id})
56
+
57
+        for pool_target in pool.targets:
58
+            current = get_manager(pool_target).version()
59
+            latest = versioning_api.version(repository=REPOSITORY).value
60
+            print("Current: %s Latest: %s" % (current, latest))
51 61
 
52
-    @base.args('pool-target-id', help="Pool Target to Migrate", type=str)
53
-    def sync(self, pool_target_id):
54
-        get_manager(pool_target_id).upgrade(None)
62
+    @base.args('pool-id', help="Pool to Migrate", type=str)
63
+    def sync(self, pool_id):
64
+        pool = self.central_api.find_pool(self.context, {"id": pool_id})
55 65
 
56
-    @base.args('pool-target-id', help="Pool Target to Migrate", type=str)
66
+        for pool_target in pool.targets:
67
+            get_manager(pool_target).upgrade(None)
68
+
69
+    @base.args('pool-id', help="Pool to Migrate", type=str)
57 70
     @base.args('revision', nargs='?')
58
-    def upgrade(self, pool_target_id, revision):
59
-        get_manager(pool_target_id).upgrade(revision)
71
+    def upgrade(self, pool_id, revision):
72
+        pool = self.central_api.find_pool(self.context, {"id": pool_id})
73
+
74
+        for pool_target in pool.targets:
75
+            get_manager(pool_target).upgrade(revision)
60 76
 
61
-    @base.args('pool-target-id', help="Pool Target to Migrate", type=str)
77
+    @base.args('pool-id', help="Pool to Migrate", type=str)
62 78
     @base.args('revision', nargs='?')
63
-    def downgrade(self, pool_target_id, revision):
64
-        get_manager(pool_target_id).downgrade(revision)
79
+    def downgrade(self, pool_id, revision):
80
+        pool = self.central_api.find_pool(self.context, {"id": pool_id})
81
+
82
+        for pool_target in pool.targets:
83
+            get_manager(pool_target).downgrade(revision)

+ 11
- 0
designate/objects/adapters/__init__.py View File

@@ -32,3 +32,14 @@ from designate.objects.adapters.api_v2.zone_transfer_request import ZoneTransfer
32 32
 from designate.objects.adapters.api_v2.validation_error import ValidationErrorAPIv2Adapter, ValidationErrorListAPIv2Adapter  # noqa
33 33
 from designate.objects.adapters.api_v2.zone_import import ZoneImportAPIv2Adapter, ZoneImportListAPIv2Adapter  # noqa
34 34
 from designate.objects.adapters.api_v2.zone_export import ZoneExportAPIv2Adapter, ZoneExportListAPIv2Adapter  # noqa
35
+
36
+# YAML
37
+
38
+from designate.objects.adapters.yaml.pool import PoolYAMLAdapter, PoolListYAMLAdapter  # noqa
39
+from designate.objects.adapters.yaml.pool_attribute import PoolAttributeYAMLAdapter, PoolAttributeListYAMLAdapter  # noqa
40
+from designate.objects.adapters.yaml.pool_also_notify import PoolAlsoNotifyYAMLAdapter, PoolAlsoNotifyListYAMLAdapter  # noqa
41
+from designate.objects.adapters.yaml.pool_nameserver import PoolNameserverYAMLAdapter, PoolNameserverListYAMLAdapter  # noqa
42
+from designate.objects.adapters.yaml.pool_ns_record import PoolNsRecordYAMLAdapter, PoolNsRecordListYAMLAdapter  # noqa
43
+from designate.objects.adapters.yaml.pool_target import PoolTargetYAMLAdapter, PoolTargetListYAMLAdapter  # noqa
44
+from designate.objects.adapters.yaml.pool_target_master import PoolTargetMasterYAMLAdapter, PoolTargetMasterListYAMLAdapter  # noqa
45
+from designate.objects.adapters.yaml.pool_target_option import PoolTargetOptionYAMLAdapter, PoolTargetOptionListYAMLAdapter  # noqa

+ 0
- 0
designate/objects/adapters/yaml/__init__.py View File


+ 81
- 0
designate/objects/adapters/yaml/base.py View File

@@ -0,0 +1,81 @@
1
+# Copyright 2016 Hewlett Packard Enterprise Development Company, L.P.
2
+#
3
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+#    not use this file except in compliance with the License. You may obtain
5
+#    a copy of the License at
6
+#
7
+#         http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+#    Unless required by applicable law or agreed to in writing, software
10
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+#    License for the specific language governing permissions and limitations
13
+#    under the License.
14
+from oslo_log import log as logging
15
+
16
+from designate.objects.adapters import base
17
+
18
+LOG = logging.getLogger(__name__)
19
+
20
+
21
+class YAMLAdapter(base.DesignateAdapter):
22
+
23
+    ADAPTER_FORMAT = 'YAML'
24
+
25
+    #####################
26
+    #  Parsing methods  #
27
+    #####################
28
+
29
+    @classmethod
30
+    def parse(cls, values, output_object, *args, **kwargs):
31
+        obj = super(YAMLAdapter, cls).parse(
32
+            cls.ADAPTER_FORMAT, values, output_object, *args, **kwargs)
33
+        return obj
34
+
35
+    @classmethod
36
+    def _render_object(cls, object, *args, **kwargs):
37
+        # The dict we will return to be rendered to JSON / output format
38
+        r_obj = {}
39
+        # Loop over all fields that are supposed to be output
40
+        for key, value in cls.MODIFICATIONS['fields'].items():
41
+            # Get properties for this field
42
+            field_props = cls.MODIFICATIONS['fields'][key]
43
+            # Check if it has to be renamed
44
+            if field_props.get('rename', False):
45
+                obj = getattr(object, field_props.get('rename'))
46
+                # if rename is specified we need to change the key
47
+                obj_key = field_props.get('rename')
48
+            else:
49
+                # if not, move on
50
+                obj = getattr(object, key, None)
51
+                obj_key = key
52
+            # Check if this item is a relation (another DesignateObject that
53
+            # will need to be converted itself
54
+            if object.FIELDS.get(obj_key, {}).get('relation'):
55
+                # Get a adapter for the nested object
56
+                # Get the class the object is and get its adapter, then set
57
+                # the item in the dict to the output
58
+                r_obj[key] = cls.get_object_adapter(
59
+                    cls.ADAPTER_FORMAT,
60
+                    object.FIELDS[obj_key].get('relation_cls')).render(
61
+                        cls.ADAPTER_FORMAT, obj, *args, **kwargs)
62
+            elif object.FIELDS.get(
63
+                    obj_key, {}).get('schema', {}).get('type') == 'integer':
64
+                r_obj[key] = int(obj)
65
+            elif obj is not None:
66
+                # Just attach the damn item if there is no weird edge cases
67
+                r_obj[key] = str(obj)
68
+        # Send it back
69
+        return r_obj
70
+
71
+    @classmethod
72
+    def _render_list(cls, list_object, *args, **kwargs):
73
+        # The list we will return to be rendered to JSON / output format
74
+        r_list = []
75
+        # iterate and convert each DesignateObject in the list, and append to
76
+        # the object we are returning
77
+        for object in list_object:
78
+            r_list.append(cls.get_object_adapter(
79
+                cls.ADAPTER_FORMAT,
80
+                object).render(cls.ADAPTER_FORMAT, object, *args, **kwargs))
81
+        return r_list

+ 59
- 0
designate/objects/adapters/yaml/pool.py View File

@@ -0,0 +1,59 @@
1
+# Copyright 2014 Hewlett-Packard Development Company, L.P.
2
+#
3
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+#    not use this file except in compliance with the License. You may obtain
5
+#    a copy of the License at
6
+#
7
+#         http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+#    Unless required by applicable law or agreed to in writing, software
10
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+#    License for the specific language governing permissions and limitations
13
+#    under the License.
14
+from oslo_log import log as logging
15
+
16
+from designate.objects.adapters.yaml import base
17
+from designate import objects
18
+LOG = logging.getLogger(__name__)
19
+
20
+
21
+class PoolYAMLAdapter(base.YAMLAdapter):
22
+
23
+    ADAPTER_OBJECT = objects.Pool
24
+
25
+    MODIFICATIONS = {
26
+        'fields': {
27
+            'id': {
28
+                'read_only': False
29
+            },
30
+            'name': {
31
+                'read_only': False
32
+            },
33
+            'description': {
34
+                'read_only': False
35
+            },
36
+            'attributes': {
37
+                'read_only': False
38
+            },
39
+            'ns_records': {
40
+                'read_only': False
41
+            },
42
+            'nameservers': {
43
+                'read_only': False
44
+            },
45
+            'targets': {
46
+                'read_only': False
47
+            },
48
+            'also_notifies': {
49
+                'read_only': False
50
+            },
51
+        }
52
+    }
53
+
54
+
55
+class PoolListYAMLAdapter(base.YAMLAdapter):
56
+
57
+    ADAPTER_OBJECT = objects.PoolList
58
+
59
+    MODIFICATIONS = {}

+ 41
- 0
designate/objects/adapters/yaml/pool_also_notify.py View File

@@ -0,0 +1,41 @@
1
+# Copyright 2014 Hewlett-Packard Development Company, L.P.
2
+#
3
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+#    not use this file except in compliance with the License. You may obtain
5
+#    a copy of the License at
6
+#
7
+#         http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+#    Unless required by applicable law or agreed to in writing, software
10
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+#    License for the specific language governing permissions and limitations
13
+#    under the License.
14
+from oslo_log import log as logging
15
+
16
+from designate.objects.adapters.yaml import base
17
+from designate import objects
18
+LOG = logging.getLogger(__name__)
19
+
20
+
21
+class PoolAlsoNotifyYAMLAdapter(base.YAMLAdapter):
22
+
23
+    ADAPTER_OBJECT = objects.PoolAlsoNotify
24
+
25
+    MODIFICATIONS = {
26
+        'fields': {
27
+            'host': {
28
+                'read_only': False
29
+            },
30
+            'port': {
31
+                'read_only': False
32
+            }
33
+        }
34
+    }
35
+
36
+
37
+class PoolAlsoNotifyListYAMLAdapter(base.YAMLAdapter):
38
+
39
+    ADAPTER_OBJECT = objects.PoolAlsoNotifyList
40
+
41
+    MODIFICATIONS = {}

+ 86
- 0
designate/objects/adapters/yaml/pool_attribute.py View File

@@ -0,0 +1,86 @@
1
+# Copyright 2014 Hewlett-Packard Development Company, L.P.
2
+#
3
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+#    not use this file except in compliance with the License. You may obtain
5
+#    a copy of the License at
6
+#
7
+#         http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+#    Unless required by applicable law or agreed to in writing, software
10
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+#    License for the specific language governing permissions and limitations
13
+#    under the License.
14
+import six
15
+from oslo_log import log as logging
16
+
17
+from designate.objects.adapters.yaml import base
18
+from designate import objects
19
+LOG = logging.getLogger(__name__)
20
+
21
+
22
+class PoolAttributeYAMLAdapter(base.YAMLAdapter):
23
+
24
+    ADAPTER_OBJECT = objects.PoolAttribute
25
+
26
+    MODIFICATIONS = {
27
+        'fields': {
28
+            'key': {
29
+                'read_only': False
30
+            },
31
+            'value': {
32
+                'read_only': False
33
+            },
34
+        }
35
+    }
36
+
37
+    @classmethod
38
+    def _render_object(cls, object, *arg, **kwargs):
39
+        return {str(object.key): str(object.value)}
40
+
41
+    @classmethod
42
+    def _parse_object(cls, values, object, *args, **kwargs):
43
+        for key in six.iterkeys(values):
44
+            object.key = key
45
+            object.value = values[key]
46
+
47
+        return object
48
+
49
+
50
+class PoolAttributeListYAMLAdapter(base.YAMLAdapter):
51
+
52
+    ADAPTER_OBJECT = objects.PoolAttributeList
53
+
54
+    MODIFICATIONS = {}
55
+
56
+    @classmethod
57
+    def _render_list(cls, list_object, *args, **kwargs):
58
+
59
+        r_list = {}
60
+
61
+        for object in list_object:
62
+            value = cls.get_object_adapter(
63
+                cls.ADAPTER_FORMAT,
64
+                object).render(cls.ADAPTER_FORMAT, object, *args, **kwargs)
65
+            for key in six.iterkeys(value):
66
+                r_list[key] = value[key]
67
+
68
+        return r_list
69
+
70
+    @classmethod
71
+    def _parse_list(cls, values, output_object, *args, **kwargs):
72
+
73
+        for key, value in values.items():
74
+            # Add the object to the list
75
+            output_object.append(
76
+                # Get the right Adapter
77
+                cls.get_object_adapter(
78
+                    cls.ADAPTER_FORMAT,
79
+                    # This gets the internal type of the list, and parses it
80
+                    # We need to do `get_object_adapter` as we need a new
81
+                    # instance of the Adapter
82
+                    output_object.LIST_ITEM_TYPE()).parse(
83
+                        {key: value}, output_object.LIST_ITEM_TYPE()))
84
+
85
+        # Return the filled list
86
+        return output_object

+ 41
- 0
designate/objects/adapters/yaml/pool_nameserver.py View File

@@ -0,0 +1,41 @@
1
+# Copyright 2014 Hewlett-Packard Development Company, L.P.
2
+#
3
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+#    not use this file except in compliance with the License. You may obtain
5
+#    a copy of the License at
6
+#
7
+#         http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+#    Unless required by applicable law or agreed to in writing, software
10
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+#    License for the specific language governing permissions and limitations
13
+#    under the License.
14
+from oslo_log import log as logging
15
+
16
+from designate.objects.adapters.yaml import base
17
+from designate import objects
18
+LOG = logging.getLogger(__name__)
19
+
20
+
21
+class PoolNameserverYAMLAdapter(base.YAMLAdapter):
22
+
23
+    ADAPTER_OBJECT = objects.PoolNameserver
24
+
25
+    MODIFICATIONS = {
26
+        'fields': {
27
+            'host': {
28
+                'read_only': False
29
+            },
30
+            'port': {
31
+                'read_only': False
32
+            }
33
+        }
34
+    }
35
+
36
+
37
+class PoolNameserverListYAMLAdapter(base.YAMLAdapter):
38
+
39
+    ADAPTER_OBJECT = objects.PoolNameserverList
40
+
41
+    MODIFICATIONS = {}

+ 41
- 0
designate/objects/adapters/yaml/pool_ns_record.py View File

@@ -0,0 +1,41 @@
1
+# Copyright 2014 Hewlett-Packard Development Company, L.P.
2
+#
3
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+#    not use this file except in compliance with the License. You may obtain
5
+#    a copy of the License at
6
+#
7
+#         http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+#    Unless required by applicable law or agreed to in writing, software
10
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+#    License for the specific language governing permissions and limitations
13
+#    under the License.
14
+from oslo_log import log as logging
15
+
16
+from designate.objects.adapters.yaml import base
17
+from designate import objects
18
+LOG = logging.getLogger(__name__)
19
+
20
+
21
+class PoolNsRecordYAMLAdapter(base.YAMLAdapter):
22
+
23
+    ADAPTER_OBJECT = objects.PoolNsRecord
24
+
25
+    MODIFICATIONS = {
26
+        'fields': {
27
+            'priority': {
28
+                'read_only': False
29
+            },
30
+            'hostname': {
31
+                'read_only': False
32
+            }
33
+        }
34
+    }
35
+
36
+
37
+class PoolNsRecordListYAMLAdapter(base.YAMLAdapter):
38
+
39
+    ADAPTER_OBJECT = objects.PoolNsRecordList
40
+
41
+    MODIFICATIONS = {}

+ 50
- 0
designate/objects/adapters/yaml/pool_target.py View File

@@ -0,0 +1,50 @@
1
+# Copyright 2014 Hewlett-Packard Development Company, L.P.
2
+#
3
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+#    not use this file except in compliance with the License. You may obtain
5
+#    a copy of the License at
6
+#
7
+#         http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+#    Unless required by applicable law or agreed to in writing, software
10
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+#    License for the specific language governing permissions and limitations
13
+#    under the License.
14
+from oslo_log import log as logging
15
+
16
+from designate.objects.adapters.yaml import base
17
+from designate import objects
18
+LOG = logging.getLogger(__name__)
19
+
20
+
21
+class PoolTargetYAMLAdapter(base.YAMLAdapter):
22
+
23
+    ADAPTER_OBJECT = objects.PoolTarget
24
+
25
+    MODIFICATIONS = {
26
+        'fields': {
27
+            'type': {
28
+                'read_only': False
29
+            },
30
+            'tsigkey_id': {
31
+                'read_only': False
32
+            },
33
+            'description': {
34
+                'read_only': False
35
+            },
36
+            'masters': {
37
+                'read_only': False
38
+            },
39
+            'options': {
40
+                'read_only': False
41
+            }
42
+        }
43
+    }
44
+
45
+
46
+class PoolTargetListYAMLAdapter(base.YAMLAdapter):
47
+
48
+    ADAPTER_OBJECT = objects.PoolTargetList
49
+
50
+    MODIFICATIONS = {}

+ 41
- 0
designate/objects/adapters/yaml/pool_target_master.py View File

@@ -0,0 +1,41 @@
1
+# Copyright 2014 Hewlett-Packard Development Company, L.P.
2
+#
3
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+#    not use this file except in compliance with the License. You may obtain
5
+#    a copy of the License at
6
+#
7
+#         http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+#    Unless required by applicable law or agreed to in writing, software
10
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+#    License for the specific language governing permissions and limitations
13
+#    under the License.
14
+from oslo_log import log as logging
15
+
16
+from designate.objects.adapters.yaml import base
17
+from designate import objects
18
+LOG = logging.getLogger(__name__)
19
+
20
+
21
+class PoolTargetMasterYAMLAdapter(base.YAMLAdapter):
22
+
23
+    ADAPTER_OBJECT = objects.PoolTargetMaster
24
+
25
+    MODIFICATIONS = {
26
+        'fields': {
27
+            'host': {
28
+                'read_only': False
29
+            },
30
+            'port': {
31
+                'read_only': False
32
+            },
33
+        }
34
+    }
35
+
36
+
37
+class PoolTargetMasterListYAMLAdapter(base.YAMLAdapter):
38
+
39
+    ADAPTER_OBJECT = objects.PoolTargetMasterList
40
+
41
+    MODIFICATIONS = {}

+ 86
- 0
designate/objects/adapters/yaml/pool_target_option.py View File

@@ -0,0 +1,86 @@
1
+# Copyright 2014 Hewlett-Packard Development Company, L.P.
2
+#
3
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+#    not use this file except in compliance with the License. You may obtain
5
+#    a copy of the License at
6
+#
7
+#         http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+#    Unless required by applicable law or agreed to in writing, software
10
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+#    License for the specific language governing permissions and limitations
13
+#    under the License.
14
+import six
15
+from oslo_log import log as logging
16
+
17
+from designate.objects.adapters.yaml import base
18
+from designate import objects
19
+LOG = logging.getLogger(__name__)
20
+
21
+
22
+class PoolTargetOptionYAMLAdapter(base.YAMLAdapter):
23
+
24
+    ADAPTER_OBJECT = objects.PoolTargetOption
25
+
26
+    MODIFICATIONS = {
27
+        'fields': {
28
+            'key': {
29
+                'read_only': False
30
+            },
31
+            'value': {
32
+                'read_only': False
33
+            },
34
+        }
35
+    }
36
+
37
+    @classmethod
38
+    def _render_object(cls, object, *arg, **kwargs):
39
+        return {str(object.key): str(object.value)}
40
+
41
+    @classmethod
42
+    def _parse_object(cls, values, object, *args, **kwargs):
43
+        for key in six.iterkeys(values):
44
+            object.key = key
45
+            object.value = values[key]
46
+
47
+        return object
48
+
49
+
50
+class PoolTargetOptionListYAMLAdapter(base.YAMLAdapter):
51
+
52
+    ADAPTER_OBJECT = objects.PoolTargetOptionList
53
+
54
+    MODIFICATIONS = {}
55
+
56
+    @classmethod
57
+    def _render_list(cls, list_object, *args, **kwargs):
58
+
59
+        r_list = {}
60
+
61
+        for object in list_object:
62
+            value = cls.get_object_adapter(
63
+                cls.ADAPTER_FORMAT,
64
+                object).render(cls.ADAPTER_FORMAT, object, *args, **kwargs)
65
+            for key in six.iterkeys(value):
66
+                r_list[key] = value[key]
67
+
68
+        return r_list
69
+
70
+    @classmethod
71
+    def _parse_list(cls, values, output_object, *args, **kwargs):
72
+
73
+        for key, value in values.items():
74
+            # Add the object to the list
75
+            output_object.append(
76
+                # Get the right Adapter
77
+                cls.get_object_adapter(
78
+                    cls.ADAPTER_FORMAT,
79
+                    # This gets the internal type of the list, and parses it
80
+                    # We need to do `get_object_adapter` as we need a new
81
+                    # instance of the Adapter
82
+                    output_object.LIST_ITEM_TYPE()).parse(
83
+                        {key: value}, output_object.LIST_ITEM_TYPE()))
84
+
85
+        # Return the filled list
86
+        return output_object

+ 26
- 3
designate/objects/pool_also_notify.py View File

@@ -18,11 +18,34 @@ from designate.objects import base
18 18
 class PoolAlsoNotify(base.DictObjectMixin, base.PersistentObjectMixin,
19 19
                      base.DesignateObject):
20 20
     FIELDS = {
21
-        'pool_id': {},
22
-        'host': {},
23
-        'port': {},
21
+        'pool_id': {
22
+            'schema': {
23
+                'type': 'string',
24
+                'description': 'Pool identifier',
25
+                'format': 'uuid',
26
+            },
27
+        },
28
+        'host': {
29
+            'schema': {
30
+                'type': 'string',
31
+                'format': 'ip-or-host',
32
+                'required': True,
33
+            },
34
+        },
35
+        'port': {
36
+            'schema': {
37
+                'type': 'integer',
38
+                'minimum': 1,
39
+                'maximum': 65535,
40
+                'required': True,
41
+            },
42
+        }
24 43
     }
25 44
 
45
+    STRING_KEYS = [
46
+        'id', 'host', 'port', 'pool_id'
47
+    ]
48
+
26 49
 
27 50
 class PoolAlsoNotifyList(base.ListObjectMixin, base.DesignateObject):
28 51
     LIST_ITEM_TYPE = PoolAlsoNotify

+ 26
- 3
designate/objects/pool_nameserver.py View File

@@ -18,11 +18,34 @@ from designate.objects import base
18 18
 class PoolNameserver(base.DictObjectMixin, base.PersistentObjectMixin,
19 19
                      base.DesignateObject):
20 20
     FIELDS = {
21
-        'pool_id': {},
22
-        'host': {},
23
-        'port': {},
21
+        'pool_id': {
22
+            'schema': {
23
+                'type': 'string',
24
+                'description': 'Pool identifier',
25
+                'format': 'uuid',
26
+            },
27
+        },
28
+        'host': {
29
+            'schema': {
30
+                'type': 'string',
31
+                'format': 'ip-or-host',
32
+                'required': True,
33
+            },
34
+        },
35
+        'port': {
36
+            'schema': {
37
+                'type': 'integer',
38
+                'minimum': 1,
39
+                'maximum': 65535,
40
+                'required': True,
41
+            },
42
+        }
24 43
     }
25 44
 
45
+    STRING_KEYS = [
46
+        'id', 'host', 'port', 'pool_id'
47
+    ]
48
+
26 49
 
27 50
 class PoolNameserverList(base.ListObjectMixin, base.DesignateObject):
28 51
     LIST_ITEM_TYPE = PoolNameserver

+ 25
- 4
designate/objects/pool_target.py View File

@@ -18,11 +18,28 @@ from designate.objects import base
18 18
 class PoolTarget(base.DictObjectMixin, base.PersistentObjectMixin,
19 19
                  base.DesignateObject):
20 20
     FIELDS = {
21
-        'pool_id': {},
21
+        'pool_id': {
22
+            'schema': {
23
+                'type': 'string',
24
+                'description': 'Pool identifier',
25
+                'format': 'uuid',
26
+            },
27
+        },
22 28
         'type': {},
23
-        'tsigkey_id': {},
24
-        'description': {},
25
-
29
+        'tsigkey_id': {
30
+            'schema': {
31
+                'type': ['string', 'null'],
32
+                'description': 'TSIG identifier',
33
+                'format': 'uuid',
34
+            },
35
+        },
36
+        'description': {
37
+            'schema': {
38
+                'type': ['string', 'null'],
39
+                'description': 'Description for the pool',
40
+                'maxLength': 160
41
+            }
42
+        },
26 43
         'masters': {
27 44
             'relation': True,
28 45
             'relation_cls': 'PoolTargetMasterList'
@@ -33,6 +50,10 @@ class PoolTarget(base.DictObjectMixin, base.PersistentObjectMixin,
33 50
         },
34 51
     }
35 52
 
53
+    STRING_KEYS = [
54
+        'id', 'type', 'pool_id'
55
+    ]
56
+
36 57
 
37 58
 class PoolTargetList(base.ListObjectMixin, base.DesignateObject):
38 59
     LIST_ITEM_TYPE = PoolTarget

+ 26
- 3
designate/objects/pool_target_master.py View File

@@ -18,11 +18,34 @@ from designate.objects import base
18 18
 class PoolTargetMaster(base.DictObjectMixin, base.PersistentObjectMixin,
19 19
                        base.DesignateObject):
20 20
     FIELDS = {
21
-        'pool_target_id': {},
22
-        'host': {},
23
-        'port': {}
21
+        'pool_target_id': {
22
+            'schema': {
23
+                'type': 'string',
24
+                'description': 'Pool Target identifier',
25
+                'format': 'uuid',
26
+            },
27
+        },
28
+        'host': {
29
+            'schema': {
30
+                'type': 'string',
31
+                'format': 'ip-or-host',
32
+                'required': True,
33
+            },
34
+        },
35
+        'port': {
36
+            'schema': {
37
+                'type': 'integer',
38
+                'minimum': 1,
39
+                'maximum': 65535,
40
+                'required': True,
41
+            },
42
+        }
24 43
     }
25 44
 
45
+    STRING_KEYS = [
46
+        'id', 'host', 'port', 'pool_target_id'
47
+    ]
48
+
26 49
 
27 50
 class PoolTargetMasterList(base.ListObjectMixin, base.DesignateObject):
28 51
     LIST_ITEM_TYPE = PoolTargetMaster

+ 25
- 3
designate/objects/pool_target_option.py View File

@@ -18,11 +18,33 @@ from designate.objects import base
18 18
 class PoolTargetOption(base.DictObjectMixin, base.PersistentObjectMixin,
19 19
                        base.DesignateObject):
20 20
     FIELDS = {
21
-        'pool_target_id': {},
22
-        'key': {},
23
-        'value': {},
21
+        'pool_target_id': {
22
+            'schema': {
23
+                'type': 'string',
24
+                'description': 'Pool Target identifier',
25
+                'format': 'uuid',
26
+            },
27
+        },
28
+        'key': {
29
+            'schema': {
30
+                'type': 'string',
31
+                'maxLength': 255,
32
+            },
33
+            'required': True,
34
+        },
35
+        'value': {
36
+            'schema': {
37
+                'type': 'string',
38
+                'maxLength': 255,
39
+            },
40
+            'required': True
41
+        }
24 42
     }
25 43
 
44
+    STRING_KEYS = [
45
+        'id', 'key', 'value', 'pool_target_id'
46
+    ]
47
+
26 48
 
27 49
 class PoolTargetOptionList(base.AttributeListObjectMixin,
28 50
                            base.DesignateObject):

+ 30
- 9
designate/pool_manager/service.py View File

@@ -97,10 +97,6 @@ class Service(service.RPCService, coordination.CoordinationMixin,
97 97
     def __init__(self, threads=None):
98 98
         super(Service, self).__init__(threads=threads)
99 99
 
100
-        # Build the Pool (and related) Object from Config
101
-        self.pool = objects.Pool.from_config(
102
-            CONF, CONF['service:pool_manager'].pool_id)
103
-
104 100
         # Get a pool manager cache connection.
105 101
         self.cache = cache.get_pool_manager_cache(
106 102
             CONF['service:pool_manager'].cache_driver)
@@ -118,11 +114,8 @@ class Service(service.RPCService, coordination.CoordinationMixin,
118 114
 
119 115
         # Compute a time (seconds) by which things should have propagated
120 116
         self.max_prop_time = (self.timeout * self.max_retries +
121
-                             self.max_retries * self.retry_interval +
122
-                             self.delay)
123
-
124
-        # Create the necessary Backend instances for each target
125
-        self._setup_target_backends()
117
+                              self.max_retries * self.retry_interval +
118
+                              self.delay)
126 119
 
127 120
     def _setup_target_backends(self):
128 121
         self.target_backends = {}
@@ -154,6 +147,34 @@ class Service(service.RPCService, coordination.CoordinationMixin,
154 147
         return topic
155 148
 
156 149
     def start(self):
150
+
151
+        # Build the Pool (and related) Object from Config
152
+        context = DesignateContext.get_admin_context()
153
+        pool_id = CONF['service:pool_manager'].pool_id
154
+
155
+        has_targets = False
156
+
157
+        while not has_targets:
158
+            try:
159
+                self.pool = self.central_api.get_pool(context, pool_id)
160
+
161
+                if len(self.pool.targets) > 0:
162
+                    has_targets = True
163
+                else:
164
+                    LOG.error(_LE("No targets for %s found."), self.pool)
165
+                    time.sleep(5)
166
+
167
+            # Pool data may not have migrated to the DB yet
168
+            except exceptions.PoolNotFound:
169
+                LOG.error(_LE("Pool ID %s not found."), pool_id)
170
+                time.sleep(5)
171
+            # designate-central service may not have started yet
172
+            except messaging.exceptions.MessagingTimeout:
173
+                time.sleep(0.2)
174
+
175
+        # Create the necessary Backend instances for each target
176
+        self._setup_target_backends()
177
+
157 178
         for target in self.pool.targets:
158 179
             self.target_backends[target.id].start()
159 180
 

+ 8
- 3
designate/tests/__init__.py View File

@@ -382,9 +382,14 @@ class TestCase(base.BaseTestCase):
382 382
         # Fetch the default pool
383 383
         pool = self.storage.get_pool(self.admin_context, default_pool_id)
384 384
 
385
-        # Add a NS record to it
386
-        pool.ns_records.append(
387
-            objects.PoolNsRecord(priority=0, hostname='ns1.example.org.'))
385
+        # Fill out the necessary pool details
386
+        pool.ns_records = objects.PoolNsRecordList.from_list([
387
+            {'hostname': 'ns1.example.org.', 'priority': 0}
388
+        ])
389
+
390
+        pool.targets = objects.PoolTargetList.from_list([
391
+            {'type': 'fake', u'description': "Fake PoolTarget for Tests"}
392
+        ])
388 393
 
389 394
         # Save the default pool
390 395
         self.storage.update_pool(self.admin_context, pool)

+ 63
- 0
designate/tests/resources/pools_yaml/multiple-pools.yaml View File

@@ -0,0 +1,63 @@
1
+---
2
+- name: pool-1
3
+  description: Default PowerDNS Pool
4
+  attributes:
5
+    internal: true
6
+  ns_records:
7
+    - hostname: ns1-1.example.org.
8
+      priority: 1
9
+    - hostname: ns1-2.example.org.
10
+      priority: 2
11
+  nameservers:
12
+    - host: 192.0.2.2
13
+      port: 53
14
+    - host: 192.0.2.3
15
+      port: 53
16
+  targets:
17
+    - type: powerdns
18
+      description: PowerDNS Database Cluster
19
+      masters:
20
+        - host: 192.0.2.1
21
+          port: 5354
22
+      options:
23
+        connection: 'mysql+pymysql://designate:password@127.0.0.1/designate_pdns?charset=utf8'
24
+  also_notifies:
25
+   - host: 192.0.2.4
26
+     port: 53
27
+
28
+- name: pool-2
29
+  id: cf2e8eab-76cd-4162-bf76-8aeee3556de0
30
+  description: Default PowerDNS Pool
31
+
32
+  attributes:
33
+    external: true
34
+  ns_records:
35
+    - hostname: ns1-1.example.org.
36
+      priority: 1
37
+    - hostname: ns1-2.example.org.
38
+      priority: 2
39
+  nameservers:
40
+    - host: 192.0.2.2
41
+      port: 53
42
+    - host: 192.0.2.3
43
+      port: 53
44
+
45
+  targets:
46
+    - type: bind
47
+      description: BIND9 Server 1
48
+      masters:
49
+        - host: 192.0.2.1
50
+          port: 5354
51
+      options:
52
+        rndc_host: 192.0.2.2
53
+        rndc_port: 953
54
+        rndc_key_file: /etc/designate/rndc.key
55
+    - type: bind
56
+      description: BIND9 Server 2
57
+      masters:
58
+        - host: 192.0.2.1
59
+          port: 5354
60
+      options:
61
+        rndc_host: 192.0.2.3
62
+        rndc_port: 953
63
+        rndc_key_file: /etc/designate/rndc.key

+ 32
- 0
designate/tests/resources/pools_yaml/pools.yaml View File

@@ -0,0 +1,32 @@
1
+---
2
+
3
+- name: default
4
+  description: Default PowerDNS Pool
5
+
6
+  attributes:
7
+    type: internal
8
+
9
+  ns_records:
10
+    - hostname: ns1-1.example.org.
11
+      priority: 1
12
+    - hostname: ns1-2.example.org.
13
+      priority: 2
14
+
15
+  nameservers:
16
+    - host: 192.0.2.2
17
+      port: 53
18
+    - host: 192.0.2.3
19
+      port: 53
20
+
21
+  targets:
22
+    - type: powerdns
23
+      description: PowerDNS Database Cluster
24
+      masters:
25
+        - host: 192.0.2.1
26
+          port: 5354
27
+      options:
28
+        connection: 'mysql+pymysql://designate:password@127.0.0.1/designate_pdns?charset=utf8'
29
+  also_notifies:
30
+   - host: 192.0.2.4
31
+     port: 53
32
+

+ 25
- 0
designate/tests/resources/pools_yaml/sample_output.yaml View File

@@ -0,0 +1,25 @@
1
+- also_notifies:
2
+  - host: 192.0.2.4
3
+    port: 53
4
+  attributes: {}
5
+  description: Default PowerDNS Pool
6
+  id: cf2e8eab-76cd-4162-bf76-8aeee3556de0
7
+  name: default
8
+  nameservers:
9
+  - host: 192.0.2.2
10
+    port: 53
11
+  - host: 192.0.2.3
12
+    port: 53
13
+  ns_records:
14
+  - hostname: ns1-1.example.org.
15
+    priority: 1
16
+  - hostname: ns1-2.example.org.
17
+    priority: 2
18
+  targets:
19
+  - description: PowerDNS Database Cluster
20
+    masters:
21
+    - host: 192.0.2.1
22
+      port: 5354
23
+    options:
24
+      connection: mysql+pymysql://designate:password@127.0.0.1/designate_pdns?charset=utf8
25
+    type: powerdns

+ 43
- 0
designate/tests/test_pool_manager/__init__.py View File

@@ -15,6 +15,49 @@
15 15
 # under the License.
16 16
 from designate.tests import TestCase
17 17
 
18
+POOL_DICT = {
19
+    'id': u'794ccc2c-d751-44fe-b57f-8894c9f5c842',
20
+    'name': u'default',
21
+    'targets': [
22
+        {
23
+            'id': 'f278782a-07dc-4502-9177-b5d85c5f7c7e',
24
+            'type': 'fake',
25
+            'masters': [
26
+                {
27
+                    'host': '127.0.0.1',
28
+                    'port': 5354
29
+                }
30
+            ],
31
+            'options': {}
32
+        },
33
+        {
34
+            'id': 'a38703f2-b71e-4e5b-ab22-30caaed61dfd',
35
+            'type': 'fake',
36
+            'masters': [
37
+                {
38
+                    'host': '127.0.0.1',
39
+                    'port': 5354
40
+                }
41
+            ],
42
+            'options': {}
43
+        },
44
+    ],
45
+    'nameservers': [
46
+        {
47
+            'id': 'c5d64303-4cba-425a-9f3c-5d708584dde4',
48
+            'host': '127.0.0.1',
49
+            'port': 5355
50
+
51
+        },
52
+        {
53
+            'id': 'c67cdc95-9a9e-4d2a-98ed-dc78cbd85234',
54
+            'host': '127.0.0.1',
55
+            'port': 5356
56
+        },
57
+    ],
58
+    'also_notifies': [],
59
+}
60
+
18 61
 
19 62
 class PoolManagerTestCase(TestCase):
20 63
     pass

+ 17
- 57
designate/tests/test_pool_manager/test_service.py View File

@@ -18,7 +18,6 @@ import logging
18 18
 import uuid
19 19
 
20 20
 import oslo_messaging as messaging
21
-from oslo_config import cfg
22 21
 from mock import call
23 22
 from mock import Mock
24 23
 from mock import patch
@@ -30,6 +29,7 @@ from designate.central import rpcapi as central_rpcapi
30 29
 from designate.mdns import rpcapi as mdns_rpcapi
31 30
 from designate.storage.impl_sqlalchemy import tables
32 31
 from designate.tests.test_pool_manager import PoolManagerTestCase
32
+from designate.tests.test_pool_manager import POOL_DICT
33 33
 import designate.pool_manager.service as pm_module
34 34
 
35 35
 LOG = logging.getLogger(__name__)
@@ -55,61 +55,13 @@ class PoolManagerServiceNoopTest(PoolManagerTestCase):
55 55
             pool_id='794ccc2c-d751-44fe-b57f-8894c9f5c842',
56 56
             group='service:pool_manager')
57 57
 
58
-        # Configure the Pool
59
-        section_name = 'pool:794ccc2c-d751-44fe-b57f-8894c9f5c842'
60
-        section_opts = [
61
-            cfg.ListOpt('targets', default=[
62
-                'f278782a-07dc-4502-9177-b5d85c5f7c7e',
63
-                'a38703f2-b71e-4e5b-ab22-30caaed61dfd',
64
-            ]),
65
-            cfg.ListOpt('nameservers', default=[
66
-                'c5d64303-4cba-425a-9f3c-5d708584dde4',
67
-                'c67cdc95-9a9e-4d2a-98ed-dc78cbd85234',
68
-            ]),
69
-            cfg.ListOpt('also_notifies', default=[]),
70
-        ]
71
-        cfg.CONF.register_group(cfg.OptGroup(name=section_name))
72
-        cfg.CONF.register_opts(section_opts, group=section_name)
73
-
74
-        # Configure the Pool Targets
75
-        section_name = 'pool_target:f278782a-07dc-4502-9177-b5d85c5f7c7e'
76
-        section_opts = [
77
-            cfg.StrOpt('type', default='fake'),
78
-            cfg.ListOpt('masters', default=['127.0.0.1:5354']),
79
-            cfg.DictOpt('options', default={})
80
-        ]
81
-        cfg.CONF.register_group(cfg.OptGroup(name=section_name))
82
-        cfg.CONF.register_opts(section_opts, group=section_name)
83
-
84
-        section_name = 'pool_target:a38703f2-b71e-4e5b-ab22-30caaed61dfd'
85
-        section_opts = [
86
-            cfg.StrOpt('type', default='fake'),
87
-            cfg.ListOpt('masters', default=['127.0.0.1:5354']),
88
-            cfg.DictOpt('options', default={})
89
-        ]
90
-        cfg.CONF.register_group(cfg.OptGroup(name=section_name))
91
-        cfg.CONF.register_opts(section_opts, group=section_name)
92
-
93
-        # Configure the Pool Nameservers
94
-        section_name = 'pool_nameserver:c5d64303-4cba-425a-9f3c-5d708584dde4'
95
-        section_opts = [
96
-            cfg.StrOpt('host', default='127.0.0.1'),
97
-            cfg.StrOpt('port', default=5355),
98
-        ]
99
-        cfg.CONF.register_group(cfg.OptGroup(name=section_name))
100
-        cfg.CONF.register_opts(section_opts, group=section_name)
101
-
102
-        section_name = 'pool_nameserver:c67cdc95-9a9e-4d2a-98ed-dc78cbd85234'
103
-        section_opts = [
104
-            cfg.StrOpt('host', default='127.0.0.1'),
105
-            cfg.StrOpt('port', default=5356),
106
-        ]
107
-        cfg.CONF.register_group(cfg.OptGroup(name=section_name))
108
-        cfg.CONF.register_opts(section_opts, group=section_name)
109
-
110 58
         # Start the Service
111
-        self.service = self.start_service('pool_manager')
112
-        self.cache = self.service.cache
59
+        with patch.object(
60
+                        central_rpcapi.CentralAPI,
61
+                        'get_pool',
62
+                        return_value=objects.Pool.from_dict(POOL_DICT)):
63
+            self.service = self.start_service('pool_manager')
64
+            self.cache = self.service.cache
113 65
 
114 66
     @staticmethod
115 67
     def _build_zone(name, action, status, id=None):
@@ -230,7 +182,11 @@ class PoolManagerServiceNoopTest(PoolManagerTestCase):
230 182
         self.config(
231 183
             threshold_percentage=50,
232 184
             group='service:pool_manager')
233
-        self.service = self.start_service('pool_manager')
185
+        with patch.object(
186
+                        central_rpcapi.CentralAPI,
187
+                        'get_pool',
188
+                        return_value=objects.Pool.from_dict(POOL_DICT)):
189
+            self.service = self.start_service('pool_manager')
234 190
 
235 191
         zone = self._build_zone('example.org.', 'CREATE', 'PENDING')
236 192
 
@@ -349,7 +305,11 @@ class PoolManagerServiceNoopTest(PoolManagerTestCase):
349 305
         self.config(
350 306
             threshold_percentage=50,
351 307
             group='service:pool_manager')
352
-        self.service = self.start_service('pool_manager')
308
+        with patch.object(
309
+                        central_rpcapi.CentralAPI,
310
+                        'get_pool',
311
+                        return_value=objects.Pool.from_dict(POOL_DICT)):
312
+            self.service = self.start_service('pool_manager')
353 313
 
354 314
         zone = self._build_zone('example.org.', 'UPDATE', 'PENDING')
355 315
 

+ 25
- 13
designate/tests/test_storage/__init__.py View File

@@ -116,7 +116,7 @@ class StorageTestCase(object):
116 116
             context, pool.id, objects.PoolAlsoNotify.from_dict(values))
117 117
 
118 118
     # Paging Tests
119
-    def _ensure_paging(self, data, method):
119
+    def _ensure_paging(self, data, method, criterion=None):
120 120
         """
121 121
         Given an array of created items we iterate through them making sure
122 122
         they match up to things returned by paged results.
@@ -124,20 +124,27 @@ class StorageTestCase(object):
124 124
         results = None
125 125
         item_number = 0
126 126
 
127
+        criterion = criterion or {}
128
+
127 129
         for current_page in range(0, int(math.ceil(float(len(data)) / 2))):
128
-            LOG.debug('Validating results on page %d', current_page)
130
+            LOG.critical('Validating results on page %d', current_page)
129 131
 
130 132
             if results is not None:
131 133
                 results = method(
132
-                    self.admin_context, limit=2, marker=results[-1]['id'])
134
+                    self.admin_context,
135
+                    limit=2,
136
+                    marker=results[-1]['id'],
137
+                    criterion=criterion
138
+                )
133 139
             else:
134
-                results = method(self.admin_context, limit=2)
140
+                results = method(self.admin_context, limit=2,
141
+                                 criterion=criterion)
135 142
 
136 143
             LOG.critical('Results: %d', len(results))
137 144
 
138 145
             for result_number, result in enumerate(results):
139
-                LOG.debug('Validating result %d on page %d', result_number,
140
-                          current_page)
146
+                LOG.critical('Validating result %d on page %d', result_number,
147
+                             current_page)
141 148
                 self.assertEqual(
142 149
                     data[item_number]['id'], results[result_number]['id'])
143 150
 
@@ -2402,7 +2409,7 @@ class StorageTestCase(object):
2402 2409
         criterion = dict(host=pool_nameserver_two['host'])
2403 2410
 
2404 2411
         results = self.storage.find_pool_nameservers(self.admin_context,
2405
-                                               criterion)
2412
+                                                     criterion)
2406 2413
         self.assertEqual(1, len(results))
2407 2414
         self.assertEqual(pool_nameserver_two['host'], results[0]['host'])
2408 2415
 
@@ -2535,15 +2542,19 @@ class StorageTestCase(object):
2535 2542
     def test_find_pool_targets(self):
2536 2543
         pool = self.create_pool(fixture=0)
2537 2544
 
2538
-        # Verify that there are no pool_targets created
2539
-        actual = self.storage.find_pool_targets(self.admin_context)
2545
+        # Verify that there are no new pool_targets created
2546
+        actual = self.storage.find_pool_targets(
2547
+            self.admin_context,
2548
+            criterion={'pool_id': pool.id})
2540 2549
         self.assertEqual(0, len(actual))
2541 2550
 
2542 2551
         # Create a PoolTarget
2543 2552
         pool_target = self.create_pool_target(pool, fixture=0)
2544 2553
 
2545
-        # Fetch the PoolTargets and ensure only 1 exists
2546
-        actual = self.storage.find_pool_targets(self.admin_context)
2554
+        # Fetch the PoolTargets and ensure only 2 exist
2555
+        actual = self.storage.find_pool_targets(
2556
+            self.admin_context,
2557
+            criterion={'pool_id': pool.id})
2547 2558
         self.assertEqual(1, len(actual))
2548 2559
 
2549 2560
         self.assertEqual(pool_target['pool_id'], actual[0]['pool_id'])
@@ -2557,7 +2568,8 @@ class StorageTestCase(object):
2557 2568
                    for i in range(10)]
2558 2569
 
2559 2570
         # Ensure we can page through the results.
2560
-        self._ensure_paging(created, self.storage.find_pool_targets)
2571
+        self._ensure_paging(created, self.storage.find_pool_targets,
2572
+                            criterion={'pool_id': pool.id})
2561 2573
 
2562 2574
     def test_find_pool_targets_with_criterion(self):
2563 2575
         pool = self.create_pool(fixture=0)
@@ -2582,7 +2594,7 @@ class StorageTestCase(object):
2582 2594
         criterion = dict(description=pool_target_two['description'])
2583 2595
 
2584 2596
         results = self.storage.find_pool_targets(self.admin_context,
2585
-                                               criterion)
2597
+                                                 criterion)
2586 2598
         self.assertEqual(1, len(results))
2587 2599
         self.assertEqual(
2588 2600
             pool_target_two['description'], results[0]['description'])

+ 156
- 0
designate/tests/unit/test_objects/test_yaml_adapters.py View File

@@ -0,0 +1,156 @@
1
+# Copyright 2014 Hewlett-Packard Development Company, L.P.
2
+#
3
+# Author: Kiall Mac Innes <kiall@hpe.com>
4
+#
5
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
6
+# not use this file except in compliance with the License. You may obtain
7
+# a copy of the License at
8
+#
9
+#      http://www.apache.org/licenses/LICENSE-2.0
10
+#
11
+# Unless required by applicable law or agreed to in writing, software
12
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+# License for the specific language governing permissions and limitations
15
+# under the License.
16
+import os
17
+
18
+import yaml
19
+from oslo_log import log as logging
20
+import oslotest.base
21
+
22
+from designate import objects
23
+from designate.objects import adapters
24
+from designate.tests import resources
25
+
26
+
27
+LOG = logging.getLogger(__name__)
28
+
29
+
30
+class DesignateYAMLAdapterTest(oslotest.base.BaseTestCase):
31
+
32
+    def assertNestedDictContainsSubset(self, expected, actual):
33
+        for key, value in expected.items():
34
+            if isinstance(value, dict):
35
+                self.assertNestedDictContainsSubset(value, actual.get(key, {}))
36
+
37
+            elif isinstance(value, list):
38
+                self.assertEqual(len(value), len(actual[key]))
39
+
40
+                for index, item in enumerate(value):
41
+                    self.assertNestedDictContainsSubset(
42
+                        item, actual[key][index])
43
+
44
+            else:
45
+                self.assertEqual(value, actual[key])
46
+
47
+    def test_yaml_parsing(self):
48
+
49
+        file = os.path.join(resources.path, 'pools_yaml/pools.yaml')
50
+        with open(file, 'r') as stream:
51
+            xpools = yaml.safe_load(stream)
52
+
53
+        for xpool in xpools:
54
+            r_pool = adapters.DesignateAdapter.parse(
55
+                'YAML', xpool, objects.Pool())
56
+            self.assertEqual('default', r_pool.name)
57
+            self.assertEqual('Default PowerDNS Pool', r_pool.description)
58
+            self.assertEqual(2, len(r_pool.ns_records))
59
+            self.assertEqual(1, r_pool.ns_records[0].priority)
60
+            self.assertEqual(2, r_pool.ns_records[1].priority)
61
+            self.assertEqual(
62
+                'ns1-1.example.org.', r_pool.ns_records[0].hostname)
63
+            self.assertEqual(
64
+                'ns1-2.example.org.', r_pool.ns_records[1].hostname)
65
+            self.assertEqual(1, len(r_pool.targets))
66
+            self.assertEqual('powerdns', r_pool.targets[0].type)
67
+            self.assertEqual(
68
+                'PowerDNS Database Cluster', r_pool.targets[0].description)
69
+            self.assertEqual(1, len(r_pool.targets[0].masters))
70
+            self.assertEqual('192.0.2.1', r_pool.targets[0].masters[0].host)
71
+            self.assertEqual(5354, r_pool.targets[0].masters[0].port)
72
+            self.assertEqual(1, len(r_pool.targets[0].options))
73
+            self.assertEqual('connection', r_pool.targets[0].options[0].key)
74
+            self.assertEqual(
75
+                'mysql+pymysql://designate:password@127.0.0.1/designate_pdns?charset=utf8',  # noqa
76
+                r_pool.targets[0].options[0].value)
77
+            self.assertEqual(1, len(r_pool.also_notifies))
78
+            self.assertEqual('192.0.2.4', r_pool.also_notifies[0].host)
79
+            self.assertEqual(53, r_pool.also_notifies[0].port)
80
+            self.assertEqual(1, len(r_pool.attributes))
81
+            self.assertEqual('type', r_pool.attributes[0].key)
82
+            self.assertEqual('internal', r_pool.attributes[0].value)
83
+
84
+    def test_yaml_rendering(self):
85
+
86
+        pool_dict = {
87
+            'also_notifies': [
88
+                {
89
+                    'host': u'192.0.2.4',
90
+                    'pool_id': u'cf2e8eab-76cd-4162-bf76-8aeee3556de0',
91
+                    'port': 53,
92
+                }
93
+            ],
94
+            'attributes': [],
95
+            'description': u'Default PowerDNS Pool',
96
+            'id': u'cf2e8eab-76cd-4162-bf76-8aeee3556de0',
97
+            'name': u'default',
98
+            'nameservers': [
99
+                {
100
+                    'host': u'192.0.2.2',
101
+                    'pool_id': u'cf2e8eab-76cd-4162-bf76-8aeee3556de0',
102
+                    'port': 53,
103
+                },
104
+                {
105
+                    'host': u'192.0.2.3',
106
+                    'pool_id': u'cf2e8eab-76cd-4162-bf76-8aeee3556de0',
107
+                    'port': 53,
108
+                }
109
+            ],
110
+            'ns_records': [
111
+                {
112
+                    'hostname': u'ns1-1.example.org.',
113
+                    'pool_id': u'cf2e8eab-76cd-4162-bf76-8aeee3556de0',
114
+                    'priority': 1,
115
+                },
116
+                {
117
+                    'hostname': u'ns1-2.example.org.',
118
+                    'pool_id': u'cf2e8eab-76cd-4162-bf76-8aeee3556de0',
119
+                    'priority': 2,
120
+                }
121
+            ],
122
+            'provisioner': u'UNMANAGED',
123
+            'targets': [
124
+                {
125
+                    'description': u'PowerDNS Database Cluster',
126
+                    'masters': [
127
+                        {
128
+                            'host': u'192.0.2.1',
129
+                            'pool_target_id': u'd567d569-2d69-41d5-828d-f7054bb10b5c',  # noqa
130
+                            'port': 5354,
131
+                        }
132
+                    ],
133
+                    'options': [
134
+                        {
135
+                            'key': u'connection',
136
+                            'pool_target_id': u'd567d569-2d69-41d5-828d-f7054bb10b5c',  # noqa
137
+                            'value': u'mysql+pymysql://designate:password@127.0.0.1/designate_pdns?charset=utf8',  # noqa
138
+                        }
139
+                    ],
140
+                    'pool_id': u'cf2e8eab-76cd-4162-bf76-8aeee3556de0',
141
+                    'type': u'powerdns',
142
+                }
143
+            ]
144
+        }
145
+
146
+        file = os.path.join(resources.path, 'pools_yaml/sample_output.yaml')
147
+        with open(file, 'r') as stream:
148
+            self.assertEqual(
149
+                stream.read(),
150
+                yaml.dump(
151
+                    adapters.DesignateAdapter.render(
152
+                        'YAML', objects.PoolList.from_list([pool_dict])
153
+                    ),
154
+                    default_flow_style=False
155
+                )
156
+            )

+ 58
- 7
designate/tests/unit/test_pool_manager/test_service.py View File

@@ -33,6 +33,55 @@ from designate.tests.unit import RwObject
33 33
 import designate.pool_manager.service as pm_module
34 34
 
35 35
 
36
+POOL_DICT = {
37
+    'also_notifies': [
38
+        {
39
+            'host': u'192.0.2.4',
40
+            'pool_id': u'cf2e8eab-76cd-4162-bf76-8aeee3556de0',
41
+            'port': 53,
42
+        }
43
+    ],
44
+    'attributes': [],
45
+    'description': u'Default PowerDNS Pool',
46
+    'id': u'cf2e8eab-76cd-4162-bf76-8aeee3556de0',
47
+    'name': u'default',
48
+    'nameservers': [
49
+        {
50
+            'host': u'192.0.2.2',
51
+            'pool_id': u'cf2e8eab-76cd-4162-bf76-8aeee3556de0',
52
+            'port': 53,
53
+        },
54
+        {
55
+            'host': u'192.0.2.3',
56
+            'pool_id': u'cf2e8eab-76cd-4162-bf76-8aeee3556de0',
57
+            'port': 53,
58
+        }
59
+    ],
60
+    'ns_records': [
61
+        {
62
+            'hostname': u'ns1-1.example.org.',
63
+            'pool_id': u'cf2e8eab-76cd-4162-bf76-8aeee3556de0',
64
+            'priority': 1,
65
+        },
66
+        {
67
+            'hostname': u'ns1-2.example.org.',
68
+            'pool_id': u'cf2e8eab-76cd-4162-bf76-8aeee3556de0',
69
+            'priority': 2,
70
+        }
71
+    ],
72
+    'provisioner': u'UNMANAGED',
73
+    'targets': [
74
+        {
75
+            'description': u'PowerDNS Database Cluster',
76
+            'masters': [],
77
+            'options': [],
78
+            'type': 'fake',
79
+            'pool_id': u'cf2e8eab-76cd-4162-bf76-8aeee3556de0',
80
+        }
81
+    ]
82
+}
83
+
84
+
36 85
 class PoolManagerInitTest(test.BaseTestCase):
37 86
     def __setUp(self):
38 87
         super(PoolManagerTest, self).setUp()
@@ -44,21 +93,20 @@ class PoolManagerInitTest(test.BaseTestCase):
44 93
             self.assertRaises(exceptions.NoPoolTargetsConfigured, Service)
45 94
 
46 95
     def test_init(self):
47
-        with patch.object(objects.Pool, 'from_config',
48
-                          return_value=Mock()):
49
-            Service._setup_target_backends = Mock()
50 96
             Service()
51 97
 
52 98
     def test_start(self):
53 99
         with patch.object(objects.Pool, 'from_config',
54 100
                           return_value=Mock()):
55
-            Service._setup_target_backends = Mock()
56 101
             pm = Service()
57
-            pm.pool.targets = ()
58 102
             pm.tg.add_timer = Mock()
59 103
             pm._pool_election = Mock()
60 104
             with patch("designate.service.RPCService.start"):
61
-                pm.start()
105
+                with patch.object(
106
+                        pm.central_api,
107
+                        'get_pool',
108
+                        return_value=objects.Pool.from_dict(POOL_DICT)):
109
+                    pm.start()
62 110
 
63 111
             call1 = pm.tg.add_timer.call_args_list[0][0]
64 112
             self.assertEqual(120, call1[0])
@@ -88,8 +136,11 @@ class PoolManagerTest(test.BaseTestCase):
88 136
     def setUp(self, *mocks):
89 137
         super(PoolManagerTest, self).setUp()
90 138
         self.pm = Service()
91
-        self.pm.pool.targets = ()
92 139
         self.pm.tg.add_timer = Mock()
140
+        self.pm.pool = Mock()
141
+        setattr(self.pm.pool, 'targets', ())
142
+        setattr(self.pm.pool, 'also_notifies', ())
143
+        setattr(self.pm.pool, 'nameservers', ())
93 144
         self.pm._pool_election = Mock()
94 145
         self.pm.target_backends = {}
95 146
 

+ 58
- 24
devstack/designate_plugins/backend-akamai View File

@@ -29,7 +29,7 @@ DESIGNATE_AKAMAI_USERNAME=${DESIGNATE_AKAMAI_USERNAME:-username}
29 29
 DESIGNATE_AKAMAI_PASSWORD=${DESIGNATE_AKAMAI_PASSWORD:-password}
30 30
 DESIGNATE_AKAMAI_MASTERS=${DESIGNATE_AKAMAI_MASTERS:-"$DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT_MDNS"}
31 31
 DESIGNATE_AKAMAI_NAMESERVERS=${DESIGNATE_AKAMAI_NAMESERVERS:-""}
32
-DESIGNATE_AKAMAI_ALSO_NOTIFIES=${DESIGNATE_AKAMAI_ALSO_NOTIFIES:-"193.108.155.34:53,23.73.134.141:53,80.67.64.148:53,23.73.134.237:53,23.73.133.141:53,23.73.133.237:53,80.67.64.10:53,72.246.0.10:53,72.247.45.157:53,72.246.192.168:53,193.108.152.143:53,60.254.128.45:53,72.247.45.110:53,72.247.45.65:53,72.247.45.25:53"}
32
+DESIGNATE_AKAMAI_ALSO_NOTIFIES=${DESIGNATE_AKAMAI_ALSO_NOTIFIES:-"193.108.155.34,23.73.134.141,80.67.64.148,23.73.134.237,23.73.133.141,23.73.133.237,80.67.64.10,72.246.0.10,72.247.45.157,72.246.192.168,193.108.152.143,60.254.128.45,72.247.45.110,72.247.45.65,72.247.45.25"}
33 33
 
34 34
 # Pull in DESIGNATE_3RDPARTY_CREDS user/pass if set
35 35
 if [ -n "$DESIGNATE_3RDPARTY_CREDS" ]; then
@@ -57,38 +57,72 @@ function install_designate_backend {
57 57
 
58 58
 # configure_designate_backend - make configuration changes, including those to other services
59 59
 function configure_designate_backend {
60
-    iniset $DESIGNATE_CONF pool_target:$DESIGNATE_TARGET_ID type akamai
61
-    iniset $DESIGNATE_CONF pool_target:$DESIGNATE_TARGET_ID masters $DESIGNATE_AKAMAI_MASTERS
62
-    iniset $DESIGNATE_CONF pool_target:$DESIGNATE_TARGET_ID options "username: $DESIGNATE_AKAMAI_USERNAME, password: $DESIGNATE_AKAMAI_PASSWORD"
60
+    # Generate Designate pool.yaml file
61
+    sudo tee $DESIGNATE_CONF_DIR/pools.yaml > /dev/null <<EOF
62
+---
63
+- name: default
64
+  description: DevStack Akamai Pool
65
+  attributes: {}
66
+
67
+  targets:
68
+    - type: akamai
69
+      description: Akamai API
70
+
71
+      options:
72
+        username: $DESIGNATE_AKAMAI_USERNAME
73
+        password: $DESIGNATE_AKAMAI_PASSWORD
74
+
75
+      masters:
76
+EOF
77
+
78
+    # Create a Pool Master for each of the Akamai Masters
79
+    IFS=',' read -a masters <<< "$DESIGNATE_AKAMAI_MASTERS"
80
+
81
+    for master in "${masters[@]}"; do
82
+        sudo tee -a $DESIGNATE_CONF_DIR/pools.yaml > /dev/null <<EOF
83
+        - host: $master
84
+          port: 53
85
+EOF
86
+    done
63 87
 
64
-    # Create a Pool Nameserver for each of the Akamai nameservers
65
-    local nameserver_ids=""
88
+    # Create a Pool NS Record for each of the Akamai Nameservers
66 89
     IFS=',' read -a nameservers <<< "$DESIGNATE_AKAMAI_NAMESERVERS"
67 90
 
68
-    for nameserver in "${nameservers[@]}"; do
69
-        local nameserver_id=`uuidgen`
70
-        iniset $DESIGNATE_CONF pool_nameserver:$nameserver_id host $(dig +short A $nameserver | head -n 1)
71
-        iniset $DESIGNATE_CONF pool_nameserver:$nameserver_id port 53
91
+    sudo tee -a $DESIGNATE_CONF_DIR/pools.yaml > /dev/null <<EOF
92
+  ns_records:
93
+EOF
72 94
 
73
-        # Append the Nameserver ID to the list
74
-        nameserver_ids+=${nameserver_id},
95
+    for nameserver in "${nameservers[@]}"; do
96
+        sudo tee -a $DESIGNATE_CONF_DIR/pools.yaml > /dev/null <<EOF
97
+    - hostname: $nameserver
98
+      priority: 1
99
+EOF
75 100
     done
76 101
 
77
-    # Configure the Pool for the set of nameserver IDs, minus the trailing comma
78
-    iniset $DESIGNATE_CONF pool:$DESIGNATE_POOL_ID nameservers "${nameserver_ids:0:-1}"
102
+    # Create a Pool Nameserver for each of the Akamai Nameservers
103
+    sudo tee -a $DESIGNATE_CONF_DIR/pools.yaml > /dev/null <<EOF
104
+  nameservers:
105
+EOF
79 106
 
80
-    # Configure the Pool to Notify Akamai's Transfer Agents
81
-    iniset $DESIGNATE_CONF pool:$DESIGNATE_POOL_ID also_notifies "$DESIGNATE_AKAMAI_ALSO_NOTIFIES"
82
-}
107
+    for nameserver in "${nameservers[@]}"; do
108
+        sudo tee -a $DESIGNATE_CONF_DIR/pools.yaml > /dev/null <<EOF
109
+    - host: `dig +short A $nameserver | head -n 1`
110
+      port: 53
111
+EOF
112
+    done
113
+
114
+    # Create a Pool Also Notifies for each of the Akamai Also Notifies
115
+    IFS=',' read -a also_notifies <<< "$DESIGNATE_AKAMAI_ALSO_NOTIFIES"
83 116
 
84
-# create_designate_ns_records - Create Pool NS Records
85
-function create_designate_ns_records_backend {
86
-    # Build an array of the Akamai nameservers.
87
-    IFS=',' read -a ns_records <<< "$DESIGNATE_AKAMAI_NAMESERVERS"
117
+    sudo tee -a $DESIGNATE_CONF_DIR/pools.yaml > /dev/null <<EOF
118
+  also_notifies:
119
+EOF
88 120
 
89
-    # Create a NS Record for each of the Akamai nameservers
90
-    for ns_record in "${ns_records[@]}"; do
91
-        designate server-create --name "${ns_record%%.}."
121
+    for also_notify in "${also_notifies[@]}"; do
122
+        sudo tee -a $DESIGNATE_CONF_DIR/pools.yaml > /dev/null <<EOF
123
+    - host: $also_notify
124
+      port: 53
125
+EOF
92 126
     done
93 127
 }
94 128
 

+ 31
- 9
devstack/designate_plugins/backend-bind9 View File

@@ -74,15 +74,37 @@ EOF
74 74
 
75 75
 # configure_designate_backend - make configuration changes, including those to other services
76 76
 function configure_designate_backend {
77
-    iniset $DESIGNATE_CONF pool_target:$DESIGNATE_TARGET_ID type bind9
78
-    iniset $DESIGNATE_CONF pool_target:$DESIGNATE_TARGET_ID masters $DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT_MDNS
79
-    iniset $DESIGNATE_CONF pool_target:$DESIGNATE_TARGET_ID options "rndc_host: $DESIGNATE_SERVICE_HOST, rndc_port: $DESIGNATE_SERVICE_PORT_RNDC, rndc_config_file: $BIND_CFG_DIR/rndc.conf, rndc_key_file: $BIND_CFG_DIR/rndc.key, host: $DESIGNATE_SERVICE_HOST, port: $DESIGNATE_SERVICE_PORT_DNS"
80
-
81
-    # DevStack Managed BIND NameServer
82
-    local nameserver_id=`uuidgen`
83
-    iniset $DESIGNATE_CONF pool:$DESIGNATE_POOL_ID nameservers $nameserver_id
84
-    iniset $DESIGNATE_CONF pool_nameserver:$nameserver_id host $DESIGNATE_SERVICE_HOST
85
-    iniset $DESIGNATE_CONF pool_nameserver:$nameserver_id port $DESIGNATE_SERVICE_PORT_DNS
77
+    # Generate Designate pool.yaml file
78
+    sudo tee $DESIGNATE_CONF_DIR/pools.yaml > /dev/null <<EOF
79
+---
80
+- name: default
81
+  description: DevStack BIND Pool
82
+  attributes: {}
83
+
84
+  ns_records:
85
+    - hostname: $DESIGNATE_DEFAULT_NS_RECORD
86
+      priority: 1
87
+
88
+  nameservers:
89
+    - host: $DESIGNATE_SERVICE_HOST
90
+      port: $DESIGNATE_SERVICE_PORT_DNS
91
+
92
+  targets:
93
+    - type: bind9
94
+      description: BIND Instance
95
+
96
+      masters:
97
+        - host: $DESIGNATE_SERVICE_HOST
98
+          port: $DESIGNATE_SERVICE_PORT_MDNS
99
+
100
+      options:
101
+        host: $DESIGNATE_SERVICE_HOST
102
+        port: $DESIGNATE_SERVICE_PORT_DNS
103
+        rndc_host: $DESIGNATE_SERVICE_HOST
104
+        rndc_port: $DESIGNATE_SERVICE_PORT_RNDC
105
+        rndc_config_file: $BIND_CFG_DIR/rndc.conf
106
+        rndc_key_file: $BIND_CFG_DIR/rndc.key
107
+EOF
86 108
 
87 109
     sudo chown $STACK_USER $BIND_CFG_DIR
88 110
 

+ 58
- 32
devstack/designate_plugins/backend-dynect View File

@@ -33,7 +33,7 @@ DESIGNATE_DYNECT_JOB_TIMEOUT=${DESIGNATE_DYNECT_JOB_TIMEOUT:-}
33 33
 DESIGNATE_DYNECT_TIMEOUT=${DESIGNATE_DYNECT_TIMEOUT:-}
34 34
 DESIGNATE_DYNECT_MASTERS=${DESIGNATE_DYNECT_MASTERS:-"$DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT_MDNS"}
35 35
 DESIGNATE_DYNECT_NAMESERVERS=${DESIGNATE_DYNECT_NAMESERVERS:-""}
36
-DESIGNATE_DYNECT_ALSO_NOTIFIES=${DESIGNATE_DYNECT_ALSO_NOTIFIES:-"204.13.249.65:53,208.78.68.65:53"}
36
+DESIGNATE_DYNECT_ALSO_NOTIFIES=${DESIGNATE_DYNECT_ALSO_NOTIFIES:-"204.13.249.65,208.78.68.65"}
37 37
 
38 38
 # Pull in DESIGNATE_3RDPARTY_CREDS user/pass if set
39 39
 if [ -n "$DESIGNATE_3RDPARTY_CREDS" ]; then
@@ -62,47 +62,73 @@ function install_designate_backend {
62 62
 
63 63
 # configure_designate_backend - make configuration changes, including those to other services
64 64
 function configure_designate_backend {
65
-    iniset $DESIGNATE_CONF pool_target:$DESIGNATE_TARGET_ID type dynect
66
-    iniset $DESIGNATE_CONF pool_target:$DESIGNATE_TARGET_ID masters $DESIGNATE_DYNECT_MASTERS
67
-    iniset $DESIGNATE_CONF pool_target:$DESIGNATE_TARGET_ID options "customer_name: $DESIGNATE_DYNECT_CUSTOMER, username: $DESIGNATE_DYNECT_USERNAME, password: $DESIGNATE_DYNECT_PASSWORD"
65
+    # Generate Designate pool.yaml file
66
+    sudo tee $DESIGNATE_CONF_DIR/pools.yaml > /dev/null <<EOF
67
+---
68
+- name: default
69
+  description: DevStack DynECT Pool
70
+  attributes: {}
71
+
72
+  targets:
73
+    - type: dynect
74
+      description: DynECT API
75
+
76
+      options:
77
+        customer_name: $DESIGNATE_DYNECT_CUSTOMER
78
+        username: $DESIGNATE_DYNECT_USERNAME
79
+        password: $DESIGNATE_DYNECT_PASSWORD
80
+
81
+      masters:
82
+EOF
83
+
84
+    # Create a Pool Master for each of the DynECT Masters
85
+    IFS=',' read -a masters <<< "$DESIGNATE_DYNECT_MASTERS"
86
+
87
+    for master in "${masters[@]}"; do
88
+        sudo tee -a $DESIGNATE_CONF_DIR/pools.yaml > /dev/null <<EOF
89
+        - host: $master
90
+          port: 53
91
+EOF
92
+    done
68 93
 
69
-    # Create a Pool Nameserver for each of the DynECT nameservers
70
-    local nameserver_ids=""
94
+    # Create a Pool NS Record for each of the DynECT Nameservers
71 95
     IFS=',' read -a nameservers <<< "$DESIGNATE_DYNECT_NAMESERVERS"
72 96
 
73
-    for nameserver in "${nameservers[@]}"; do
74
-        local nameserver_id=`uuidgen`
75
-        iniset $DESIGNATE_CONF pool_nameserver:$nameserver_id host $(dig +short A $nameserver | head -n 1)
76
-        iniset $DESIGNATE_CONF pool_nameserver:$nameserver_id port 53
97
+    sudo tee -a $DESIGNATE_CONF_DIR/pools.yaml > /dev/null <<EOF
98
+  ns_records:
99
+EOF
77 100
 
78
-        # Append the Nameserver ID to the list
79
-        nameserver_ids+=${nameserver_id},
101
+    for nameserver in "${nameservers[@]}"; do
102
+        sudo tee -a $DESIGNATE_CONF_DIR/pools.yaml > /dev/null <<EOF
103
+    - hostname: $nameserver
104
+      priority: 1
105
+EOF
80 106
     done
81 107
 
82
-    # Configure the Pool for the set of nameserver IDs, minus the trailing comma
83
-    iniset $DESIGNATE_CONF pool:$DESIGNATE_POOL_ID nameservers "${nameserver_ids:0:-1}"
84
-
85
-    # Configure the Pool to Notify DynECT's Transfer Agents
86
-    iniset $DESIGNATE_CONF pool:$DESIGNATE_POOL_ID also_notifies "$DESIGNATE_DYNECT_ALSO_NOTIFIES"
108
+    # Create a Pool Nameserver for each of the DynECT Nameservers
109
+    sudo tee -a $DESIGNATE_CONF_DIR/pools.yaml > /dev/null <<EOF
110
+  nameservers:
111
+EOF
87 112
 
88
-    # Global DynECT Backend Settings
89
-    if [ ! -z $DESIGNATE_DYNECT_JOB_TIMEOUT ]; then
90
-        iniset $DESIGNATE_CONF backend:dynect job_timeout "$DESIGNATE_DYNECT_JOB_TIMEOUT"
91
-    fi
113
+    for nameserver in "${nameservers[@]}"; do
114
+        sudo tee -a $DESIGNATE_CONF_DIR/pools.yaml > /dev/null <<EOF
115
+    - host: `dig +short A $nameserver | head -n 1`
116
+      port: 53
117
+EOF
118
+    done
92 119
 
93
-    if [ ! -z $DESIGNATE_DYNECT_TIMEOUT ]; then
94
-        iniset $DESIGNATE_CONF backend:dynect timeout "$DESIGNATE_DYNECT_TIMEOUT"
95
-    fi
96
-}
120
+    # Create a Pool Also Notifies for each of the DynECT Also Notifies
121
+    IFS=',' read -a also_notifies <<< "$DESIGNATE_DYNECT_ALSO_NOTIFIES"
97 122
 
98
-# create_designate_ns_records - Create Pool NS Records
99
-function create_designate_ns_records_backend {
100
-    # Build an array of the DynECT nameservers.
101
-    IFS=',' read -a ns_records <<< "$DESIGNATE_DYNECT_NAMESERVERS"
123
+    sudo tee -a $DESIGNATE_CONF_DIR/pools.yaml > /dev/null <<EOF
124
+  also_notifies:
125
+EOF
102 126
 
103
-    # Create a NS Record for each of the DynECT nameservers
104
-    for ns_record in "${ns_records[@]}"; do
105
-        designate server-create --name "${ns_record%%.}."
127
+    for also_notify in "${also_notifies[@]}"; do
128
+        sudo tee -a $DESIGNATE_CONF_DIR/pools.yaml > /dev/null <<EOF
129
+    - host: $also_notify
130
+      port: 53
131
+EOF
106 132
     done
107 133
 }
108 134
 

+ 15
- 1
devstack/designate_plugins/backend-fake View File

@@ -31,7 +31,21 @@ function install_designate_backend {
31 31
 
32 32
 # configure_designate_backend - make configuration changes, including those to other services
33 33
 function configure_designate_backend {
34
-    :
34
+    # Generate Designate pool.yaml file
35
+    sudo tee $DESIGNATE_CONF_DIR/pools.yaml > /dev/null <<EOF
36
+---
37
+- name: default
38
+  description: DevStack Fake Pool
39
+  attributes: {}
40
+
41
+  ns_records:
42
+    - hostname: $DESIGNATE_DEFAULT_NS_RECORD
43
+      priority: 1
44
+
45
+  targets:
46
+    - type: fake
47
+      description: Fake Backend
48
+EOF
35 49
 }
36 50
 
37 51
 # init_designate_backend - initialize databases, etc.

+ 28
- 9
devstack/designate_plugins/backend-infoblox View File

@@ -53,15 +53,6 @@ function install_designate_backend {
53 53
 
54 54
 # configure_designate_backend - make configuration changes, including those to other services
55 55
 function configure_designate_backend {
56
-    iniset $DESIGNATE_CONF pool_target:$DESIGNATE_TARGET_ID type infoblox
57
-    iniset $DESIGNATE_CONF pool_target:$DESIGNATE_TARGET_ID masters $DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT_MDNS
58
-    iniset $DESIGNATE_CONF pool_target:$DESIGNATE_TARGET_ID options "host: $DESIGNATE_INFOBLOX_NAMESERVER_IP, port: $DESIGNATE_SERVICE_PORT_DNS"
59
-
60
-    local nameserver_id=`uuidgen`
61
-    iniset $DESIGNATE_CONF pool:$DESIGNATE_POOL_ID nameservers $nameserver_id
62
-    iniset $DESIGNATE_CONF pool_nameserver:$nameserver_id host $DESIGNATE_INFOBLOX_NAMESERVER_IP
63
-    iniset $DESIGNATE_CONF pool_nameserver:$nameserver_id port $DESIGNATE_SERVICE_PORT_DNS
64
-
65 56
     iniset $DESIGNATE_CONF backend:infoblox wapi_url $DESIGNATE_INFOBLOX_WAPI_URL
66 57
     iniset $DESIGNATE_CONF backend:infoblox username $DESIGNATE_INFOBLOX_USERNAME
67 58
     iniset $DESIGNATE_CONF backend:infoblox password $DESIGNATE_INFOBLOX_PASSWORD
@@ -72,6 +63,34 @@ function configure_designate_backend {
72 63
     iniset $DESIGNATE_CONF backend:infoblox dns_view $DESIGNATE_INFOBLOX_DNS_VIEW
73 64
     iniset $DESIGNATE_CONF backend:infoblox net_view $DESIGNATE_INFOBLOX_NET_VIEW
74 65
     iniset $DESIGNATE_CONF backend:infoblox ns_group $DESIGNATE_INFOBLOX_NS_GROUP
66
+
67
+    # Generate Designate pool.yaml file
68
+    sudo tee $DESIGNATE_CONF_DIR/pools.yaml > /dev/null <<EOF
69
+---
70
+- name: default
71
+  description: DevStack InfoBlox Pool
72
+  attributes: {}
73
+
74
+  ns_records:
75
+    - hostname: $DESIGNATE_DEFAULT_NS_RECORD
76
+      priority: 1
77
+
78
+  nameservers:
79
+    - host: $DESIGNATE_INFOBLOX_NAMESERVER_IP
80
+      port: $DESIGNATE_SERVICE_PORT_DNS
81
+
82
+  targets:
83
+    - type: powerdns
84
+      description: InfoBlox Cluster API
85
+
86
+      masters:
87
+        - host: $DESIGNATE_SERVICE_HOST
88
+          port: $DESIGNATE_SERVICE_PORT_MDNS
89
+
90
+      options:
91
+        host: $DESIGNATE_INFOBLOX_NAMESERVER_IP
92
+        port: $DESIGNATE_SERVICE_PORT_DNS
93
+EOF
75 94
 }
76 95
 
77 96
 # init_designate_backend - initialize databases, etc.

+ 0
- 77
devstack/designate_plugins/backend-ipa View File

@@ -1,77 +0,0 @@
1
-# Configure the ipa backend
2
-
3
-# Enable with:
4
-# DESIGNATE_BACKEND_DRIVER=ipa
5
-
6
-# Dependencies:
7
-# ``functions`` file
8
-# ``designate`` configuration
9
-
10
-# install_designate_backend - install any external requirements
11
-# configure_designate_backend - make configuration changes, including those to other services
12
-# init_designate_backend - initialize databases, etc.
13
-# start_designate_backend - start any external services
14
-# stop_designate_backend - stop any external services
15
-# cleanup_designate_backend - remove transient data and cache
16
-
17
-# Save trace setting
18
-DP_IPA_XTRACE=$(set +o | grep xtrace)
19
-set +o xtrace
20
-
21
-# Defaults
22
-# --------
23
-DESIGNATE_IPA_HOST=${DESIGNATE_IPA_HOST:-$(hostname)}
24
-DESIGNATE_IPA_CA_CERT=${DESIGNATE_IPA_CA_CERT:-/etc/ipa/ca.crt}
25
-DESIGNATE_IPA_CLIENT_KEYTAB=${DESIGNATE_IPA_CLIENT_KEYTAB:-$HOME/ipaadmin.keytab}
26
-
27
-# Entry Points
28
-# ------------
29
-
30
-# install_designate_backend - install any external requirements
31
-function install_designate_backend {
32
-    :
33
-}
34
-
35
-# configure_designate_backend - make configuration changes, including those to other services
36
-function configure_designate_backend {
37
-    rc=0
38
-    if [[ ! -f $DESIGNATE_IPA_CA_CERT ]]; then
39
-        echo ERROR: IPA CA cert file $DESIGNATE_IPA_CA_CERT not found
40
-        rc=1
41
-    fi
42
-    if [[ ! -f $DESIGNATE_IPA_CLIENT_KEYTAB ]]; then
43
-        echo ERROR: IPA client keytab file $DESIGNATE_IPA_CLIENT_KEYTAB not found
44
-        rc=1
45
-    fi
46
-    if [[ $rc = 1 ]]; then
47
-        die $LINENO "Error with IPA configuration"
48
-    fi
49
-    iniset $DESIGNATE_CONF backend:ipa ipa_host $DESIGNATE_IPA_HOST
50
-    iniset $DESIGNATE_CONF backend:ipa ipa_ca_cert $DESIGNATE_IPA_CA_CERT
51
-    iniset $DESIGNATE_CONF backend:ipa ipa_client_keytab $DESIGNATE_IPA_CLIENT_KEYTAB
52
-    # devstack tests use dummy NS records, so tell IPA to allow this
53
-    iniset $DESIGNATE_CONF backend:ipa ipa_force_ns_use True
54
-}
55
-
56
-# init_designate_backend - initialize databases, etc.
57
-function init_designate_backend {
58
-    :
59
-}
60
-
61
-# start_designate_backend - start any external services
62
-function start_designate_backend {
63
-    :
64
-}
65
-
66
-# stop_designate_backend - stop any external services
67
-function stop_designate_backend {
68
-    :
69
-}
70
-
71
-# cleanup_designate_backend - remove transient data and cache
72
-function cleanup_designate_backend {
73
-    :
74
-}
75
-
76
-# Restore xtrace
77
-$DP_IPA_XTRACE

+ 34
- 10
devstack/designate_plugins/backend-powerdns View File

@@ -53,16 +53,36 @@ function install_designate_backend {
53 53
 
54 54
 # configure_designate_backend - make configuration changes, including those to other services
55 55
 function configure_designate_backend {
56
-    iniset $DESIGNATE_CONF pool_target:$DESIGNATE_TARGET_ID type powerdns
57
-    iniset $DESIGNATE_CONF pool_target:$DESIGNATE_TARGET_ID masters $DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT_MDNS
58
-    iniset $DESIGNATE_CONF pool_target:$DESIGNATE_TARGET_ID options "connection: `database_connection_url designate_pdns`, host: $DESIGNATE_SERVICE_HOST, port: $DESIGNATE_SERVICE_PORT_DNS"
59
-
60
-    # DevStack Managed PDNS NameServer
61
-    local nameserver_id=`uuidgen`
62
-    iniset $DESIGNATE_CONF pool:$DESIGNATE_POOL_ID nameservers $nameserver_id
63
-    iniset $DESIGNATE_CONF pool_nameserver:$nameserver_id host $DESIGNATE_SERVICE_HOST
64
-    iniset $DESIGNATE_CONF pool_nameserver:$nameserver_id port $DESIGNATE_SERVICE_PORT_DNS
56
+    # Generate Designate pool.yaml file
57
+    sudo tee $DESIGNATE_CONF_DIR/pools.yaml > /dev/null <<EOF
58
+---
59
+- name: default
60
+  description: DevStack PowerDNS Pool
61
+  attributes: {}
62
+
63
+  ns_records:
64
+    - hostname: $DESIGNATE_DEFAULT_NS_RECORD
65
+      priority: 1
66
+
67
+  nameservers:
68
+    - host: $DESIGNATE_SERVICE_HOST
69
+      port: $DESIGNATE_SERVICE_PORT_DNS
70
+
71
+  targets:
72
+    - type: powerdns
73
+      description: PowerDNS Database Cluster
74
+
75
+      masters:
76
+        - host: $DESIGNATE_SERVICE_HOST
77
+          port: $DESIGNATE_SERVICE_PORT_MDNS
78
+
79
+      options:
80
+        host: $DESIGNATE_SERVICE_HOST
81
+        port: $DESIGNATE_SERVICE_PORT_DNS
82
+        connection: '`database_connection_url designate_pdns`'
83
+EOF
65 84
 
85
+    # Generate PowerDNS pdns.conf file
66 86
     sudo tee $POWERDNS_CFG_DIR/pdns.conf > /dev/null <<EOF
67 87
 # General Config
68 88
 setgid=pdns
@@ -123,9 +143,12 @@ function init_designate_backend {
123 143
 
124 144
     # (Re)create designate_pdns database
125 145
     recreate_database designate_pdns utf8
146
+}
126 147
 
148
+# create_designate_pool_configuration_backend - Perform post-pool config tasks
149
+function create_designate_pool_configuration_backend {
127 150
     # Init and migrate designate_pdns database
128
-    designate-manage powerdns sync $DESIGNATE_TARGET_ID
151
+    designate-manage powerdns sync $DESIGNATE_POOL_ID
129 152
 }
130 153
 
131 154
 # start_designate_backend - start any external services
@@ -133,6 +156,7 @@ function start_designate_backend {
133 156
     start_service pdns
134 157
 }
135 158
 
159
+
136 160
 # stop_designate_backend - stop any external services
137 161
 function stop_designate_backend {
138 162
     stop_service pdns

+ 12
- 13
devstack/plugin.sh View File

@@ -49,6 +49,7 @@ function configure_designate {
49 49
 
50 50
     # General Configuration
51 51
     iniset_rpc_backend designate $DESIGNATE_CONF DEFAULT
52
+    iniset $DESIGNATE_CONF DEFAULT rpc_response_timeout 5
52 53
 
53 54
     iniset $DESIGNATE_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL
54 55
     iniset $DESIGNATE_CONF DEFAULT verbose True
@@ -76,9 +77,6 @@ function configure_designate {
76 77
         iniset $DESIGNATE_CONF pool_manager_cache:sqlalchemy connection `database_connection_url designate_pool_manager`
77 78
     fi
78 79
 
79
-    # Pool Options
80
-    iniset $DESIGNATE_CONF pool:$DESIGNATE_POOL_ID targets $DESIGNATE_TARGET_ID
81
-
82 80
     # API Configuration
83 81
     sudo cp $DESIGNATE_DIR/etc/designate/api-paste.ini $DESIGNATE_APIPASTE_CONF
84 82
     iniset $DESIGNATE_CONF service:api enabled_extensions_v1 $DESIGNATE_ENABLED_EXTENSIONS_V1
@@ -185,13 +183,14 @@ function create_designate_accounts {
185 183
     fi
186 184
 }
187 185
 
188
-# create_designate_ns_records - Create Pool NS Records
189
-function create_designate_ns_records {
190
-    # Allow Backends to install their own NS Records rather than the default
191
-    if function_exists create_designate_ns_records_backend; then
192
-        create_designate_ns_records_backend
193
-    else
194
-        designate server-create --name $DESIGNATE_DEFAULT_NS_RECORD
186
+# create_designate_pool_configuration - Create Pool Configuration
187
+function create_designate_pool_configuration {
188
+    # Sync Pools Config
189
+    designate-manage pool update --file $DESIGNATE_CONF_DIR/pools.yaml
190
+
191
+    # Allow Backends to do backend specific tasks
192
+    if function_exists create_designate_pool_configuration_backend; then
193
+        create_designate_pool_configuration_backend
195 194
     fi
196 195
 }
197 196
 
@@ -320,14 +319,14 @@ if is_service_enabled designate; then
320 319
         echo_summary "Initializing Designate"
321 320
         init_designate
322 321
 
323
-        echo "Configuring Tempest options for Designate"
322
+        echo_summary "Configuring Tempest options for Designate"
324 323
         configure_designate_tempest
325 324
 
326 325
         echo_summary "Starting Designate"
327 326
         start_designate
328 327
 
329
-        echo_summary "Creating pool NS records"
330
-        create_designate_ns_records
328
+        echo_summary "Creating Pool Configuration"
329
+        create_designate_pool_configuration
331 330
     fi
332 331
 
333 332
     if [[ "$1" == "unstack" ]]; then

+ 0
- 1
devstack/settings View File

@@ -2,7 +2,6 @@
2 2
 DESIGNATE_BACKEND_DRIVER=${DESIGNATE_BACKEND_DRIVER:=powerdns}
3 3
 DESIGNATE_POOL_MANAGER_CACHE_DRIVER=${DESIGNATE_POOL_MANAGER_CACHE_DRIVER:-memcache}
4 4
 DESIGNATE_POOL_ID=${DESIGNATE_POOL_ID:-794ccc2c-d751-44fe-b57f-8894c9f5c842}
5
-DESIGNATE_TARGET_ID=${DESIGNATE_TARGET_ID:-f26e0b32-736f-4f0a-831b-039a415c481e}
6 5
 DESIGNATE_DEFAULT_NS_RECORD=${DESIGNATE_DEFAULT_NS_RECORD:-ns1.devstack.org.}
7 6
 DESIGNATE_NOTIFICATION_DRIVER=${DESIGNATE_NOTIFICATION_DRIVER:-}
8 7
 DESIGNATE_NOTIFICATION_TOPICS=${DESIGNATE_NOTIFICATION_TOPICS:-notifications}

+ 61
- 0
doc/source/pools.rst View File

@@ -62,3 +62,64 @@ but it will **not** trigger zones to be moved from one pool to another.
62 62
     As more filters are merged there will be support for dynamic filters.
63 63
 
64 64
 
65
+Managing Pools
66
+==============
67
+
68
+In mitaka we moved the method of updating pools to a CLI in `designate-manage`
69
+
70
+There is a YAML file that defines the pool, and is used to load this information into the database.
71
+
72
+
73
+.. literalinclude:: ../../etc/designate/pools.yaml.sample
74
+       :language: yaml
75
+
76
+Designate Manage Pools Command Reference
77
+----------------------------------------
78
+
79
+Update Pools Information
80
+^^^^^^^^^^^^^^^^^^^^^^^^
81
+
82
+.. code-block:: language
83
+
84
+  designate-manage pool update [options]
85
+
86
+Options:
87
+""""""""
88
+
89
+  --file        Input file (Default: ``/etc/designate/pools.yaml``)
90
+  --dry_run     Simulate an update. (Default: False)
91
+  --delete      Delete Pools that are not in the input file (Defaults: False)
92
+
93
+.. warning::
94
+
95
+  | Running with ``--delete True`` can be **extremely** dangerous.
96
+  | It will delete any pools that are not in the supplied YAML file, and any
97
+  | zones that are in that Pool.
98
+  | Before running with ``--delete True`` we recommend operators run with
99
+  | ``--delete True --dry_run True`` to view the outcome.
100
+
101
+
102
+
103
+Generate YAML File
104
+^^^^^^^^^^^^^^^^^^
105
+
106
+.. code-block:: language
107
+
108
+    designate-manage pool generate_file [options]
109
+
110
+Options:
111
+""""""""
112
+
113
+  --file        YAML file output too (Default: ``/etc/designate/pools.yaml``)
114
+
115
+Generate YAML File from Liberty Config
116
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
117
+
118
+.. code-block:: language
119
+
120
+    designate-manage pool export_from_config [options]
121
+
122
+Options:
123
+""""""""
124
+
125
+  --file        YAML file output too (Default: ``/etc/designate/pools.yaml``)

+ 94
- 0
doc/source/upgrade/mitaka.rst View File

@@ -0,0 +1,94 @@
1
+..
2
+    Copyright 2016 Hewlett Packard Enterprise Development Company, L.P.
3
+
4
+    Licensed under the Apache License, Version 2.0 (the "License"); you may
5
+    not use this file except in compliance with the License. You may obtain
6
+    a copy of the License at
7
+
8
+        http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+    Unless required by applicable law or agreed to in writing, software
11
+    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
+    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
+    License for the specific language governing permissions and limitations
14
+    under the License.
15
+
16
+********************************
17
+Upgrading to Mitaka from Liberty
18
+********************************
19
+
20
+.. note:: This is a WIP - it will be updated as more items are added to Mitaka
21
+
22
+Pools Configuration
23
+===================
24
+
25
+We have updated how the config data for pools is now stored.
26
+
27
+Previously there was a mix of content in the ``designate.conf`` file and in the
28
+designate database.
29
+
30
+We have moved all of the data to the database in Mitaka, to avoid confusion, and
31
+avoid the massive complexity that exists in the config file.
32
+
33
+.. warning:: This part of the upgrade **requires** downtime.
34
+
35
+We have 2 new commands in the ``designate-manage`` utility that are able to assist
36
+the migration.
37
+
38
+To make the config syntax simpler we have a new YAML based config file that is
39
+used to load information into the database.
40
+
41
+.. literalinclude:: ../../../etc/designate/pools.yaml.sample
42
+       :language: yaml
43
+
44
+We have a command that will allow you to take your current running config, and
45
+export it to the new YAML format.
46
+
47
+.. note::
48
+
49
+    You will need to have at least one instance of central running, and machine
50
+    ``designate-manage`` is running on will need access to the messageing queue
51
+
52
+.. code-block:: console
53
+
54
+    designate-manage pool generate_file --file output.yml
55
+
56
+This will create a YAML file, with all the currently defined pools, and all of their config.
57
+
58
+We suggest this is then migrated into a config management system, or other document management system.
59
+
60
+From this point on all updated to pools should be one by updating this file, and
61
+running:
62
+
63
+.. code-block:: console
64
+
65
+    designate-manage pool update --file /path/to/file.yml
66
+
67
+
68
+Pools - Step by Step
69
+--------------------
70
+
71
+1. Ensure there is not 2 pools with the same name.
72
+2. Stop all Designate Services.
73
+3. Deploy new Mitaka code
74
+4. Start ``designate-central``
75
+5. Run
76
+    .. code-block:: console
77
+
78
+        designate-manage pool export_from_config --file output.yml
79
+
80
+6. Ensure the output file is correct (reference sample file for each value)
81
+7. Run
82
+
83
+    .. code-block:: console
84
+
85
+        designate-manage pool update --file output.yml --dry_run True --delete True
86
+
87
+8. Ensure the output of this command is not removing any Pools
88
+9. Run
89
+
90
+   .. code-block:: console
91
+
92
+        designate-manage pool generate_file --file output.yml --delete True
93
+
94
+10. Start the remaining designate services.

+ 54
- 0
etc/designate/pools.yaml.sample View File

@@ -0,0 +1,54 @@