designate-2.0.0/0000775000567000056710000000000012701406373014620 5ustar jenkinsjenkins00000000000000designate-2.0.0/functionaltests/0000775000567000056710000000000012701406373020045 5ustar jenkinsjenkins00000000000000designate-2.0.0/functionaltests/__init__.py0000664000567000056710000000016712701406241022154 0ustar jenkinsjenkins00000000000000import logging logging.basicConfig( filename='functional-tests.log', filemode='w', level=logging.DEBUG, ) designate-2.0.0/functionaltests/common/0000775000567000056710000000000012701406373021335 5ustar jenkinsjenkins00000000000000designate-2.0.0/functionaltests/common/datagen.py0000664000567000056710000001606612701406241023315 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ import uuid import random from functionaltests.api.v2.models.blacklist_model import BlacklistModel from functionaltests.api.v2.models.pool_model import PoolModel from functionaltests.api.v2.models.transfer_requests_model import \ TransferRequestsModel from functionaltests.api.v2.models.transfer_accepts_model import \ TransferAcceptsModel from functionaltests.api.v2.models.recordset_model import RecordsetModel from functionaltests.api.v2.models.zone_model import ZoneModel from functionaltests.api.v2.models.tld_model import TLDModel def random_ip(): return ".".join(str(random.randrange(0, 256)) for _ in range(4)) def random_ipv6(): def hexes(n): return "".join(random.choice("1234567890abcdef") for _ in range(n)) result = ":".join(hexes(4) for _ in range(8)) return result.replace("0000", "0") def random_uuid(): return uuid.uuid4() def random_string(prefix='rand', n=8, suffix=''): """Return a string containing random digits :param prefix: the exact text to start the string. Defaults to "rand" :param n: the number of random digits to generate :param suffix: the exact text to end the string """ digits = "".join(str(random.randrange(0, 10)) for _ in range(n)) return prefix + digits + suffix def random_zone_data(name=None, email=None, ttl=None, description=None): """Generate random zone data, with optional overrides :return: A ZoneModel """ if name is None: name = random_string(prefix='testdomain', suffix='.com.') if email is None: email = ("admin@" + name).strip('.') if description is None: description = random_string(prefix='Description ') if ttl is None: ttl = random.randint(1200, 8400), return ZoneModel.from_dict({ 'name': name, 'email': email, 'ttl': random.randint(1200, 8400), 'description': description}) def random_transfer_request_data(description=None, target_project_id=None): """Generate random zone data, with optional overrides :return: A TransferRequestModel """ data = {} if description is None: data['description'] = random_string(prefix='Description ') if target_project_id: data['target_project_id'] = target_project_id return TransferRequestsModel.from_dict(data) def random_transfer_accept_data(key=None, zone_transfer_request_id=None): """Generate random zone data, with optional overrides :return: A TransferRequestModel """ if key is None: key = random_string() if zone_transfer_request_id is None: zone_transfer_request_id = random_uuid() return TransferAcceptsModel.from_dict({ 'key': key, 'zone_transfer_request_id': zone_transfer_request_id}) def random_recordset_data(record_type, zone_name, name=None, records=None, ttl=None): """Generate random recordset data, with optional overrides :return: A RecordsetModel """ if name is None: name = random_string(prefix=record_type, suffix='.' + zone_name) if records is None: records = [random_ip()] if ttl is None: ttl = random.randint(1200, 8400) return RecordsetModel.from_dict({ 'type': record_type, 'name': name, 'records': records, 'ttl': ttl}) def random_a_recordset(zone_name, ip=None, **kwargs): if ip is None: ip = random_ip() return random_recordset_data('A', zone_name, records=[ip], **kwargs) def random_aaaa_recordset(zone_name, ip=None, **kwargs): if ip is None: ip = random_ipv6() return random_recordset_data('AAAA', zone_name, records=[ip], **kwargs) def random_cname_recordset(zone_name, cname=None, **kwargs): if cname is None: cname = zone_name return random_recordset_data('CNAME', zone_name, records=[cname], **kwargs) def random_mx_recordset(zone_name, pref=None, host=None, **kwargs): if pref is None: pref = str(random.randint(0, 65535)) if host is None: host = random_string(prefix='mail', suffix='.' + zone_name) data = "{0} {1}".format(pref, host) return random_recordset_data('MX', zone_name, records=[data], **kwargs) def random_blacklist_data(): data = { "pattern": random_string() } return BlacklistModel.from_dict(data) def random_pool_data(): ns_zone = random_zone_data().name data = { "name": random_string(), } records = [] for i in range(0, 2): records.append("ns%s.%s" % (i, ns_zone)) ns_records = [{"hostname": x, "priority": random.randint(1, 999)} for x in records] data["ns_records"] = ns_records return PoolModel.from_dict(data) def random_zonefile_data(name=None, ttl=None): """Generate random zone data, with optional overrides :return: A ZoneModel """ zone_base = ('$ORIGIN &\n& # IN SOA ns.& nsadmin.& # # # # #\n' '& # IN NS ns.&\n& # IN MX 10 mail.&\nns.& 360 IN A 1.0.0.1') if name is None: name = random_string(prefix='testdomain', suffix='.com.') if ttl is None: ttl = str(random.randint(1200, 8400)) return zone_base.replace('&', name).replace('#', ttl) def random_spf_recordset(zone_name, data=None, **kwargs): data = data or "v=spf1 +all" return random_recordset_data('SPF', zone_name, records=[data], **kwargs) def random_srv_recordset(zone_name, data=None): data = data or "10 0 8080 %s.%s" % (random_string(), zone_name) return random_recordset_data('SRV', zone_name, name="_sip._tcp.%s" % zone_name, records=[data]) def random_sshfp_recordset(zone_name, algorithm_number=None, fingerprint_type=None, fingerprint=None, **kwargs): algorithm_number = algorithm_number or 2 fingerprint_type = fingerprint_type or 1 fingerprint = fingerprint or \ "123456789abcdef67890123456789abcdef67890" data = "%s %s %s" % (algorithm_number, fingerprint_type, fingerprint) return random_recordset_data('SSHFP', zone_name, records=[data], **kwargs) def random_txt_recordset(zone_name, data=None, **kwargs): data = data or "v=spf1 +all" return random_recordset_data('TXT', zone_name, records=[data], **kwargs) def random_tld_data(): data = { "name": random_string(prefix='tld') } return TLDModel.from_dict(data) def wildcard_ns_recordset(zone_name): name = "*.{0}".format(zone_name) records = ["ns.example.com."] return random_recordset_data('NS', zone_name, name, records) designate-2.0.0/functionaltests/common/utils.py0000664000567000056710000000724512701406241023051 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ import collections import functools import time import types import netaddr def def_method(f, *args, **kwargs): @functools.wraps(f) def new_method(self): return f(self, *args, **kwargs) return new_method def parameterized_class(cls): """A class decorator for running parameterized test cases. Mark your class with @parameterized_class. Mark your test cases with @parameterized. """ test_functions = { k: v for k, v in vars(cls).items() if k.startswith('test') } for name, f in test_functions.items(): if not hasattr(f, '_test_data'): continue # remove the original test function from the class delattr(cls, name) # add a new test function to the class for each entry in f._test_data for tag, args in f._test_data.items(): new_name = "{0}_{1}".format(f.__name__, tag) if hasattr(cls, new_name): raise Exception( "Parameterized test case '{0}.{1}' created from '{0}.{2}' " "already exists".format(cls.__name__, new_name, name)) # Using `def new_method(self): f(self, **args)` is not sufficient # (all new_methods use the same args value due to late binding). # Instead, use this factory function. new_method = def_method(f, **args) # To add a method to a class, available for all instances: # MyClass.method = types.MethodType(f, None, MyClass) setattr(cls, new_name, types.MethodType(new_method, None, cls)) return cls def parameterized(data): """A function decorator for parameterized test cases. Example: @parameterized({ 'zero': dict(val=0), 'one': dict(val=1), }) def test_val(self, val): self.assertEqual(self.get_val(), val) The above will generate two test cases: `test_val_zero` which runs with val=0 `test_val_one` which runs with val=1 :param data: A dictionary that looks like {tag: {arg1: val1, ...}} """ def wrapped(f): f._test_data = data return f return wrapped def wait_for_condition(condition, interval=5, timeout=45): end_time = time.time() + timeout while time.time() < end_time: result = condition() if result: return result time.sleep(interval) raise Exception("Timed out after {0} seconds".format(timeout)) def memoized(func): """A decorator to cache function's return value""" cache = {} @functools.wraps(func) def wrapper(*args): if not isinstance(args, collections.Hashable): # args is not cacheable. just call the function. return func(*args) if args in cache: return cache[args] else: value = func(*args) cache[args] = value return value return wrapper def shorten_ipv6_addrs(addrs): """Shorten ipv6 addresses""" new_addrs = [] for a in addrs: an = netaddr.IPAddress(a, version=6) new_addrs.append(an.format(netaddr.ipv6_compact)) return new_addrs designate-2.0.0/functionaltests/common/__init__.py0000664000567000056710000000000012701406241023426 0ustar jenkinsjenkins00000000000000designate-2.0.0/functionaltests/common/config.py0000664000567000056710000000602212701406241023146 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ import os from oslo_config import cfg cfg.CONF.register_group(cfg.OptGroup( name='identity', title="Configuration for Keystone identity" )) cfg.CONF.register_group(cfg.OptGroup( name='auth', title="Configuration for Keystone auth" )) cfg.CONF.register_group(cfg.OptGroup( name='noauth', title="Configuration to run tests without Keystone" )) cfg.CONF.register_group(cfg.OptGroup( name='testconfig', title="Configuration to customize how the tests run" )) cfg.CONF.register_opts([ cfg.StrOpt('designate_override_url', help="Use this instead of the endpoint in the service catalog"), cfg.StrOpt('uri', help="The Keystone v2 endpoint"), cfg.StrOpt('uri_v3', help="The Keystone v3 endpoint"), cfg.StrOpt('auth_version', default='v2'), cfg.StrOpt('region'), cfg.StrOpt('username'), cfg.StrOpt('tenant_name'), cfg.StrOpt('password', secret=True), cfg.StrOpt('domain_name'), cfg.StrOpt('alt_username'), cfg.StrOpt('alt_tenant_name'), cfg.StrOpt('alt_password', secret=True), cfg.StrOpt('alt_domain_name'), ], group='identity') cfg.CONF.register_opts([ cfg.StrOpt('admin_username'), cfg.StrOpt('admin_tenant_name'), cfg.StrOpt('admin_password', secret=True), cfg.StrOpt('admin_domain_name'), ], group="auth") cfg.CONF.register_opts([ cfg.StrOpt('designate_endpoint', help="The Designate API endpoint"), cfg.StrOpt('tenant_id', default='noauth-project'), cfg.StrOpt('alt_tenant_id', default='alt-project'), cfg.StrOpt('admin_tenant_id', default='admin-project'), cfg.BoolOpt('use_noauth', default=False), ], group='noauth') cfg.CONF.register_opts([ cfg.ListOpt('nameservers', default=["127.0.0.1:53"]), cfg.StrOpt('interface', default='public'), cfg.StrOpt('service', default='dns') ], group="designate") cfg.CONF.register_opts([ cfg.ListOpt('hooks', default=[], help="The list of request hook class names to enable"), cfg.StrOpt('v2_path_pattern', default='/v2/{path}', help="Specifies how to build the path for the request"), cfg.BoolOpt('no_admin_setup', default=False, help="Skip admin actions (like increasing quotas) in setUp()"), cfg.BoolOpt('disable_ssl_certificate_validation', default=False), ], group='testconfig') def find_config_file(): return os.environ.get( 'TEMPEST_CONFIG', '/opt/stack/tempest/etc/tempest.conf') def read_config(): cfg.CONF(args=[], default_config_files=[find_config_file()]) designate-2.0.0/functionaltests/common/base.py0000664000567000056710000000162712701406241022621 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ import tempest_lib.base from functionaltests.common.config import read_config class BaseDesignateTest(tempest_lib.base.BaseTestCase): def __init__(self, *args, **kwargs): super(BaseDesignateTest, self).__init__(*args, **kwargs) @classmethod def setUpClass(cls): super(BaseDesignateTest, cls).setUpClass() read_config() designate-2.0.0/functionaltests/common/test_meta.py0000664000567000056710000000542612701406241023675 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from functionaltests.api.v2.models.recordset_model import RecordsetModel from functionaltests.common.models import ZoneFile from functionaltests.common.models import ZoneFileRecord import tempest_lib.base class MetaTest(tempest_lib.base.BaseTestCase): def test_zone_file_model_meta_test(self): zone_file = ZoneFile.from_text( """ $ORIGIN mydomain.com. $TTL 1234 mydomain.com. IN NS ns1.example.com. mydomain.com. IN SOA ns1.example.com. mail.mydomain.com. 1 2 3 4 5 """) self.assertEqual('mydomain.com.', zone_file.origin) self.assertEqual(1234, zone_file.ttl) ns_record = ZoneFileRecord( name='mydomain.com.', type='NS', data='ns1.example.com.') soa_record = ZoneFileRecord( name='mydomain.com.', type='SOA', data='ns1.example.com. mail.mydomain.com. 1 2 3 4 5') self.assertEqual(zone_file.records[0], ns_record) self.assertEqual(zone_file.records[1], soa_record) def test_zone_file_record_model_meta_test(self): record = ZoneFileRecord(name='one.com.', type='A', data='1.2.3.4') wrong_name = ZoneFileRecord(name='two.com.', type='A', data='1.2.3.4') wrong_type = ZoneFileRecord(name='one.com.', type='MX', data='1.2.3.4') wrong_data = ZoneFileRecord(name='one.com.', type='A', data='1.2.3.5') self.assertEqual(record, record) self.assertNotEqual(record, wrong_name) self.assertNotEqual(record, wrong_type) self.assertNotEqual(record, wrong_data) def test_zone_file_records_from_recordset(self): # we don't need all of the recordset's fields here recordset = RecordsetModel.from_dict({ "type": "NS", "name": "mydomain.com.", "records": ["ns1.a.com.", "ns2.a.com.", "ns3.a.com."], }) records = ZoneFileRecord.records_from_recordset(recordset) expected = [ ZoneFileRecord(name="mydomain.com.", type="NS", data="ns1.a.com."), ZoneFileRecord(name="mydomain.com.", type="NS", data="ns2.a.com."), ZoneFileRecord(name="mydomain.com.", type="NS", data="ns3.a.com."), ] self.assertEqual(expected, records) designate-2.0.0/functionaltests/common/models.py0000664000567000056710000001136712701406241023174 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ import json class BaseModel(object): @classmethod def from_json(cls, json_str): return cls.from_dict(json.loads(json_str)) def to_json(self): return json.dumps(self.to_dict()) @classmethod def from_dict(cls, data): model = cls() for key in data: setattr(model, key, data.get(key)) return model def to_dict(self): result = {} for key in self.__dict__: result[key] = getattr(self, key) if isinstance(result[key], BaseModel): result[key] = result[key].to_dict() return result def __str__(self): return "%s" % self.to_dict() class LinksModel(BaseModel): pass class MetadataModel(BaseModel): pass class CollectionModel(BaseModel): """ { 'collection_name' : [ ], 'links': { }, 'metdata': { }, } """ SUB_MODELS = { 'links': LinksModel, 'metadata': MetadataModel, } @classmethod def from_dict(cls, data): model = super(CollectionModel, cls).from_dict(data) # deserialize e.g. data['zones'] collection = [] if hasattr(model, cls.COLLECTION_NAME): for d in getattr(model, cls.COLLECTION_NAME): collection.append(cls.MODEL_TYPE.from_dict(d)) setattr(model, cls.COLLECTION_NAME, collection) # deserialize data['links'], data['metadata'], etc for key, model_type in cls.SUB_MODELS.items(): if hasattr(model, key): val = getattr(model, key) setattr(model, key, model_type.from_dict(val)) return model class EntityModel(BaseModel): """ { 'entity_name': { } } """ @classmethod def from_dict(cls, data): model = super(EntityModel, cls).from_dict(data) if hasattr(model, cls.ENTITY_NAME): val = getattr(model, cls.ENTITY_NAME) setattr(model, cls.ENTITY_NAME, cls.MODEL_TYPE.from_dict(val)) return model class ZoneFile(object): def __init__(self, origin, ttl, records): self.origin = origin self.ttl = ttl self.records = records def __str__(self): return str(self.__dict__) def __repr__(self): return str(self) def __eq__(self, other): return self.__dict__ == other.__dict__ @classmethod def from_text(cls, text): """Return a ZoneFile from a string containing the zone file contents""" # filter out empty lines and strip all leading/trailing whitespace. # this assumes no multiline records lines = [x.strip() for x in text.split('\n') if x.strip()] assert lines[0].startswith('$ORIGIN') assert lines[1].startswith('$TTL') return ZoneFile( origin=lines[0].split(' ')[1], ttl=int(lines[1].split(' ')[1]), records=[ZoneFileRecord.from_text(x) for x in lines[2:]], ) class ZoneFileRecord(object): def __init__(self, name, type, data): self.name = str(name) self.type = str(type) self.data = str(data) def __str__(self): return str(self.__dict__) def __repr__(self): return str(self) def __eq__(self, other): return self.__dict__ == other.__dict__ def __hash__(self): return hash(tuple(sorted(self.__dict__.items()))) @classmethod def from_text(cls, text): """Create a ZoneFileRecord from a line of text of a zone file, like: mydomain.com. IN NS ns1.example.com. """ # assumes records don't have a TTL between the name and the class. # assumes no parentheses in the record, all on a single line. parts = [x for x in text.split(' ', 4) if x.strip()] name, rclass, rtype, data = parts assert rclass == 'IN' return cls(name=name, type=rtype, data=data) @classmethod def records_from_recordset(cls, recordset): """Returns a list of ZoneFileRecords, one for each entry in the recordset's list of records """ return [ cls(name=recordset.name, type=recordset.type, data=data) for data in recordset.records ] designate-2.0.0/functionaltests/common/dnsclient.py0000664000567000056710000000300112701406241023656 0ustar jenkinsjenkins00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import os import dns.resolver from oslo_config import cfg from functionaltests.common import utils def query(name, type_, server="127.0.0.1", port=53, timeout=3): resolver = dns.resolver.Resolver() resolver.nameservers = [server] resolver.port = int(port) resolver.timeout = timeout try: return resolver.query(name, type_) except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): return False def query_servers(name, type_, servers=None, timeout=3): servers = servers or os.environ.get("DESIGNATE_SERVERS", cfg.CONF.designate.nameservers) results = [] for srv in servers: server, port = srv.split(":") port = port or 53 result = utils.wait_for_condition( lambda: query(name, type_, server, port)) results.append(result) return results designate-2.0.0/functionaltests/common/hooks/0000775000567000056710000000000012701406373022460 5ustar jenkinsjenkins00000000000000designate-2.0.0/functionaltests/common/hooks/__init__.py0000664000567000056710000000174512701406241024572 0ustar jenkinsjenkins00000000000000""" Copyright 2016 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ # a dictionary mapping the class name to the hook class _HOOKS = {} def register_hook(cls): """Register the request hook. This does not enable the hook. Hooks are enable via the config file. Usage: >>> register_hook(MyHook) """ _HOOKS[cls.__name__] = cls def get_class(name): """Get a hook class by it's class name: Usage: >>> get_hook_class('MyHook') """ return _HOOKS.get(name) designate-2.0.0/functionaltests/common/hooks/base.py0000664000567000056710000000251412701406241023740 0ustar jenkinsjenkins00000000000000""" Copyright 2016 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ class BaseRequestHook(object): """When writing your own hook, do three things: 1. Implement this hook interface 2. Register your hook in a global lookup using hook.register_hook() 3. Specify the name of your hook in a config file A new instance of a hook is created before for each request, for storing per request state if you want. """ def before(self, req_args, req_kwargs): """A hook called before each request :param req_args: a list (mutable) :param req_kwargs: a dictionary """ pass def after(self, resp, resp_body): """A hook called after each request""" pass def on_exception(self, exception): """A hook called when an exception occurs on a request""" pass designate-2.0.0/functionaltests/common/noauth.py0000664000567000056710000000363712701406241023210 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ import copy import re from six.moves.urllib import parse from tempest_lib.auth import AuthProvider class NoAuthAuthProvider(AuthProvider): def __init__(self, creds, override_url): super(NoAuthAuthProvider, self).__init__(creds) self.override_url = override_url @classmethod def check_credentials(cls, credentials): return True def base_url(self, *args, **kwargs): return self.override_url def _decorate_request(self, filters, method, url, headers=None, body=None, auth_data=None): base_url = self.base_url(filters=filters, auth_data=auth_data) # build the unauthenticated request _headers = copy.deepcopy(headers) if headers is not None else {} _headers['X-Auth-Project-ID'] = self.credentials.tenant_id if url is None or url == "": _url = base_url else: # Join base URL and url, and remove multiple contiguous slashes _url = "/".join([base_url, url]) parts = [x for x in parse.urlparse(_url)] parts[2] = re.sub("/{2,}", "/", parts[2]) _url = parse.urlunparse(parts) # no change to method or body return str(_url), _headers, body def _get_auth(self): return None def is_expired(self): return False def _fill_credentials(self): pass designate-2.0.0/functionaltests/common/client.py0000664000567000056710000001761512701406241023171 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ import abc import logging from config import cfg from noauth import NoAuthAuthProvider from six import string_types from six.moves.urllib.parse import quote_plus from tempest_lib.common.rest_client import RestClient from tempest_lib.auth import KeystoneV2Credentials from tempest_lib.auth import KeystoneV2AuthProvider from functionaltests.common.utils import memoized from functionaltests.common import hooks LOG = logging.getLogger(__name__) class KeystoneV2AuthProviderWithOverridableUrl(KeystoneV2AuthProvider): def base_url(self, *args, **kwargs): # use the base url from the config if it was specified if cfg.CONF.identity.designate_override_url: return cfg.CONF.identity.designate_override_url else: return super(KeystoneV2AuthProviderWithOverridableUrl, self) \ .base_url(*args, **kwargs) class KeystoneV2AuthProviderNoToken(KeystoneV2AuthProviderWithOverridableUrl): def _decorate_request(self, filters, method, url, headers=None, body=None, auth_data=None): _res = super(KeystoneV2AuthProviderNoToken, self)._decorate_request( filters, method, url, headers=headers, body=body, auth_data=auth_data) _url, _headers, _body = _res del _headers['X-Auth-Token'] return (_url, _headers, _body) class BaseDesignateClient(RestClient): def __init__(self, with_token=True): no_cert_check = cfg.CONF.testconfig.disable_ssl_certificate_validation interface = cfg.CONF.designate.interface if not interface.endswith('URL'): interface += "URL" self.hooks = [] self._populate_hooks() super(BaseDesignateClient, self).__init__( auth_provider=self.get_auth_provider(with_token), service=cfg.CONF.designate.service, region=cfg.CONF.identity.region, disable_ssl_certificate_validation=no_cert_check, endpoint_type=interface ) def _populate_hooks(self): for name in cfg.CONF.testconfig.hooks: LOG.debug("Loading request hook '%s' from config", name) try: cls = hooks.get_class(name) if not cls: LOG.debug("'%s' not found. Call register_hook", name) else: self.hooks.append(cls) except Exception as e: LOG.exception(e) def request(self, *args, **kwargs): req_hooks = [hook_class() for hook_class in self.hooks] try: for hook in req_hooks: hook.before(args, kwargs) r, b = super(BaseDesignateClient, self).request(*args, **kwargs) for hook in req_hooks: hook.after(r, b) return r, b except Exception as e: for hook in req_hooks: hook.on_exception(e) raise def get_auth_provider(self, with_token=True): if cfg.CONF.noauth.use_noauth: return self._get_noauth_auth_provider() return self._get_keystone_auth_provider(with_token) @abc.abstractmethod def _get_noauth_auth_provider(self): pass @abc.abstractmethod def _get_keystone_auth_provider(self): pass def _create_keystone_auth_provider(self, creds, with_token=True): if with_token: auth_provider = KeystoneV2AuthProviderWithOverridableUrl( creds, cfg.CONF.identity.uri) else: auth_provider = KeystoneV2AuthProviderNoToken( creds, cfg.CONF.identity.uri) auth_provider.fill_credentials() return auth_provider class DesignateClient(BaseDesignateClient): """Client with default user""" def _get_noauth_auth_provider(self): creds = KeystoneV2Credentials( tenant_id=cfg.CONF.noauth.tenant_id, ) return NoAuthAuthProvider(creds, cfg.CONF.noauth.designate_endpoint) def _get_keystone_auth_provider(self, with_token=True): creds = KeystoneV2Credentials( username=cfg.CONF.identity.username, password=cfg.CONF.identity.password, tenant_name=cfg.CONF.identity.tenant_name, ) return self._create_keystone_auth_provider(creds, with_token) class DesignateAltClient(BaseDesignateClient): """Client with alternate user""" def _get_noauth_auth_provider(self): creds = KeystoneV2Credentials( tenant_id=cfg.CONF.noauth.alt_tenant_id, ) return NoAuthAuthProvider(creds, cfg.CONF.noauth.designate_endpoint) def _get_keystone_auth_provider(self, with_token=True): creds = KeystoneV2Credentials( username=cfg.CONF.identity.alt_username, password=cfg.CONF.identity.alt_password, tenant_name=cfg.CONF.identity.alt_tenant_name, ) return self._create_keystone_auth_provider(creds, with_token) class DesignateAdminClient(BaseDesignateClient): """Client with admin user""" def _get_noauth_auth_provider(self): creds = KeystoneV2Credentials( tenant_id=cfg.CONF.noauth.tenant_id, ) return NoAuthAuthProvider(creds, cfg.CONF.noauth.designate_endpoint) def _get_keystone_auth_provider(self, with_token=True): creds = KeystoneV2Credentials( username=cfg.CONF.auth.admin_username, password=cfg.CONF.auth.admin_password, tenant_name=cfg.CONF.auth.admin_tenant_name, ) return self._create_keystone_auth_provider(creds, with_token) class ClientMixin(object): @classmethod @memoized def get_clients(cls, with_token): return { 'default': DesignateClient(with_token), 'alt': DesignateAltClient(with_token), 'admin': DesignateAdminClient(with_token), } def __init__(self, client): self.client = client @classmethod def deserialize(cls, resp, body, model_type): return resp, model_type.from_json(body) @classmethod def as_user(cls, user, with_token=True): """ :param user: 'default', 'alt', or 'admin' :param with_token: Boolean for whether to send the x-auth-token with requests """ return cls(cls.get_clients(with_token)[user]) @property def tenant_id(self): return self.client.tenant_id @classmethod def add_filters(cls, url, filters): """ :param url: base URL for the request :param filters: dict with var:val pairs to add as parameters to URL """ first = True for f in filters: if isinstance(filters[f], string_types): filters[f] = quote_plus(filters[f].encode('utf-8')) url = '{url}{sep}{var}={val}'.format( url=url, sep=('?' if first else '&'), var=f, val=filters[f] ) first = False return url def create_uri(self, path, filters=None): url_pattern = cfg.CONF.testconfig.v2_path_pattern params = { 'path': path, 'tenant_id': self.client.tenant_id, 'tenant_name': self.client.tenant_name, 'user': self.client.user, 'user_id': self.client.user_id, } uri = url_pattern.format(**params) uri.replace('//', '/') if filters: uri = self.add_filters(uri, filters) return uri designate-2.0.0/functionaltests/api/0000775000567000056710000000000012701406373020616 5ustar jenkinsjenkins00000000000000designate-2.0.0/functionaltests/api/__init__.py0000664000567000056710000000000012701406241022707 0ustar jenkinsjenkins00000000000000designate-2.0.0/functionaltests/api/v2/0000775000567000056710000000000012701406373021145 5ustar jenkinsjenkins00000000000000designate-2.0.0/functionaltests/api/v2/test_blacklist_unauthed.py0000664000567000056710000000467312701406241026427 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from tempest_lib import exceptions from functionaltests.common import datagen from functionaltests.api.v2.base import DesignateV2Test from functionaltests.api.v2.clients.blacklist_client import BlacklistClient from functionaltests.api.v2.fixtures import BlacklistFixture class BlacklistTest(DesignateV2Test): def setUp(self): super(BlacklistTest, self).setUp() self.increase_quotas(user='admin') self.client = BlacklistClient.as_user('admin', with_token=False) self.fixture = self.useFixture(BlacklistFixture(user='admin')) def test_create_blacklist(self): self.assertRaises( exceptions.Unauthorized, self.client.post_blacklist, datagen.random_blacklist_data()) def test_get_fake_blacklist(self): self.assertRaises( exceptions.Unauthorized, self.client.get_blacklist, 'junk') def test_get_existing_blacklist(self): self.assertRaises( exceptions.Unauthorized, self.client.get_blacklist, self.fixture.created_blacklist.id) def test_list_blacklists(self): self.assertRaises( exceptions.Unauthorized, self.client.list_blacklists) def test_update_fake_blacklist(self): self.assertRaises( exceptions.Unauthorized, self.client.patch_blacklist, 'junk', datagen.random_blacklist_data()) def test_update_existing_blacklist(self): self.assertRaises( exceptions.Unauthorized, self.client.patch_blacklist, self.fixture.created_blacklist.id, datagen.random_blacklist_data()) def test_delete_fake_blacklist(self): self.assertRaises( exceptions.Unauthorized, self.client.delete_blacklist, 'junk') def test_delete_existing_blacklist(self): self.assertRaises( exceptions.Unauthorized, self.client.delete_blacklist, self.fixture.created_blacklist.id) designate-2.0.0/functionaltests/api/v2/test_blacklist.py0000664000567000056710000000714112701406241024523 0ustar jenkinsjenkins00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import uuid from tempest_lib import exceptions from functionaltests.common import datagen from functionaltests.api.v2.base import DesignateV2Test from functionaltests.api.v2.clients.blacklist_client import BlacklistClient from functionaltests.api.v2.fixtures import BlacklistFixture class BlacklistTest(DesignateV2Test): def test_list_blacklists(self): self.useFixture(BlacklistFixture()) resp, model = BlacklistClient.as_user('admin').list_blacklists() self.assertEqual(200, resp.status) self.assertGreater(len(model.blacklists), 0) def test_create_blacklist(self): fixture = self.useFixture(BlacklistFixture()) self.assertEqual(fixture.post_model.pattern, fixture.created_blacklist.pattern) def test_update_blacklist(self): old_model = self.useFixture(BlacklistFixture()).created_blacklist patch_model = datagen.random_blacklist_data() resp, new_model = BlacklistClient.as_user('admin').patch_blacklist( old_model.id, patch_model) self.assertEqual(200, resp.status) resp, model = BlacklistClient.as_user('admin').get_blacklist( new_model.id) self.assertEqual(200, resp.status) self.assertEqual(old_model.id, new_model.id) self.assertEqual(model.pattern, new_model.pattern) def test_delete_blacklist(self): fixture = self.useFixture(BlacklistFixture()) resp, model = BlacklistClient.as_user('admin').delete_blacklist( fixture.created_blacklist.id) self.assertEqual(204, resp.status) def test_get_blacklist_404(self): client = BlacklistClient.as_user('admin') self._assert_exception( exceptions.NotFound, 'blacklist_not_found', 404, client.get_blacklist, str(uuid.uuid4())) def test_update_blacklist_404(self): model = datagen.random_blacklist_data() client = BlacklistClient.as_user('admin') self._assert_exception( exceptions.NotFound, 'blacklist_not_found', 404, client.patch_blacklist, str(uuid.uuid4()), model) def test_delete_blacklist_404(self): client = BlacklistClient.as_user('admin') self._assert_exception( exceptions.NotFound, 'blacklist_not_found', 404, client.delete_blacklist, str(uuid.uuid4())) def test_get_blacklist_invalid_uuid(self): client = BlacklistClient.as_user('admin') self._assert_invalid_uuid(client.get_blacklist, 'fooo') def test_update_blacklist_invalid_uuid(self): model = datagen.random_blacklist_data() client = BlacklistClient.as_user('admin') self._assert_invalid_uuid(client.patch_blacklist, 'fooo', model) def test_delete_blacklist_invalid_uuid(self): client = BlacklistClient.as_user('admin') self._assert_invalid_uuid(client.get_blacklist, 'fooo') designate-2.0.0/functionaltests/api/v2/test_recordset_validation.py0000664000567000056710000001324612701406241026762 0ustar jenkinsjenkins00000000000000""" Copyright 2016 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from tempest_lib import exceptions from functionaltests.common import datagen from functionaltests.common import utils from functionaltests.api.v2.base import DesignateV2Test from functionaltests.api.v2.clients.recordset_client import RecordsetClient from functionaltests.api.v2.fixtures import ZoneFixture from functionaltests.api.v2.fixtures import RecordsetFixture from functionaltests.api.v2.test_recordset import RECORDSETS_DATASET INVALID_TXT_DATASET = { 'trailing_slash': dict(data='\\'), 'trailing_double_slash': dict(data='\\\\'), 'trailing_slash_after_text': dict(data='v=spf1 +all\\'), } VALID_TXT_DATASET = { 'slash_with_one_trailing_space': dict(data='\\ '), 'slash_with_many_trailing_space': dict(data='\\ '), 'text_with_slash_and_trailing_space': dict(data='the txts \ '), } INVALID_MX_DATASET = { 'empty_preference': dict(pref=''), 'minus_zero_preference': dict(pref='-0'), 'minus_one_preference': dict(pref='-1'), } INVALID_SSHFP_DATASET = { 'minus_zero_algorithm': dict(algo='-0', finger=None), 'minus_zero_fingerprint': dict(algo=None, finger='-0'), 'minus_one_algorithm': dict(algo='-1', finger=None), 'minus_one_fingerprint': dict(algo=None, finger='-1'), } @utils.parameterized_class class RecordsetValidationTest(DesignateV2Test): def setUp(self): super(RecordsetValidationTest, self).setUp() self.increase_quotas(user='default') self.ensure_tld_exists('com') self.zone = self.useFixture(ZoneFixture()).created_zone self.client = RecordsetClient.as_user('default') @utils.parameterized(RECORDSETS_DATASET) def test_create_invalid(self, make_recordset, data=None): data = data or ["b0rk"] for i in data: model = make_recordset(self.zone) model.data = i self._assert_exception( exceptions.BadRequest, 'invalid_object', 400, self.client.post_recordset, self.zone.id, model) @utils.parameterized(RECORDSETS_DATASET) def test_update_invalid(self, make_recordset, data=None): data = data or ["b0rk"] post_model = make_recordset(self.zone) fixture = self.useFixture(RecordsetFixture(self.zone.id, post_model)) recordset_id = fixture.created_recordset.id for i in data: model = make_recordset(self.zone) model.data = i self._assert_exception( exceptions.BadRequest, 'invalid_object', 400, self.client.put_recordset, self.zone.id, recordset_id, model) def test_cannot_create_wildcard_NS_recordset(self): model = datagen.wildcard_ns_recordset(self.zone.name) self._assert_exception( exceptions.BadRequest, 'invalid_object', 400, self.client.post_recordset, self.zone.id, model) def test_cname_recordsets_cannot_have_more_than_one_record(self): post_model = datagen.random_cname_recordset(zone_name=self.zone.name) post_model.records = [ "a.{0}".format(self.zone.name), "b.{0}".format(self.zone.name), ] self.assertRaises(exceptions.BadRequest, self.client.post_recordset, self.zone.id, post_model) @utils.parameterized(INVALID_TXT_DATASET) def test_cannot_create_TXT_with(self, data): post_model = datagen.random_txt_recordset(self.zone.name, data) e = self._assert_exception( exceptions.BadRequest, 'invalid_object', 400, self.client.post_recordset, self.zone.id, post_model, ) self.assertEqual( "u'%s' is not a 'txt-data'" % data.replace('\\', '\\\\'), e.resp_body['errors']['errors'][0]['message'], ) @utils.parameterized(VALID_TXT_DATASET) def test_create_TXT_with(self, data): post_model = datagen.random_txt_recordset(self.zone.name, data) fixture = self.useFixture(RecordsetFixture(self.zone.id, post_model)) recordset = fixture.created_recordset self.client.wait_for_recordset(self.zone.id, recordset.id) @utils.parameterized(VALID_TXT_DATASET) def test_create_SPF_with(self, data): post_model = datagen.random_spf_recordset(self.zone.name, data) fixture = self.useFixture(RecordsetFixture(self.zone.id, post_model)) recordset = fixture.created_recordset self.client.wait_for_recordset(self.zone.id, recordset.id) @utils.parameterized(INVALID_MX_DATASET) def test_cannot_create_MX_with(self, pref): post_model = datagen.random_mx_recordset(self.zone.name, pref=pref) self._assert_exception( exceptions.BadRequest, 'invalid_object', 400, self.client.post_recordset, self.zone.id, post_model, ) @utils.parameterized(INVALID_SSHFP_DATASET) def test_cannot_create_SSHFP_with(self, algo, finger): post_model = datagen.random_sshfp_recordset( zone_name=self.zone.name, algorithm_number=algo, fingerprint_type=finger, ) self._assert_exception( exceptions.BadRequest, 'invalid_object', 400, self.client.post_recordset, self.zone.id, post_model, ) designate-2.0.0/functionaltests/api/v2/test_tld.py0000664000567000056710000000714512701406241023342 0ustar jenkinsjenkins00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import uuid from tempest_lib import exceptions from functionaltests.common import datagen from functionaltests.api.v2.base import DesignateV2Test from functionaltests.api.v2.clients.tld_client import TLDClient from functionaltests.api.v2.fixtures import TLDFixture class TLDTest(DesignateV2Test): def setUp(self): super(TLDTest, self).setUp() self.ensure_tld_exists('com') self.client = TLDClient.as_user('admin') self.fixture = self.useFixture(TLDFixture()) def test_list_tlds(self): resp, model = self.client.list_tlds() self.assertEqual(resp.status, 200) self.assertGreater(len(model.tlds), 0) def test_create_tld(self): self.assertEqual(self.fixture.post_resp.status, 201) resp, tld = self.client.get_tld(self.fixture.created_tld.id) self.assertEqual(resp.status, 200) self.assertEqual(tld.name, self.fixture.created_tld.name) self.assertEqual(tld.id, self.fixture.created_tld.id) self.assertEqual(tld.created_at, self.fixture.created_tld.created_at) self.assertEqual(tld.updated_at, self.fixture.created_tld.updated_at) self.assertEqual(tld.description, self.fixture.created_tld.description) def test_update_tld(self): old_model = self.fixture.created_tld patch_model = datagen.random_tld_data() resp, new_model = self.client.patch_tld(old_model.id, patch_model) self.assertEqual(resp.status, 200) self.assertEqual(new_model.id, old_model.id) self.assertEqual(new_model.name, patch_model.name) resp, new_model = self.client.get_tld(new_model.id) self.assertEqual(resp.status, 200) self.assertEqual(new_model.id, old_model.id) self.assertEqual(new_model.name, patch_model.name) def test_delete_tld(self): resp, model = self.client.delete_tld(self.fixture.created_tld.id) self.assertEqual(resp.status, 204) self.assertRaises(exceptions.NotFound, self.client.get_tld, self.fixture.created_tld.id) def test_get_tld_404(self): self._assert_exception( exceptions.NotFound, 'tld_not_found', 404, self.client.get_tld, str(uuid.uuid4())) def test_update_tld_404(self): model = datagen.random_tld_data() self._assert_exception( exceptions.NotFound, 'tld_not_found', 404, self.client.patch_tld, str(uuid.uuid4()), model) def test_delete_tld_404(self): self._assert_exception( exceptions.NotFound, 'tld_not_found', 404, self.client.delete_tld, str(uuid.uuid4())) def test_get_tld_invalid_uuid(self): self._assert_invalid_uuid(self.client.get_tld, 'fooo') def test_update_tld_invalid_uuid(self): model = datagen.random_tld_data() self._assert_invalid_uuid(self.client.patch_tld, 'fooo', model) def test_delete_tld_invalid_uuid(self): self._assert_invalid_uuid(self.client.get_tld, 'fooo') designate-2.0.0/functionaltests/api/v2/__init__.py0000664000567000056710000000000012701406241023236 0ustar jenkinsjenkins00000000000000designate-2.0.0/functionaltests/api/v2/models/0000775000567000056710000000000012701406373022430 5ustar jenkinsjenkins00000000000000designate-2.0.0/functionaltests/api/v2/models/recordset_model.py0000664000567000056710000000171712701406241026154 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from functionaltests.common.models import BaseModel from functionaltests.common.models import CollectionModel from functionaltests.common.models import EntityModel class RecordsetData(BaseModel): pass class RecordsetModel(EntityModel): ENTITY_NAME = 'recordset' MODEL_TYPE = RecordsetData class RecordsetListModel(CollectionModel): COLLECTION_NAME = 'recordsets' MODEL_TYPE = RecordsetData designate-2.0.0/functionaltests/api/v2/models/transfer_requests_model.py0000664000567000056710000000214112701406241027731 0ustar jenkinsjenkins00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from functionaltests.common.models import BaseModel from functionaltests.common.models import CollectionModel from functionaltests.common.models import EntityModel class TransferRequestsData(BaseModel): pass class TransferRequestsModel(EntityModel): ENTITY_NAME = 'transfer_request' MODEL_TYPE = TransferRequestsData class TransferRequestsListModel(CollectionModel): COLLECTION_NAME = 'transfer_requests' MODEL_TYPE = TransferRequestsData designate-2.0.0/functionaltests/api/v2/models/zone_import_model.py0000664000567000056710000000147112701406241026524 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from functionaltests.common.models import BaseModel from functionaltests.common.models import CollectionModel class ZoneImportModel(BaseModel): pass class ZoneImportListModel(CollectionModel): COLLECTION_NAME = 'imports' MODEL_TYPE = ZoneImportModel designate-2.0.0/functionaltests/api/v2/models/__init__.py0000664000567000056710000000000012701406241024521 0ustar jenkinsjenkins00000000000000designate-2.0.0/functionaltests/api/v2/models/zone_export_model.py0000664000567000056710000000147112701406241026533 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from functionaltests.common.models import BaseModel from functionaltests.common.models import CollectionModel class ZoneExportModel(BaseModel): pass class ZoneExportListModel(CollectionModel): COLLECTION_NAME = 'exports' MODEL_TYPE = ZoneExportModel designate-2.0.0/functionaltests/api/v2/models/blacklist_model.py0000664000567000056710000000206012701406241026122 0ustar jenkinsjenkins00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from functionaltests.common.models import BaseModel from functionaltests.common.models import CollectionModel from functionaltests.common.models import EntityModel class BlacklistData(BaseModel): pass class BlacklistModel(EntityModel): ENTITY_NAME = 'blacklist' MODEL_TYPE = BlacklistData class BlacklistListModel(CollectionModel): COLLECTION_NAME = 'blacklists' MODEL_TYPE = BlacklistData designate-2.0.0/functionaltests/api/v2/models/transfer_accepts_model.py0000664000567000056710000000213212701406241027500 0ustar jenkinsjenkins00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from functionaltests.common.models import BaseModel from functionaltests.common.models import CollectionModel from functionaltests.common.models import EntityModel class TransferAcceptsData(BaseModel): pass class TransferAcceptsModel(EntityModel): ENTITY_NAME = 'transfer_accept' MODEL_TYPE = TransferAcceptsData class TransferAcceptsListModel(CollectionModel): COLLECTION_NAME = 'transfer_accepts' MODEL_TYPE = TransferAcceptsData designate-2.0.0/functionaltests/api/v2/models/pool_model.py0000664000567000056710000000201512701406241025123 0ustar jenkinsjenkins00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from functionaltests.common.models import BaseModel from functionaltests.common.models import CollectionModel from functionaltests.common.models import EntityModel class PoolData(BaseModel): pass class PoolModel(EntityModel): ENTITY_NAME = 'pool' MODEL_TYPE = PoolData class PoolListModel(CollectionModel): COLLECTION_NAME = 'pools' MODEL_TYPE = PoolData designate-2.0.0/functionaltests/api/v2/models/tld_model.py0000664000567000056710000000200612701406241024735 0ustar jenkinsjenkins00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from functionaltests.common.models import BaseModel from functionaltests.common.models import CollectionModel from functionaltests.common.models import EntityModel class TLDData(BaseModel): pass class TLDModel(EntityModel): ENTITY_NAME = 'tld' MODEL_TYPE = TLDData class TLDListModel(CollectionModel): COLLECTION_NAME = 'tlds' MODEL_TYPE = TLDData designate-2.0.0/functionaltests/api/v2/models/quotas_model.py0000664000567000056710000000143112701406241025467 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from functionaltests.common.models import BaseModel from functionaltests.common.models import EntityModel class QuotasData(BaseModel): pass class QuotasModel(EntityModel): ENTITY_NAME = 'quota' MODEL_TYPE = QuotasData designate-2.0.0/functionaltests/api/v2/models/zone_model.py0000664000567000056710000000144512701406241025133 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from functionaltests.common.models import BaseModel from functionaltests.common.models import CollectionModel class ZoneModel(BaseModel): pass class ZoneListModel(CollectionModel): COLLECTION_NAME = 'zones' MODEL_TYPE = ZoneModel designate-2.0.0/functionaltests/api/v2/test_zone_unauthed.py0000664000567000056710000000446012701406241025424 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from tempest_lib import exceptions from functionaltests.common import datagen from functionaltests.api.v2.base import DesignateV2Test from functionaltests.api.v2.clients.zone_client import ZoneClient from functionaltests.api.v2.fixtures import ZoneFixture class ZoneTest(DesignateV2Test): def setUp(self): super(ZoneTest, self).setUp() self.increase_quotas(user='default') self.client = ZoneClient.as_user('default', with_token=False) self.fixture = self.useFixture(ZoneFixture(user='default')) def test_create_zone(self): self.assertRaises( exceptions.Unauthorized, self.client.post_zone, datagen.random_zone_data()) def test_get_fake_zone(self): self.assertRaises( exceptions.Unauthorized, self.client.get_zone, 'junk') def test_get_existing_zone(self): self.assertRaises( exceptions.Unauthorized, self.client.get_zone, self.fixture.created_zone.id) def test_list_zones(self): self.assertRaises( exceptions.Unauthorized, self.client.list_zones) def test_update_fake_zone(self): self.assertRaises( exceptions.Unauthorized, self.client.patch_zone, 'junk', datagen.random_zone_data()) def test_update_existing_zone(self): self.assertRaises( exceptions.Unauthorized, self.client.patch_zone, self.fixture.created_zone.id, datagen.random_zone_data()) def test_delete_fake_zone(self): self.assertRaises( exceptions.Unauthorized, self.client.delete_zone, 'junk') def test_delete_existing_zone(self): self.assertRaises( exceptions.Unauthorized, self.client.delete_zone, self.fixture.created_zone.id) designate-2.0.0/functionaltests/api/v2/test_recordset.py0000664000567000056710000002054712701406241024552 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ import dns.rdatatype from tempest_lib import exceptions from functionaltests.common import datagen from functionaltests.common import dnsclient from functionaltests.common import utils from functionaltests.api.v2.base import DesignateV2Test from functionaltests.api.v2.clients.recordset_client import RecordsetClient from functionaltests.api.v2.fixtures import ZoneFixture from functionaltests.api.v2.fixtures import RecordsetFixture RECORDSETS_DATASET = { 'A': dict( make_recordset=lambda z: datagen.random_a_recordset(z.name)), 'AAAA': dict( make_recordset=lambda z: datagen.random_aaaa_recordset(z.name)), 'CNAME': dict( make_recordset=lambda z: datagen.random_cname_recordset(z.name)), 'MX': dict( make_recordset=lambda z: datagen.random_mx_recordset(z.name)), 'SPF': dict( make_recordset=lambda z: datagen.random_spf_recordset(z.name)), 'SRV': dict( make_recordset=lambda z: datagen.random_srv_recordset(z.name)), 'SSHFP': dict( make_recordset=lambda z: datagen.random_sshfp_recordset(z.name)), 'TXT': dict( make_recordset=lambda z: datagen.random_txt_recordset(z.name)), } WILDCARD_RECORDSETS_DATASET = { 'A': dict(make_recordset=lambda z: datagen.random_a_recordset(zone_name=z.name, name="*.{0}".format(z.name))), 'AAAA': dict(make_recordset=lambda z: datagen.random_aaaa_recordset(zone_name=z.name, name="*.{0}".format(z.name))), 'CNAME': dict(make_recordset=lambda z: datagen.random_cname_recordset(zone_name=z.name, name="*.{0}".format(z.name))), 'MX': dict(make_recordset=lambda z: datagen.random_mx_recordset(zone_name=z.name, name="*.{0}".format(z.name))), 'SPF': dict(make_recordset=lambda z: datagen.random_spf_recordset(zone_name=z.name, name="*.{0}".format(z.name))), 'SSHFP': dict(make_recordset=lambda z: datagen.random_sshfp_recordset(zone_name=z.name, name="*.{0}".format(z.name))), 'TXT': dict(make_recordset=lambda z: datagen.random_txt_recordset(zone_name=z.name, name="*.{0}".format(z.name))), } @utils.parameterized_class class RecordsetTest(DesignateV2Test): def setUp(self): super(RecordsetTest, self).setUp() self.increase_quotas(user='default') self.ensure_tld_exists('com') self.zone = self.useFixture(ZoneFixture()).created_zone def test_list_recordsets(self): post_model = datagen.random_a_recordset(self.zone.name) self.useFixture(RecordsetFixture(self.zone.id, post_model)) resp, model = RecordsetClient.as_user('default') \ .list_recordsets(self.zone.id) self.assertEqual(200, resp.status) self.assertGreater(len(model.recordsets), 0) def assert_dns(self, model): results = dnsclient.query_servers(model.name, model.type) model_data = model.to_dict() if model.type == 'AAAA': model_data['records'] = utils.shorten_ipv6_addrs( model_data['records']) for answer in results: data = { "type": dns.rdatatype.to_text(answer.rdtype), "name": str(answer.canonical_name), # DNSPython wraps TXT values in "" so '+all v=foo' becomes # '"+all" "+v=foo"' "records": [i.to_text().replace('"', '') for i in answer.rrset.items] } if answer.rrset.ttl != 0: data['ttl'] = answer.rrset.ttl self.assertEqual(model_data, data) @utils.parameterized(RECORDSETS_DATASET) def test_crud_recordset(self, make_recordset): post_model = make_recordset(self.zone) fixture = self.useFixture(RecordsetFixture(self.zone.id, post_model)) recordset_id = fixture.created_recordset.id self.assert_dns(fixture.post_model) put_model = make_recordset(self.zone) del put_model.name # don't try to update the name resp, put_resp_model = RecordsetClient.as_user('default') \ .put_recordset(self.zone.id, recordset_id, put_model) self.assertEqual(202, resp.status, "on put response") self.assertEqual("PENDING", put_resp_model.status) self.assertEqual(post_model.name, put_resp_model.name) self.assertEqual(put_model.records, put_resp_model.records) self.assertEqual(put_model.ttl, put_resp_model.ttl) RecordsetClient.as_user('default').wait_for_recordset( self.zone.id, recordset_id) put_model.name = post_model.name self.assert_dns(put_model) resp, delete_resp_model = RecordsetClient.as_user('default') \ .delete_recordset(self.zone.id, recordset_id) self.assertEqual(202, resp.status, "on delete response") RecordsetClient.as_user('default').wait_for_404( self.zone.id, recordset_id) @utils.parameterized(WILDCARD_RECORDSETS_DATASET) def test_can_create_and_query_wildcard_recordset(self, make_recordset): post_model = make_recordset(self.zone) self.useFixture(RecordsetFixture(self.zone.id, post_model)) verify_models = [ post_model.from_dict(post_model.to_dict()) for x in range(3) ] verify_models[0].name = "abc.{0}".format(self.zone.name) verify_models[1].name = "abc.def.{0}".format(self.zone.name) verify_models[2].name = "abc.def.hij.{0}".format(self.zone.name) for m in verify_models: self.assert_dns(m) class RecordsetOwnershipTest(DesignateV2Test): def setUp(self): super(RecordsetOwnershipTest, self).setUp() self.increase_quotas(user='default') self.increase_quotas(user='alt') self.ensure_tld_exists('com') def test_no_create_recordset_by_alt_tenant(self): zone = self.useFixture(ZoneFixture(user='default')).created_zone # try with name=A123456.zone.com. recordset = datagen.random_a_recordset(zone_name=zone.name) self.assertRaises(exceptions.RestClientException, lambda: RecordsetClient.as_user('alt') .post_recordset(zone.id, recordset)) # try with name=zone.com. recordset.name = zone.name self.assertRaises(exceptions.RestClientException, lambda: RecordsetClient.as_user('alt') .post_recordset(zone.id, recordset)) def test_no_create_super_recordsets(self): # default creates zone a.b.c.example.com. # alt fails to create record with name b.c.example.com zone_data = datagen.random_zone_data() recordset = datagen.random_a_recordset(zone_name=zone_data.name) recordset.name = 'b.c.' + zone_data.name zone_data.name = 'a.b.c.' + zone_data.name fixture = self.useFixture(ZoneFixture(zone_data, user='default')) self.assertRaises(exceptions.RestClientException, lambda: RecordsetClient.as_user('alt') .post_recordset(fixture.created_zone.id, recordset)) def test_no_create_recordset_via_alt_domain(self): zone = self.useFixture(ZoneFixture(user='default')).created_zone alt_zone = self.useFixture(ZoneFixture(user='alt')).created_zone # alt attempts to create record with name A12345.{zone} recordset = datagen.random_a_recordset(zone_name=zone.name) self.assertRaises(exceptions.RestClientException, lambda: RecordsetClient.as_user('alt') .post_recordset(zone.id, recordset)) self.assertRaises(exceptions.RestClientException, lambda: RecordsetClient.as_user('alt') .post_recordset(alt_zone.id, recordset)) designate-2.0.0/functionaltests/api/v2/clients/0000775000567000056710000000000012701406373022606 5ustar jenkinsjenkins00000000000000designate-2.0.0/functionaltests/api/v2/clients/transfer_accepts_client.py0000664000567000056710000000502612701406241030041 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from functionaltests.api.v2.models.transfer_accepts_model import \ TransferAcceptsModel from functionaltests.api.v2.models.transfer_accepts_model import \ TransferAcceptsListModel from functionaltests.common.client import ClientMixin class TransferAcceptClient(ClientMixin): def transfer_accepts_uri(self, filters=None): return self.create_uri("/zones/tasks/transfer_accepts", filters=filters) def transfer_accept_uri(self, transfer_request_id): return "{0}/{1}".format(self.transfer_accepts_uri(), transfer_request_id) def list_transfer_accepts(self, zone_id, filters=None, **kwargs): resp, body = self.client.get( self.transfer_accepts_uri(filters), **kwargs) return self.deserialize(resp, body, TransferAcceptsListModel) def get_transfer_accept(self, zone_id, transfer_request_id, **kwargs): resp, body = self.client.get(self.transfer_accept_uri( transfer_request_id), **kwargs) return self.deserialize(resp, body, TransferAcceptsModel) def post_transfer_accept(self, transfer_request_model, **kwargs): resp, body = self.client.post( self.transfer_accepts_uri(), body=transfer_request_model.to_json(), **kwargs) return self.deserialize(resp, body, TransferAcceptsModel) def put_transfer_accept(self, zone_id, transfer_request_id, transfer_request_model, **kwargs): resp, body = self.client.put(self.transfer_accept_uri( transfer_request_id), body=transfer_request_model.to_json(), **kwargs) return self.deserialize(resp, body, TransferAcceptsModel) def delete_transfer_accept(self, zone_id, transfer_request_id, **kwargs): resp, body = self.client.delete( self.transfer_accept_uri(zone_id, transfer_request_id), **kwargs) return self.deserialize(resp, body, TransferAcceptsModel) designate-2.0.0/functionaltests/api/v2/clients/quotas_client.py0000664000567000056710000000301312701406241026021 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from functionaltests.api.v2.models.quotas_model import QuotasModel from functionaltests.common.client import ClientMixin class QuotasClient(ClientMixin): def quotas_uri(self, tenant_id, filters=None): url = "/admin/quotas/{0}".format(tenant_id) if filters: url = self.add_filters(url, filters) return url def get_quotas(self, tenant_id, filters=None, **kwargs): resp, body = self.client.get( self.quotas_uri(tenant_id, filters), **kwargs) return self.deserialize(resp, body, QuotasModel) def patch_quotas(self, tenant_id, quotas_model, **kwargs): resp, body = self.client.patch(self.quotas_uri(tenant_id), body=quotas_model.to_json(), **kwargs) return self.deserialize(resp, body, QuotasModel) def delete_quotas(self, tenant_id, **kwargs): resp, body = self.client.patch(self.quotas_uri(tenant_id), **kwargs) return self.deserialize(resp, body, QuotasModel) designate-2.0.0/functionaltests/api/v2/clients/__init__.py0000664000567000056710000000000012701406241024677 0ustar jenkinsjenkins00000000000000designate-2.0.0/functionaltests/api/v2/clients/zone_export_client.py0000664000567000056710000000553412701406241027073 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from functionaltests.api.v2.models.zone_export_model import ZoneExportModel from functionaltests.api.v2.models.zone_export_model import ZoneExportListModel from functionaltests.common import utils from functionaltests.common.client import ClientMixin from functionaltests.common.models import ZoneFile class ZoneExportClient(ClientMixin): def zone_exports_uri(self, filters=None): return self.create_uri("/zones/tasks/exports", filters=filters) def create_zone_export_uri(self, zone_id, filters=None): return self.create_uri( "/zones/{0}/tasks/export".format(zone_id), filters=filters, ) def zone_export_uri(self, id): return "{0}/{1}".format(self.zone_exports_uri(), id) def list_zone_exports(self, filters=None, **kwargs): resp, body = self.client.get( self.zone_exports_uri(filters), **kwargs) return self.deserialize(resp, body, ZoneExportListModel) def get_zone_export(self, id, **kwargs): resp, body = self.client.get(self.zone_export_uri(id)) return self.deserialize(resp, body, ZoneExportModel) def get_exported_zone(self, id, **kwargs): uri = "{0}/export".format(self.zone_export_uri(id)) headers = {'Accept': 'text/dns'} resp, body = self.client.get(uri, headers=headers) if resp.status < 400: return resp, ZoneFile.from_text(body) return resp, body def post_zone_export(self, zone_id, **kwargs): uri = self.create_zone_export_uri(zone_id) resp, body = self.client.post(uri, body='', **kwargs) return self.deserialize(resp, body, ZoneExportModel) def delete_zone_export(self, id, **kwargs): resp, body = self.client.delete(self.zone_export_uri(id), **kwargs) return resp, body def wait_for_zone_export(self, zone_export_id): utils.wait_for_condition( lambda: self.is_zone_export_active(zone_export_id)) def is_zone_export_active(self, zone_export_id): resp, model = self.get_zone_export(zone_export_id) # don't have assertEqual but still want to fail fast assert resp.status == 200 if model.status == 'COMPLETE': return True elif model.status == 'ERROR': raise Exception("Saw ERROR status") return False designate-2.0.0/functionaltests/api/v2/clients/pool_client.py0000664000567000056710000000367412701406241025473 0ustar jenkinsjenkins00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from functionaltests.api.v2.models.pool_model import PoolModel from functionaltests.api.v2.models.pool_model import PoolListModel from functionaltests.common.client import ClientMixin class PoolClient(ClientMixin): def pools_uri(self, filters=None): return self.create_uri("/pools", filters=filters) def pool_uri(self, pool_id): return "{0}/{1}".format(self.pools_uri(), pool_id) def list_pools(self, filters=None, **kwargs): resp, body = self.client.get(self.pools_uri(filters), **kwargs) return self.deserialize(resp, body, PoolListModel) def get_pool(self, pool_id, **kwargs): resp, body = self.client.get(self.pool_uri(pool_id)) return self.deserialize(resp, body, PoolModel) def post_pool(self, pool_model, **kwargs): resp, body = self.client.post( self.pools_uri(), body=pool_model.to_json(), **kwargs) return self.deserialize(resp, body, PoolModel) def patch_pool(self, pool_id, pool_model, **kwargs): resp, body = self.client.patch( self.pool_uri(pool_id), body=pool_model.to_json(), **kwargs) return self.deserialize(resp, body, PoolModel) def delete_pool(self, pool_id, **kwargs): return self.client.delete(self.pool_uri(pool_id), **kwargs) designate-2.0.0/functionaltests/api/v2/clients/blacklist_client.py0000664000567000056710000000415312701406241026463 0ustar jenkinsjenkins00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from functionaltests.api.v2.models.blacklist_model import BlacklistModel from functionaltests.api.v2.models.blacklist_model import BlacklistListModel from functionaltests.common.client import ClientMixin class BlacklistClient(ClientMixin): def blacklists_uri(self, filters=None): return self.create_uri("/blacklists", filters=filters) def blacklist_uri(self, blacklist_id): return "{0}/{1}".format(self.blacklists_uri(), blacklist_id) def list_blacklists(self, filters=None, **kwargs): resp, body = self.client.get(self.blacklists_uri(filters), **kwargs) return self.deserialize(resp, body, BlacklistListModel) def get_blacklist(self, blacklist_id, **kwargs): resp, body = self.client.get(self.blacklist_uri(blacklist_id)) return self.deserialize(resp, body, BlacklistModel) def post_blacklist(self, blacklist_model, **kwargs): resp, body = self.client.post( self.blacklists_uri(), body=blacklist_model.to_json(), **kwargs) return self.deserialize(resp, body, BlacklistModel) def patch_blacklist(self, blacklist_id, blacklist_model, **kwargs): resp, body = self.client.patch( self.blacklist_uri(blacklist_id), body=blacklist_model.to_json(), **kwargs) return self.deserialize(resp, body, BlacklistModel) def delete_blacklist(self, blacklist_id, **kwargs): return self.client.delete(self.blacklist_uri(blacklist_id), **kwargs) designate-2.0.0/functionaltests/api/v2/clients/zone_import_client.py0000664000567000056710000000456112701406241027063 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from functionaltests.api.v2.models.zone_import_model import ZoneImportModel from functionaltests.api.v2.models.zone_import_model import ZoneImportListModel from functionaltests.common.client import ClientMixin from functionaltests.common import utils class ZoneImportClient(ClientMixin): def zone_imports_uri(self, filters=None): return self.create_uri("/zones/tasks/imports", filters=filters) def zone_import_uri(self, id): return "{0}/{1}".format(self.zone_imports_uri(), id) def list_zone_imports(self, filters=None, **kwargs): resp, body = self.client.get( self.zone_imports_uri(filters), **kwargs) return self.deserialize(resp, body, ZoneImportListModel) def get_zone_import(self, id, **kwargs): resp, body = self.client.get(self.zone_import_uri(id)) return self.deserialize(resp, body, ZoneImportModel) def post_zone_import(self, zonefile_data, **kwargs): headers = {'Content-Type': 'text/dns'} resp, body = self.client.post(self.zone_imports_uri(), body=zonefile_data, headers=headers, **kwargs) return self.deserialize(resp, body, ZoneImportModel) def delete_zone_import(self, id, **kwargs): resp, body = self.client.delete(self.zone_import_uri(id), **kwargs) return resp, body def wait_for_zone_import(self, zone_import_id): utils.wait_for_condition( lambda: self.is_zone_import_active(zone_import_id)) def is_zone_import_active(self, zone_import_id): resp, model = self.get_zone_import(zone_import_id) # don't have assertEqual but still want to fail fast assert resp.status == 200 if model.status == 'COMPLETE': return True elif model.status == 'ERROR': raise Exception("Saw ERROR status") return False designate-2.0.0/functionaltests/api/v2/clients/recordset_client.py0000664000567000056710000000630312701406241026504 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from tempest_lib.exceptions import NotFound from functionaltests.api.v2.models.recordset_model import RecordsetModel from functionaltests.api.v2.models.recordset_model import RecordsetListModel from functionaltests.common.client import ClientMixin from functionaltests.common import utils class RecordsetClient(ClientMixin): def recordsets_uri(self, zone_id, filters=None): return self.create_uri("/zones/{0}/recordsets".format(zone_id), filters=filters) def recordset_uri(self, zone_id, recordset_id): return "{0}/{1}".format(self.recordsets_uri(zone_id), recordset_id) def list_recordsets(self, zone_id, filters=None, **kwargs): resp, body = self.client.get( self.recordsets_uri(zone_id, filters), **kwargs) return self.deserialize(resp, body, RecordsetListModel) def get_recordset(self, zone_id, recordset_id, **kwargs): resp, body = self.client.get(self.recordset_uri(zone_id, recordset_id), **kwargs) return self.deserialize(resp, body, RecordsetModel) def post_recordset(self, zone_id, recordset_model, **kwargs): resp, body = self.client.post(self.recordsets_uri(zone_id), body=recordset_model.to_json(), **kwargs) return self.deserialize(resp, body, RecordsetModel) def put_recordset(self, zone_id, recordset_id, recordset_model, **kwargs): resp, body = self.client.put(self.recordset_uri(zone_id, recordset_id), body=recordset_model.to_json(), **kwargs) return self.deserialize(resp, body, RecordsetModel) def delete_recordset(self, zone_id, recordset_id, **kwargs): resp, body = self.client.delete( self.recordset_uri(zone_id, recordset_id), **kwargs) return self.deserialize(resp, body, RecordsetModel) def wait_for_recordset(self, zone_id, recordset_id): utils.wait_for_condition( lambda: self.is_recordset_active(zone_id, recordset_id)) def wait_for_404(self, zone_id, recordset_id): utils.wait_for_condition( lambda: self.is_recordset_404(zone_id, recordset_id)) def is_recordset_active(self, zone_id, recordset_id): resp, model = self.get_recordset( zone_id, recordset_id) assert resp.status == 200 if model.status == 'ACTIVE': return True elif model.status == 'ERROR': raise Exception("Saw ERROR status") return False def is_recordset_404(self, zone_id, recordset_id): try: self.get_recordset(zone_id, recordset_id) except NotFound: return True return False designate-2.0.0/functionaltests/api/v2/clients/tld_client.py0000664000567000056710000000363112701406241025276 0ustar jenkinsjenkins00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from functionaltests.api.v2.models.tld_model import TLDModel from functionaltests.api.v2.models.tld_model import TLDListModel from functionaltests.common.client import ClientMixin class TLDClient(ClientMixin): def tlds_uri(self, filters=None): return self.create_uri("/tlds", filters=filters) def tld_uri(self, tld_id): return "{0}/{1}".format(self.tlds_uri(), tld_id) def list_tlds(self, filters=None, **kwargs): resp, body = self.client.get(self.tlds_uri(filters), **kwargs) return self.deserialize(resp, body, TLDListModel) def get_tld(self, tld_id, **kwargs): resp, body = self.client.get(self.tld_uri(tld_id)) return self.deserialize(resp, body, TLDModel) def post_tld(self, tld_model, **kwargs): resp, body = self.client.post( self.tlds_uri(), body=tld_model.to_json(), **kwargs) return self.deserialize(resp, body, TLDModel) def patch_tld(self, tld_id, tld_model, **kwargs): resp, body = self.client.patch( self.tld_uri(tld_id), body=tld_model.to_json(), **kwargs) return self.deserialize(resp, body, TLDModel) def delete_tld(self, tld_id, **kwargs): return self.client.delete(self.tld_uri(tld_id), **kwargs) designate-2.0.0/functionaltests/api/v2/clients/zone_client.py0000664000567000056710000000567612701406241025501 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from tempest_lib.exceptions import NotFound from functionaltests.api.v2.models.zone_model import ZoneModel from functionaltests.api.v2.models.zone_model import ZoneListModel from functionaltests.common.client import ClientMixin from functionaltests.common import utils class ZoneClient(ClientMixin): def zones_uri(self, filters=None): return self.create_uri("/zones", filters=filters) def zone_uri(self, id): return "{0}/{1}".format(self.zones_uri(), id) def list_zones(self, filters=None, **kwargs): resp, body = self.client.get(self.zones_uri(filters), **kwargs) return self.deserialize(resp, body, ZoneListModel) def get_zone(self, id, **kwargs): resp, body = self.client.get(self.zone_uri(id)) return self.deserialize(resp, body, ZoneModel) def post_zone(self, zone_model, **kwargs): resp, body = self.client.post(self.zones_uri(), body=zone_model.to_json(), **kwargs) return self.deserialize(resp, body, ZoneModel) def patch_zone(self, id, zone_model, **kwargs): resp, body = self.client.patch(self.zone_uri(id), body=zone_model.to_json(), **kwargs) return self.deserialize(resp, body, ZoneModel) def delete_zone(self, id, **kwargs): resp, body = self.client.delete(self.zone_uri(id), **kwargs) return self.deserialize(resp, body, ZoneModel) def wait_for_zone(self, zone_id): utils.wait_for_condition(lambda: self.is_zone_active(zone_id)) def wait_for_zone_404(self, zone_id): utils.wait_for_condition(lambda: self.is_zone_404(zone_id)) def is_zone_active(self, zone_id): resp, model = self.get_zone(zone_id) # don't have assertEqual but still want to fail fast assert resp.status == 200 if model.status == 'ACTIVE': return True elif model.status == 'ERROR': raise Exception("Saw ERROR status") return False def is_zone_404(self, zone_id): try: # tempest_lib rest client raises exceptions on bad status codes resp, model = self.get_zone(zone_id) except NotFound: return True return False def zones_dot_json(self, filters=None, **kwargs): uri = self.create_uri("/zones.json", filters=filters) resp, body = self.client.get(uri, **kwargs) return self.deserialize(resp, body, ZoneListModel) designate-2.0.0/functionaltests/api/v2/clients/transfer_requests_client.py0000664000567000056710000000620612701406241030273 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from functionaltests.api.v2.models.transfer_requests_model import \ TransferRequestsModel from functionaltests.api.v2.models.transfer_requests_model import \ TransferRequestsListModel from functionaltests.common.client import ClientMixin class TransferRequestClient(ClientMixin): def create_transfer_requests_uri(self, zone_id, filters=None): return self.create_uri( "/zones/{0}/tasks/transfer_requests".format(zone_id), filters=filters, ) def transfer_requests_uri(self, filters=None): return self.create_uri( "/zones/tasks/transfer_requests", filters=filters, ) def transfer_request_uri(self, transfer_request_id): return self.create_uri( "/zones/tasks/transfer_requests/{0}".format(transfer_request_id) ) def list_transfer_requests(self, filters=None, **kwargs): resp, body = self.client.get( self.transfer_requests_uri(filters), **kwargs) return self.deserialize(resp, body, TransferRequestsListModel) def get_transfer_request(self, transfer_request_id, **kwargs): resp, body = self.client.get(self.transfer_request_uri( transfer_request_id), **kwargs) return self.deserialize(resp, body, TransferRequestsModel) def post_transfer_request(self, zone_id, transfer_request_model=None, **kwargs): resp, body = self.client.post( self.create_transfer_requests_uri(zone_id), body=transfer_request_model.to_json(), **kwargs) return self.deserialize(resp, body, TransferRequestsModel) def post_transfer_request_empty_body(self, zone_id, **kwargs): resp, body = self.client.post( self.create_transfer_requests_uri(zone_id), body=None, **kwargs) return self.deserialize(resp, body, TransferRequestsModel) def put_transfer_request(self, transfer_request_id, transfer_request_model, **kwargs): resp, body = self.client.put(self.transfer_request_uri( transfer_request_id), body=transfer_request_model.to_json(), **kwargs) return self.deserialize(resp, body, TransferRequestsModel) def delete_transfer_request(self, transfer_request_id, **kwargs): resp, body = self.client.delete( self.transfer_request_uri(transfer_request_id), **kwargs) # the body is empty on a successful delete if body: return self.deserialize(resp, body, TransferRequestsModel) return resp, body designate-2.0.0/functionaltests/api/v2/base.py0000664000567000056710000000464312701406241022432 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from oslo_config import cfg from tempest_lib import exceptions from functionaltests.api.v2.clients.quotas_client import QuotasClient from functionaltests.api.v2.clients.tld_client import TLDClient from functionaltests.api.v2.models.quotas_model import QuotasModel from functionaltests.api.v2.models.tld_model import TLDModel from functionaltests.common.base import BaseDesignateTest class DesignateV2Test(BaseDesignateTest): def increase_quotas(self, user): if cfg.CONF.testconfig.no_admin_setup: return QuotasClient.as_user('admin').patch_quotas( QuotasClient.as_user(user).tenant_id, QuotasModel.from_dict({ 'quota': { 'zones': 9999999, 'recordset_records': 9999999, 'zone_records': 9999999, 'zone_recordsets': 9999999}})) def ensure_tld_exists(self, tld='com'): if cfg.CONF.testconfig.no_admin_setup: return try: tld_model = TLDModel.from_dict({'name': tld}) TLDClient.as_user('admin').post_tld(tld_model) except exceptions.Conflict: pass def _assert_invalid_uuid(self, method, *args, **kw): """ Test that UUIDs used in the URL is valid. """ self._assert_exception( exceptions.BadRequest, 'invalid_uuid', 400, method, *args) def _assert_exception(self, exc, type_, status, method, *args, **kwargs): """ Checks the response that a api call with a exception contains the wanted data. """ try: method(*args, **kwargs) except exc as e: self.assertEqual(status, e.resp_body['code']) self.assertEqual(type_, e.resp_body['type']) return e else: raise self.failureException("Test failed due to no exception.") designate-2.0.0/functionaltests/api/v2/test_recordset_unauthed.py0000664000567000056710000000674512701406241026453 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from tempest_lib import exceptions from functionaltests.common import datagen from functionaltests.common import utils from functionaltests.api.v2.base import DesignateV2Test from functionaltests.api.v2.clients.recordset_client import RecordsetClient from functionaltests.api.v2.clients.zone_client import ZoneClient @utils.parameterized_class class RecordsetTest(DesignateV2Test): def setUp(self): super(RecordsetTest, self).setUp() self.increase_quotas(user='default') self.ensure_tld_exists('com') resp, self.zone = ZoneClient.as_user('default').post_zone( datagen.random_zone_data()) ZoneClient.as_user('default').wait_for_zone(self.zone.id) self.client = RecordsetClient.as_user('default', with_token=False) def tearDown(self): super(RecordsetTest, self).tearDown() resp, self.zone = ZoneClient.as_user('default').delete_zone( self.zone.id) def test_create_a_recordset(self): post_model = datagen.random_a_recordset(self.zone.name) self.assertRaises( exceptions.Unauthorized, self.client.post_recordset, self.zone.id, post_model) def test_get_fake_recordset(self): self.assertRaises( exceptions.Unauthorized, self.client.get_recordset, self.zone.id, 'junk') def test_get_existing_recordset(self): post_model = datagen.random_a_recordset(self.zone.name) resp, resp_model = RecordsetClient.as_user('default') \ .post_recordset(self.zone.id, post_model) self.assertRaises( exceptions.Unauthorized, self.client.get_recordset, self.zone.id, resp_model.id) def test_list_recordsets(self): self.assertRaises( exceptions.Unauthorized, self.client.list_recordsets, self.zone.id) def test_update_fake_recordset(self): put_model = datagen.random_a_recordset(self.zone.name) self.assertRaises( exceptions.Unauthorized, self.client.put_recordset, self.zone.id, 'junk', put_model) def test_update_existing_recordset(self): post_model = datagen.random_a_recordset(self.zone.name) resp, resp_model = RecordsetClient.as_user('default') \ .post_recordset(self.zone.id, post_model) self.assertRaises( exceptions.Unauthorized, self.client.put_recordset, self.zone.id, resp_model.id, post_model) def test_delete_fake_recordset(self): self.assertRaises( exceptions.Unauthorized, self.client.delete_recordset, self.zone.id, 'junk') def test_delete_existing_recordset(self): post_model = datagen.random_a_recordset(self.zone.name) resp, resp_model = RecordsetClient.as_user('default') \ .post_recordset(self.zone.id, post_model) self.assertRaises( exceptions.Unauthorized, self.client.delete_recordset, self.zone.id, resp_model.id) designate-2.0.0/functionaltests/api/v2/test_zone_ownership_transfers.py0000664000567000056710000001710712701406241027716 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from tempest_lib import exceptions from functionaltests.common import datagen from functionaltests.common import utils from functionaltests.api.v2.base import DesignateV2Test from functionaltests.api.v2.clients.transfer_requests_client import \ TransferRequestClient from functionaltests.api.v2.clients.transfer_accepts_client import \ TransferAcceptClient from functionaltests.api.v2.clients.zone_client import ZoneClient from functionaltests.api.v2.fixtures import ZoneFixture from functionaltests.api.v2.fixtures import TransferRequestFixture @utils.parameterized_class class TransferZoneOwnerShipTest(DesignateV2Test): def setUp(self): super(TransferZoneOwnerShipTest, self).setUp() self.increase_quotas(user='default') self.increase_quotas(user='alt') self.ensure_tld_exists('com') self.zone = self.useFixture(ZoneFixture()).created_zone def test_list_transfer_requests(self): self.useFixture(TransferRequestFixture( zone=self.zone, post_model=datagen.random_transfer_request_data(), )) resp, model = TransferRequestClient.as_user('default') \ .list_transfer_requests() self.assertEqual(200, resp.status) self.assertGreater(len(model.transfer_requests), 0) def test_create_zone_transfer_request(self): fixture = self.useFixture(TransferRequestFixture( zone=self.zone, post_model=datagen.random_transfer_request_data(), )) self.assertEqual(201, fixture.post_resp.status) self.assertEqual(self.zone.id, fixture.transfer_request.zone_id) # todo: this fails. the zone_name is null in the POST's response, but # it's filled in on a subsequent get # self.assertEqual(self.zone.name, fixture.transfer_request.zone_name) self.assertEqual(TransferRequestClient.as_user(fixture.user).tenant_id, fixture.transfer_request.project_id) self.assertIsNone(fixture.transfer_request.target_project_id) # check that the zone_name is filled in resp, transfer_request = TransferRequestClient.as_user(fixture.user) \ .get_transfer_request(fixture.transfer_request.id) self.assertEqual(self.zone.name, transfer_request.zone_name) def test_view_zone_transfer_request(self): fixture = self.useFixture(TransferRequestFixture( zone=self.zone, post_model=datagen.random_transfer_request_data(), )) resp, transfer_request = TransferRequestClient.as_user('alt')\ .get_transfer_request(fixture.transfer_request.id) self.assertEqual(resp.status, 200) self.assertIsNone(getattr(transfer_request, 'key', None)) def test_create_zone_transfer_request_scoped(self): target_project_id = TransferRequestClient.as_user('alt').tenant_id post_model = datagen.random_transfer_request_data( target_project_id=target_project_id) fixture = self.useFixture(TransferRequestFixture( zone=self.zone, post_model=post_model, user='default', target_user='alt', )) self.assertEqual(201, fixture.post_resp.status) self.assertEqual(self.zone.id, fixture.transfer_request.zone_id) # todo: the zone_name is null initially, but shows up on later gets # self.assertEqual(fixture.transfer_request.zone_name, self.zone.name) self.assertEqual(TransferRequestClient.as_user(fixture.user).tenant_id, fixture.transfer_request.project_id) self.assertEqual(target_project_id, fixture.transfer_request.target_project_id) resp, transfer_request = TransferRequestClient.as_user('alt')\ .get_transfer_request(fixture.transfer_request.id) self.assertEqual(200, resp.status) def test_view_zone_transfer_request_scoped(self): target_project_id = TransferRequestClient.as_user('admin').tenant_id post_model = datagen.random_transfer_request_data( target_project_id=target_project_id) fixture = self.useFixture(TransferRequestFixture( zone=self.zone, post_model=post_model, user='default', target_user='admin', )) transfer_request = fixture.transfer_request self.assertEqual(transfer_request.target_project_id, target_project_id) self._assert_exception( exceptions.NotFound, 'zone_transfer_request_not_found', 404, TransferRequestClient.as_user('alt').get_transfer_request, self.zone.id) resp, transfer_request = TransferRequestClient.as_user('admin')\ .get_transfer_request(transfer_request.id) self.assertEqual(200, resp.status) def test_create_zone_transfer_request_no_body(self): client = TransferRequestClient.as_user('default') resp, transfer_request = client \ .post_transfer_request_empty_body(self.zone.id) self.assertEqual(201, resp.status) self.addCleanup(TransferRequestFixture.cleanup_transfer_request, client, transfer_request.id) def test_do_zone_transfer(self): fixture = self.useFixture(TransferRequestFixture( zone=self.zone, post_model=datagen.random_transfer_request_data(), user='default', target_user='alt', )) transfer_request = fixture.transfer_request resp, transfer_accept = TransferAcceptClient.as_user('alt')\ .post_transfer_accept( datagen.random_transfer_accept_data( key=transfer_request.key, zone_transfer_request_id=transfer_request.id )) self.assertEqual(201, resp.status) def test_do_zone_transfer_scoped(self): target_project_id = TransferRequestClient.as_user('alt').tenant_id post_model = datagen.random_transfer_request_data( target_project_id=target_project_id) fixture = self.useFixture(TransferRequestFixture( zone=self.zone, post_model=post_model, user='default', target_user='alt', )) transfer_request = fixture.transfer_request resp, retrived_transfer_request = TransferRequestClient.\ as_user('alt').get_transfer_request(transfer_request.id) self.assertEqual(200, resp.status) resp, transfer_accept = TransferAcceptClient.as_user('alt')\ .post_transfer_accept( datagen.random_transfer_accept_data( key=transfer_request.key, zone_transfer_request_id=transfer_request.id )) self.assertEqual(201, resp.status) client = ZoneClient.as_user('default') self._assert_exception( exceptions.NotFound, 'zone_not_found', 404, client.get_zone, self.zone.id) resp, zone = ZoneClient.as_user('alt').get_zone(self.zone.id) self.assertEqual(200, resp.status) designate-2.0.0/functionaltests/api/v2/test_pool_unauthed.py0000664000567000056710000000445212701406241025423 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from tempest_lib import exceptions from functionaltests.common import datagen from functionaltests.api.v2.base import DesignateV2Test from functionaltests.api.v2.clients.pool_client import PoolClient from functionaltests.api.v2.fixtures import PoolFixture class PoolTest(DesignateV2Test): def setUp(self): super(PoolTest, self).setUp() self.increase_quotas(user='admin') self.client = PoolClient.as_user('admin', with_token=False) self.fixture = self.useFixture(PoolFixture(user='admin')) def test_create_pool(self): self.assertRaises( exceptions.Unauthorized, self.client.post_pool, datagen.random_pool_data()) def test_get_fake_pool(self): self.assertRaises( exceptions.Unauthorized, self.client.get_pool, 'junk') def test_get_existing_pool(self): self.assertRaises( exceptions.Unauthorized, self.client.get_pool, self.fixture.created_pool.id) def test_list_pools(self): self.assertRaises( exceptions.Unauthorized, self.client.list_pools) def test_update_fake_pool(self): self.assertRaises( exceptions.Unauthorized, self.client.patch_pool, 'junk', datagen.random_pool_data()) def test_update_existing_pool(self): self.assertRaises( exceptions.Unauthorized, self.client.patch_pool, self.fixture.created_pool.id, datagen.random_pool_data()) def test_delete_fake_pool(self): self.assertRaises( exceptions.Unauthorized, self.client.delete_pool, 'junk') def test_delete_existing_pool(self): self.assertRaises( exceptions.Unauthorized, self.client.delete_pool, self.fixture.created_pool.id) designate-2.0.0/functionaltests/api/v2/test_zone.py0000664000567000056710000001556012701406241023532 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from tempest_lib.exceptions import Conflict from tempest_lib.exceptions import Forbidden from tempest_lib.exceptions import NotFound from functionaltests.common import datagen from functionaltests.api.v2.base import DesignateV2Test from functionaltests.api.v2.clients.recordset_client import RecordsetClient from functionaltests.api.v2.clients.zone_client import ZoneClient from functionaltests.api.v2.clients.zone_import_client import ZoneImportClient from functionaltests.api.v2.clients.zone_export_client import ZoneExportClient from functionaltests.api.v2.fixtures import ZoneFixture from functionaltests.api.v2.fixtures import ZoneImportFixture from functionaltests.api.v2.fixtures import ZoneExportFixture from functionaltests.common.models import ZoneFileRecord class ZoneTest(DesignateV2Test): def setUp(self): super(ZoneTest, self).setUp() self.increase_quotas(user='default') self.ensure_tld_exists('com') self.fixture = self.useFixture(ZoneFixture(user='default')) def test_list_zones(self): resp, model = ZoneClient.as_user('default').list_zones() self.assertEqual(200, resp.status) self.assertGreater(len(model.zones), 0) def test_create_zone(self): self.assertEqual(202, self.fixture.post_resp.status) def test_update_zone(self): old_model = self.fixture.created_zone patch_model = datagen.random_zone_data() del patch_model.name # don't try to override the zone name resp, new_model = ZoneClient.as_user('default').patch_zone( old_model.id, patch_model) self.assertEqual(202, resp.status) ZoneClient.as_user('default').wait_for_zone(new_model.id) resp, model = ZoneClient.as_user('default').get_zone(new_model.id) self.assertEqual(200, resp.status) self.assertEqual(old_model.id, new_model.id) self.assertEqual(old_model.name, new_model.name) self.assertEqual(patch_model.ttl, new_model.ttl) self.assertEqual(patch_model.email, new_model.email) def test_delete_zone(self): client = ZoneClient.as_user('default') resp, model = client.delete_zone(self.fixture.created_zone.id) self.assertEqual(202, resp.status) client.wait_for_zone_404(model.id) def test_list_zones_dot_json_fails(self): self.assertRaises(NotFound, lambda: ZoneClient.as_user('default').zones_dot_json()) class ZoneOwnershipTest(DesignateV2Test): def setup(self): super(ZoneTest, self).setUp() self.increase_quotas(user='default') self.increase_quotas(user='alt') self.ensure_tld_exists('com') def test_no_create_duplicate_domain(self): post_model = self.useFixture(ZoneFixture(user='default')).post_model self.assertRaises(Conflict, lambda: ZoneClient.as_user('default').post_zone(post_model)) self.assertRaises(Conflict, lambda: ZoneClient.as_user('alt').post_zone(post_model)) def test_no_create_subdomain_by_alt_user(self): zone = self.useFixture(ZoneFixture(user='default')).post_model subzone = datagen.random_zone_data(name='sub.' + zone.name) subsubzone = datagen.random_zone_data(name='sub.sub.' + zone.name) self.assertRaises(Forbidden, lambda: ZoneClient.as_user('alt').post_zone(subzone)) self.assertRaises(Forbidden, lambda: ZoneClient.as_user('alt').post_zone(subsubzone)) def test_no_create_superdomain_by_alt_user(self): superzone = datagen.random_zone_data() zone = datagen.random_zone_data(name="a.b." + superzone.name) self.useFixture(ZoneFixture(zone, user='default')) self.assertRaises(Forbidden, lambda: ZoneClient.as_user('alt').post_zone(superzone)) class ZoneImportTest(DesignateV2Test): def setUp(self): super(ZoneImportTest, self).setUp() self.increase_quotas(user='default') self.ensure_tld_exists('com') def test_import_domain(self): user = 'default' import_client = ZoneImportClient.as_user(user) zone_client = ZoneClient.as_user(user) fixture = self.useFixture(ZoneImportFixture(user=user)) import_id = fixture.zone_import.id resp, model = import_client.get_zone_import(import_id) self.assertEqual(200, resp.status) self.assertEqual('COMPLETE', model.status) self.addCleanup(ZoneFixture.cleanup_zone, zone_client, model.zone_id) # Wait for the zone to become 'ACTIVE' zone_client.wait_for_zone(model.zone_id) resp, zone_model = zone_client.get_zone(model.zone_id) # Now make sure we can delete the zone_import import_client.delete_zone_import(import_id) self.assertRaises(NotFound, lambda: import_client.get_zone_import(model.id)) class ZoneExportTest(DesignateV2Test): def setUp(self): super(ZoneExportTest, self).setUp() self.increase_quotas(user='default') self.ensure_tld_exists('com') def test_export_domain(self): user = 'default' zone_fixture = self.useFixture(ZoneFixture(user=user)) zone = zone_fixture.created_zone export_fixture = self.useFixture(ZoneExportFixture(zone.id, user=user)) export_id = export_fixture.zone_export.id export_client = ZoneExportClient.as_user(user) resp, model = export_client.get_zone_export(export_id) self.assertEqual(200, resp.status) self.assertEqual('COMPLETE', model.status) # fetch the zone file resp, zone_file = export_client.get_exported_zone(export_id) self.assertEqual(200, resp.status) self.assertEqual(zone.name, zone_file.origin) self.assertEqual(zone.ttl, zone_file.ttl) # the list of records in the zone file must match the zone's recordsets # (in this case there should be only two records - a SOA and an NS?) recordset_client = RecordsetClient.as_user(user) resp, model = recordset_client.list_recordsets(zone.id) records = [] for recordset in model.recordsets: records.extend(ZoneFileRecord.records_from_recordset(recordset)) self.assertEqual(set(records), set(zone_file.records)) export_client.delete_zone_export(export_id) self.assertRaises(NotFound, lambda: export_client.get_zone_export(export_id)) designate-2.0.0/functionaltests/api/v2/test_pool.py0000664000567000056710000000654012701406241023526 0ustar jenkinsjenkins00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Author: Endre Karlson # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import uuid from tempest_lib import exceptions from functionaltests.common import datagen from functionaltests.api.v2.base import DesignateV2Test from functionaltests.api.v2.clients.pool_client import PoolClient from functionaltests.api.v2.fixtures import PoolFixture class PoolTest(DesignateV2Test): def test_list_pools(self): self.useFixture(PoolFixture()) resp, model = PoolClient.as_user('admin').list_pools() self.assertEqual(200, resp.status) self.assertGreater(len(model.pools), 0) def test_create_pool(self): fixture = self.useFixture(PoolFixture()) post_model = fixture.post_model created_pool = fixture.created_pool self.assertEqual(post_model.name, created_pool.name) self.assertEqual(post_model.ns_records, created_pool.ns_records) def test_update_pool(self): old_model = self.useFixture(PoolFixture()).created_pool patch_model = datagen.random_pool_data() resp, new_model = PoolClient.as_user('admin').patch_pool( old_model.id, patch_model) self.assertEqual(202, resp.status) resp, model = PoolClient.as_user('admin').get_pool(new_model.id) self.assertEqual(200, resp.status) self.assertEqual(old_model.id, new_model.id) self.assertEqual(patch_model.name, new_model.name) def test_delete_pool(self): pool = self.useFixture(PoolFixture()).created_pool resp, model = PoolClient.as_user('admin').delete_pool(pool.id) self.assertEqual(204, resp.status) def test_get_pool_404(self): client = PoolClient.as_user('admin') self._assert_exception( exceptions.NotFound, 'pool_not_found', 404, client.get_pool, str(uuid.uuid4())) def test_update_pool_404(self): model = datagen.random_pool_data() client = PoolClient.as_user('admin') self._assert_exception( exceptions.NotFound, 'pool_not_found', 404, client.patch_pool, str(uuid.uuid4()), model) def test_delete_pool_404(self): client = PoolClient.as_user('admin') self._assert_exception( exceptions.NotFound, 'pool_not_found', 404, client.delete_pool, str(uuid.uuid4())) def test_get_pool_invalid_uuid(self): client = PoolClient.as_user('admin') self._assert_invalid_uuid(client.get_pool, 'fooo') def test_update_pool_invalid_uuid(self): model = datagen.random_pool_data() client = PoolClient.as_user('admin') self._assert_invalid_uuid(client.patch_pool, 'fooo', model) def test_delete_pool_invalid_uuid(self): client = PoolClient.as_user('admin') self._assert_invalid_uuid(client.get_pool, 'fooo') designate-2.0.0/functionaltests/api/v2/fixtures.py0000664000567000056710000002276312701406241023374 0ustar jenkinsjenkins00000000000000""" Copyright 2015 Rackspace Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. """ from __future__ import absolute_import from __future__ import print_function import sys import traceback import fixtures from tempest_lib.exceptions import NotFound from testtools.runtest import MultipleExceptions from functionaltests.api.v2.clients.blacklist_client import BlacklistClient from functionaltests.api.v2.clients.pool_client import PoolClient from functionaltests.api.v2.clients.recordset_client import RecordsetClient from functionaltests.api.v2.clients.tld_client import TLDClient from functionaltests.api.v2.clients.zone_client import ZoneClient from functionaltests.api.v2.clients.zone_import_client import ZoneImportClient from functionaltests.api.v2.clients.zone_export_client import ZoneExportClient from functionaltests.api.v2.clients.transfer_requests_client import \ TransferRequestClient from functionaltests.common import datagen class BaseFixture(fixtures.Fixture): def setUp(self): # Sometimes, exceptions are raised in _setUp methods on fixtures. # testtools pushes the exception into a MultipleExceptions object along # with an artificial SetupError, which produces bad error messages. # This just logs those stack traces to stderr for easier debugging. try: super(BaseFixture, self).setUp() except MultipleExceptions as e: for i, exc_info in enumerate(e.args): print('--- printing MultipleExceptions traceback {} of {} ---' .format(i + 1, len(e.args)), file=sys.stderr) traceback.print_exception(*exc_info) raise class ZoneFixture(BaseFixture): def __init__(self, post_model=None, user='default'): super(ZoneFixture, self).__init__() self.post_model = post_model or datagen.random_zone_data() self.user = user def _setUp(self): super(ZoneFixture, self)._setUp() self._create_zone() def _create_zone(self): client = ZoneClient.as_user(self.user) self.post_resp, self.created_zone = client.post_zone(self.post_model) assert self.post_resp.status == 202 self.addCleanup(self.cleanup_zone, client, self.created_zone.id) client.wait_for_zone(self.created_zone.id) @classmethod def cleanup_zone(cls, client, zone_id): try: client.delete_zone(zone_id) except NotFound: pass class ZoneImportFixture(BaseFixture): def __init__(self, post_model=None, user='default'): super(ZoneImportFixture, self).__init__() self.post_model = post_model or datagen.random_zonefile_data() self.user = user def _setUp(self): super(ZoneImportFixture, self)._setUp() self._import_zone() def _import_zone(self): client = ZoneImportClient.as_user(self.user) self.post_resp, self.zone_import = client.post_zone_import( self.post_model) assert self.post_resp.status == 202 self.addCleanup(self.cleanup_zone_import, client, self.zone_import.id) client.wait_for_zone_import(self.zone_import.id) @classmethod def cleanup_zone_import(cls, client, import_id): try: client.delete_zone_import(import_id) except NotFound: pass class ZoneExportFixture(BaseFixture): def __init__(self, zone_id, user='default'): super(ZoneExportFixture, self).__init__() self.zone_id = zone_id self.user = user def _setUp(self): super(ZoneExportFixture, self)._setUp() self._export_zone() def _export_zone(self): client = ZoneExportClient.as_user(self.user) self.post_resp, self.zone_export = client.post_zone_export( self.zone_id) assert self.post_resp.status == 202 self.addCleanup(self.cleanup_zone_export, client, self.zone_export.id) client.wait_for_zone_export(self.zone_export.id) @classmethod def cleanup_zone_export(cls, client, export_id): try: client.delete_zone_export(export_id) except NotFound: pass class RecordsetFixture(BaseFixture): def __init__(self, zone_id, post_model, user='default'): super(RecordsetFixture, self).__init__() self.zone_id = zone_id self.post_model = post_model self.user = user def _setUp(self): super(RecordsetFixture, self)._setUp() self._create_recordset() def _create_recordset(self): client = RecordsetClient.as_user(self.user) self.post_resp, self.created_recordset = client.post_recordset( self.zone_id, self.post_model) assert self.post_resp.status == 202 self.addCleanup(self.cleanup_recordset, client, self.zone_id, self.created_recordset.id) assert self.created_recordset.status == "PENDING" assert self.created_recordset.name == self.post_model.name assert self.created_recordset.ttl == self.post_model.ttl assert self.created_recordset.records == self.post_model.records RecordsetClient.as_user('default').wait_for_recordset( self.zone_id, self.created_recordset.id) @classmethod def cleanup_recordset(cls, client, zone_id, recordset_id): try: client.delete_recordset(zone_id, recordset_id) except NotFound: pass class PoolFixture(BaseFixture): def __init__(self, post_model=None, user='admin'): super(PoolFixture, self).__init__() self.post_model = post_model or datagen.random_pool_data() self.user = user def _setUp(self): super(PoolFixture, self)._setUp() self._create_pool() def _create_pool(self): client = PoolClient.as_user(self.user) self.post_resp, self.created_pool = client.post_pool(self.post_model) assert self.post_resp.status == 201 self.addCleanup(self.cleanup_pool, client, self.created_pool.id) @classmethod def cleanup_pool(cls, client, pool_id): try: client.delete_pool(pool_id) except NotFound: pass class TransferRequestFixture(BaseFixture): def __init__(self, zone, post_model=None, user='default', target_user='alt'): """Assuming the zone is being transferred between the two users, this fixture will ensure that zone is deleted by trying to delete the zone as each user. """ self.zone = zone self.post_model = post_model or datagen.random_transfer_request_data() self.user = user self.target_user = target_user def _setUp(self): super(TransferRequestFixture, self)._setUp() self._create_transfer_request() def _create_transfer_request(self): client = TransferRequestClient.as_user(self.user) self.post_resp, self.transfer_request = client \ .post_transfer_request(self.zone.id, self.post_model) assert self.post_resp.status == 201 self.addCleanup(self.cleanup_transfer_request, client, self.transfer_request.id) self.addCleanup(ZoneFixture.cleanup_zone, ZoneClient.as_user(self.user), self.zone.id) self.addCleanup(ZoneFixture.cleanup_zone, ZoneClient.as_user(self.target_user), self.zone.id) @classmethod def cleanup_transfer_request(self, client, transfer_id): try: client.delete_transfer_request(transfer_id) except NotFound: pass class BlacklistFixture(BaseFixture): def __init__(self, post_model=None, user='admin'): super(BlacklistFixture, self).__init__() self.post_model = post_model or datagen.random_blacklist_data() self.user = user def _setUp(self): super(BlacklistFixture, self)._setUp() self._create_blacklist() def _create_blacklist(self): client = BlacklistClient.as_user(self.user) self.post_resp, self.created_blacklist = client.post_blacklist( self.post_model) assert self.post_resp.status == 201 self.addCleanup(self.cleanup_blacklist, client, self.created_blacklist.id) @classmethod def cleanup_blacklist(cls, client, blacklist_id): try: client.delete_blacklist(blacklist_id) except NotFound: pass class TLDFixture(BaseFixture): def __init__(self, post_model=None, user='admin'): super(TLDFixture, self).__init__() self.post_model = post_model or datagen.random_tld_data() self.user = user def _setUp(self): super(TLDFixture, self)._setUp() self._create_tld() def _create_tld(self): client = TLDClient.as_user(self.user) self.post_resp, self.created_tld = client.post_tld(self.post_model) assert self.post_resp.status == 201 self.addCleanup(self.cleanup_tld, client, self.created_tld.id) @classmethod def cleanup_tld(cls, client, tld_id): try: client.delete_tld(tld_id) except NotFound: pass designate-2.0.0/devstack/0000775000567000056710000000000012701406373016424 5ustar jenkinsjenkins00000000000000designate-2.0.0/devstack/exercise.sh0000775000567000056710000002211412701406241020564 0ustar jenkinsjenkins00000000000000#!/usr/bin/env bash # **designate.sh** # Simple Tests to verify designate is running echo "*********************************************************************" echo "Begin DevStack Exercise: $0" echo "*********************************************************************" # This script exits on an error so that errors don't compound and you see # only the first error that occurred. set -o errexit # Print the commands being run so that we can see the command that triggers # an error. It is also useful for following allowing as the install occurs. set -o xtrace # Keep track of the current directory SCRIPT_DIR=$(cd $(dirname "$0") && pwd) DEVSTACK_DIR=$(cd $SCRIPT_DIR/../..; pwd)/devstack if [ -x "$HOME/devstack/stack.sh" ]; then DEVSTACK_DIR=$HOME/devstack/ fi # Import common functions source $DEVSTACK_DIR/functions # Import configuration source $DEVSTACK_DIR/openrc admin admin # Import exercise configuration source $DEVSTACK_DIR/exerciserc # Skip if designate is not enabled is_service_enabled designate || exit 55 # Import settings + designate library source $SCRIPT_DIR/plugin.sh # Settings # ======== source $SCRIPT_DIR/settings # Used with dig to look up in DNS DIG_TIMEOUT=30 if [ "$DESIGNATE_BACKEND_DRIVER" == "akamai" ]; then # Akamai can be slow to propagate changes out DIG_TIMEOUT=300 fi # used with dig to look up in DNS DIG_FLAGS="-p $DESIGNATE_SERVICE_PORT_DNS @$DESIGNATE_SERVICE_HOST" # used with dig to do an AXFR against MDNS DIG_AXFR_FLAGS="-p $DESIGNATE_SERVICE_PORT_MDNS @$DESIGNATE_SERVICE_HOST AXFR +tcp +nocmd" # Functions # ========= function cleanup { # Try to cleanup any domains, this is important for backends like # Akamai/Dyn, where state is not fully reset between test runs. source $DEVSTACK_DIR/openrc admin admin designate --all-tenants domain-list -f csv | awk 'BEGIN { FS = "," } ; {print $1}' | \ tail -n+2 | xargs --no-run-if-empty -n1 designate --all-tenants domain-delete } trap cleanup EXIT function ensure_record_present { local record_name=$1 local record_type=$2 local record_value=$3 if [ "$DESIGNATE_BACKEND_DRIVER" = "fake" ] ; then # if the backend is fake, there will be no actual DNS records return 0 fi if ! timeout $DIG_TIMEOUT sh -c "while ! dig +short $DIG_FLAGS $record_name $record_type | grep \"$record_value\"; do sleep 1; done"; then die $LINENO "Error: record $record_name ($record_type) not found in DNS" fi # Display for debugging dig $DIG_FLAGS $record_name $record_type return 0 } function ensure_record_absent { local record_name=$1 local record_type=$2 local record_value=$3 if [ "$DESIGNATE_BACKEND_DRIVER" = "fake" ] ; then # if the backend is fake, there will be no actual DNS records return 0 fi if ! timeout $DIG_TIMEOUT sh -c "while dig +short $DIG_FLAGS $record_name $record_type | grep \"$record_value\"; do sleep 1; done"; then # Display for debugging dig $DIG_FLAGS $record_name $record_type die $LINENO "Error: record $record_name ($record_type) found in DNS, should be absent" fi return 0 } # do an AXFR request to MDNS # if it does not match the expected value, give an error function verify_axfr_in_mdns { # Display for debugging dig $DIG_AXFR_FLAGS "$1" if dig $DIG_AXFR_FLAGS "$1"; then if [ -n "$2" ] ; then local axfr_records=$(dig $DIG_AXFR_FLAGS "$1" | grep "$1" | wc -l) if [ "$axfr_records" = "$2" ] ; then return 0 else die $LINENO "Error: AXFR to MDNS did not return the expected number of records" fi fi return 0 else die $LINENO "Error: AXFR to MDNS did not return a correct response" fi } # get the domain id (uuid) given the domain name # if REQUIRED is set, die with an error if name not found function get_domain_id { local domain_name=$1 local required=$2 local domain_id=$(designate domain-list | egrep " $domain_name " | get_field 1) if [ "$required" = "1" ] ; then die_if_not_set $LINENO domain_id "Failure retrieving DOMAIN_ID" fi echo "$domain_id" } # get the domain_name given the id function get_domain_name { designate domain-list | grep "$1" | get_field 2 } # if the given domain does not exist, it will be created # the domain_id of the domain will be returned function get_or_create_domain_id { local domainid=$(get_domain_id "$1") if [[ -z "$domainid" ]]; then designate domain-create --name $1 --email admin@devstack.org --ttl 86400 --description "domain $1" 1>&2 domainid=$(designate domain-list | grep "$1" | get_field 1) fi echo $domainid } # get the record id (uuid) given the record name and domain id # if REQUIRED is set, die with an error if name not found function get_record_id { local domain_id=$1 local record_name=$2 local record_type=$3 local required=$4 local record_id=$(designate record-list $domain_id | egrep " $record_name " | egrep " $record_type " | get_field 1) if [ "$required" = "1" ] ; then die_if_not_set $LINENO record_id "Failure retrieving RECORD_ID" fi echo "$record_id" } # Testing Servers # =============== designate server-list # NUMBER_OF_RECORDS keeps track of the records we need to get for AXFR # We start with the number of NS lines returned from server list # (Header line makes up for SOA + Number of NS record lines) NUMBER_OF_RECORDS=$(designate server-list -f csv | wc -l) # Add 1 extra to account for the additional SOA at the end of the AXFR ((NUMBER_OF_RECORDS+=1)) # Testing Domains # =============== # List domains designate domain-list # Create random domain name DOMAIN_NAME="exercise-$(openssl rand -hex 4).com." # Create the domain designate domain-create --name $DOMAIN_NAME --email devstack@example.org DOMAIN_ID=$(get_domain_id $DOMAIN_NAME 1) # Fetch the domain designate domain-get $DOMAIN_ID # List the nameservers hosting the domain designate domain-servers-list $DOMAIN_ID # Testing Records # =============== # Create random record name A_RECORD_NAME="$(openssl rand -hex 4).${DOMAIN_NAME}" # Create an A record designate record-create $DOMAIN_ID --name $A_RECORD_NAME --type A --data 127.0.0.1 ((NUMBER_OF_RECORDS++)) A_RECORD_ID=$(get_record_id $DOMAIN_ID $A_RECORD_NAME A) # Fetch the record designate record-get $DOMAIN_ID $A_RECORD_ID # Verify the record is published in DNS ensure_record_present $A_RECORD_NAME A 127.0.0.1 # ----- # Create random record name AAAA_RECORD_NAME="$(openssl rand -hex 4).${DOMAIN_NAME}" # Create an AAAA record designate record-create $DOMAIN_ID --name $AAAA_RECORD_NAME --type AAAA --data "2607:f0d0:1002:51::4" ((NUMBER_OF_RECORDS++)) AAAA_RECORD_ID=$(get_record_id $DOMAIN_ID $AAAA_RECORD_NAME AAAA) # Fetch the record designate record-get $DOMAIN_ID $AAAA_RECORD_ID # Verify the record is published in DNS ensure_record_present $AAAA_RECORD_NAME AAAA 2607:f0d0:1002:51::4 # ----- # Create a MX record designate record-create $DOMAIN_ID --name $DOMAIN_NAME --type MX --priority 5 --data "mail.example.com." ((NUMBER_OF_RECORDS++)) MX_RECORD_ID=$(get_record_id $DOMAIN_ID $DOMAIN_NAME MX) # Fetch the record designate record-get $DOMAIN_ID $MX_RECORD_ID # Verify the record is published in DNS ensure_record_present $DOMAIN_NAME MX "5 mail.example.com." # ----- # Create a SRV record designate record-create $DOMAIN_ID --name _sip._tcp.$DOMAIN_NAME --type SRV --priority 10 --data "5 5060 sip.example.com." ((NUMBER_OF_RECORDS++)) SRV_RECORD_ID=$(get_record_id $DOMAIN_ID _sip._tcp.$DOMAIN_NAME SRV) # Fetch the record designate record-get $DOMAIN_ID $SRV_RECORD_ID # Verify the record is published in DNS ensure_record_present _sip._tcp.$DOMAIN_NAME SRV "10 5 5060 sip.example.com." # ----- # Create random record name CNAME_RECORD_NAME="$(openssl rand -hex 4).${DOMAIN_NAME}" # Create a CNAME record designate record-create $DOMAIN_ID --name $CNAME_RECORD_NAME --type CNAME --data $DOMAIN_NAME ((NUMBER_OF_RECORDS++)) CNAME_RECORD_ID=$(get_record_id $DOMAIN_ID $CNAME_RECORD_NAME CNAME) # Fetch the record designate record-get $DOMAIN_ID $CNAME_RECORD_ID # Verify the record is published in DNS ensure_record_present $CNAME_RECORD_NAME CNAME $DOMAIN_NAME # ----- # List Records designate record-list $DOMAIN_ID # Send an AXFR to MDNS and check for the records returned verify_axfr_in_mdns $DOMAIN_NAME $NUMBER_OF_RECORDS # ----- # Delete a Record designate record-delete $DOMAIN_ID $CNAME_RECORD_ID # List Records designate record-list $DOMAIN_ID # Fetch the record - should be gone designate record-get $DOMAIN_ID $CNAME_RECORD_ID || echo "good - record was removed" # verify not in DNS anymore ensure_record_absent $CNAME_RECORD_NAME CNAME $DOMAIN_NAME # Testing Domains Delete # ====================== # Delete the domain designate domain-delete $DOMAIN_ID # Fetch the domain - should be gone designate domain-get $DOMAIN_ID || echo "good - domain was removed" set +o xtrace echo "*********************************************************************" echo "SUCCESS: End DevStack Exercise: $0" echo "*********************************************************************" designate-2.0.0/devstack/settings0000664000567000056710000000514512701406241020206 0ustar jenkinsjenkins00000000000000# Default options DESIGNATE_BACKEND_DRIVER=${DESIGNATE_BACKEND_DRIVER:=powerdns} DESIGNATE_POOL_MANAGER_CACHE_DRIVER=${DESIGNATE_POOL_MANAGER_CACHE_DRIVER:-memcache} DESIGNATE_POOL_ID=${DESIGNATE_POOL_ID:-794ccc2c-d751-44fe-b57f-8894c9f5c842} DESIGNATE_DEFAULT_NS_RECORD=${DESIGNATE_DEFAULT_NS_RECORD:-ns1.devstack.org.} DESIGNATE_NOTIFICATION_DRIVER=${DESIGNATE_NOTIFICATION_DRIVER:-} DESIGNATE_NOTIFICATION_TOPICS=${DESIGNATE_NOTIFICATION_TOPICS:-notifications} DESIGNATE_PERIODIC_RECOVERY_INTERVAL=${DESIGNATE_PERIODIC_RECOVERY_INTERVAL:-120} DESIGNATE_PERIODIC_SYNC_INTERVAL=${DESIGNATE_PERIODIC_SYNC_INTERVAL:-1800} DESIGNATE_COORDINATION_URL=${DESIGNATE_COORDINATION_URL:-} # Default extensions DESIGNATE_ENABLED_EXTENSIONS_V1=${DESIGNATE_ENABLED_EXTENSIONS_V1:-"quotas"} DESIGNATE_ENABLED_EXTENSIONS_V2=${DESIGNATE_ENABLED_EXTENSIONS_V2:-""} DESIGNATE_ENABLED_EXTENSIONS_ADMIN=${DESIGNATE_ENABLED_EXTENSIONS_ADMIN:-"quotas"} # Default IP/port settings DESIGNATE_SERVICE_PROTOCOL=${DESIGNATE_SERVICE_PROTOCOL:-$SERVICE_PROTOCOL} DESIGNATE_SERVICE_HOST=${DESIGNATE_SERVICE_HOST:-$SERVICE_HOST} DESIGNATE_SERVICE_PORT=${DESIGNATE_SERVICE_PORT:-9001} DESIGNATE_SERVICE_PORT_INT=${DESIGNATE_SERVICE_PORT_INT:-19001} DESIGNATE_SERVICE_PORT_DNS=${DESIGNATE_SERVICE_PORT_DNS:-53} DESIGNATE_SERVICE_PORT_MDNS=${DESIGNATE_SERVICE_PORT_MDNS:-5354} # Default directories DESIGNATE_BIN_DIR=$(get_python_exec_prefix) DESIGNATE_DIR=$DEST/designate DESIGNATEDASHBOARD_DIR=$DEST/designate-dashboard DESIGNATE_CONF_DIR=/etc/designate DESIGNATE_STATE_PATH=${DESIGNATE_STATE_PATH:=$DATA_DIR/designate} DESIGNATE_CONF=$DESIGNATE_CONF_DIR/designate.conf DESIGNATE_LOG_DIR=/var/log/designate DESIGNATE_AUTH_CACHE_DIR=${DESIGNATE_AUTH_CACHE_DIR:-/var/cache/designate} DESIGNATE_ROOTWRAP_CONF=$DESIGNATE_CONF_DIR/rootwrap.conf DESIGNATE_APIPASTE_CONF=$DESIGNATE_CONF_DIR/api-paste.ini DESIGNATE_PLUGINS=$DESIGNATE_DIR/devstack/designate_plugins # Default repositories DESIGNATE_REPO=${DESIGNATE_REPO:-${GIT_BASE}/openstack/designate.git} DESIGNATE_BRANCH=${DESIGNATE_BRANCH:-master} DESIGNATEDASHBOARD_REPO=${DESIGNATEDASHBOARD_REPO:-${GIT_BASE}/openstack/designate-dashboard.git} DESIGNATEDASHBOARD_BRANCH=${DESIGNATEDASHBOARD_BRANCH:-master} GITDIR["python-designateclient"]=$DEST/python-designateclient # Tell Tempest this project is present TEMPEST_SERVICES+=,designate # Turn on all Designate services by default enable_service designate enable_service designate-central enable_service designate-api enable_service designate-pool-manager enable_service designate-zone-manager enable_service designate-mdns enable_service designate-agent enable_service designate-sink designate-2.0.0/devstack/plugin.sh0000775000567000056710000003224712701406243020265 0ustar jenkinsjenkins00000000000000# Install and start **Designate** service in Devstack # Save trace setting XTRACE=$(set +o | grep xtrace) set +o xtrace # Get backend configuration # ---------------------------- if is_service_enabled designate && [[ -r $DESIGNATE_PLUGINS/backend-$DESIGNATE_BACKEND_DRIVER ]]; then # Load plugin source $DESIGNATE_PLUGINS/backend-$DESIGNATE_BACKEND_DRIVER fi # Helper Functions # ---------------- function setup_colorized_logging_designate { local conf_file=$1 local conf_section=$2 local project_var=${3:-"project_name"} local user_var=${4:-"user_name"} setup_colorized_logging $conf_file $conf_section $project_var $user_var # Override the logging_context_format_string value chosen by # setup_colorized_logging. iniset $conf_file $conf_section logging_context_format_string "%(asctime)s.%(msecs)03d %(color)s%(levelname)s %(name)s [%(request_id)s %(user_identity)s%(color)s] %(instance)s%(color)s%(message)s" } # DevStack Plugin # --------------- # cleanup_designate - Remove residual data files, anything left over from previous # runs that a clean run would need to clean up function cleanup_designate { sudo rm -rf $DESIGNATE_STATE_PATH $DESIGNATE_AUTH_CACHE_DIR cleanup_designate_backend } # configure_designate - Set config files, create data dirs, etc function configure_designate { [ ! -d $DESIGNATE_CONF_DIR ] && sudo mkdir -m 755 -p $DESIGNATE_CONF_DIR sudo chown $STACK_USER $DESIGNATE_CONF_DIR [ ! -d $DESIGNATE_LOG_DIR ] && sudo mkdir -m 755 -p $DESIGNATE_LOG_DIR sudo chown $STACK_USER $DESIGNATE_LOG_DIR # (Re)create ``designate.conf`` rm -f $DESIGNATE_CONF # General Configuration iniset_rpc_backend designate $DESIGNATE_CONF DEFAULT iniset $DESIGNATE_CONF DEFAULT rpc_response_timeout 5 iniset $DESIGNATE_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL iniset $DESIGNATE_CONF DEFAULT verbose True iniset $DESIGNATE_CONF DEFAULT state_path $DESIGNATE_STATE_PATH iniset $DESIGNATE_CONF DEFAULT root-helper sudo designate-rootwrap $DESIGNATE_ROOTWRAP_CONF iniset $DESIGNATE_CONF storage:sqlalchemy connection `database_connection_url designate` # Coordination Configuration if [[ -n "$DESIGNATE_COORDINATION_URL" ]]; then iniset $DESIGNATE_CONF coordination backend_url $DESIGNATE_COORDINATION_URL fi # Install the policy file for the API server cp $DESIGNATE_DIR/etc/designate/policy.json $DESIGNATE_CONF_DIR/policy.json iniset $DESIGNATE_CONF DEFAULT policy_file $DESIGNATE_CONF_DIR/policy.json # Pool Manager Configuration iniset $DESIGNATE_CONF service:pool_manager pool_id $DESIGNATE_POOL_ID iniset $DESIGNATE_CONF service:pool_manager cache_driver $DESIGNATE_POOL_MANAGER_CACHE_DRIVER iniset $DESIGNATE_CONF service:pool_manager periodic_recovery_interval $DESIGNATE_PERIODIC_RECOVERY_INTERVAL iniset $DESIGNATE_CONF service:pool_manager periodic_sync_interval $DESIGNATE_PERIODIC_SYNC_INTERVAL # Pool Manager Cache if [ "$DESIGNATE_POOL_MANAGER_CACHE_DRIVER" == "sqlalchemy" ]; then iniset $DESIGNATE_CONF pool_manager_cache:sqlalchemy connection `database_connection_url designate_pool_manager` fi # API Configuration sudo cp $DESIGNATE_DIR/etc/designate/api-paste.ini $DESIGNATE_APIPASTE_CONF iniset $DESIGNATE_CONF service:api enabled_extensions_v1 $DESIGNATE_ENABLED_EXTENSIONS_V1 iniset $DESIGNATE_CONF service:api enabled_extensions_v2 $DESIGNATE_ENABLED_EXTENSIONS_V2 iniset $DESIGNATE_CONF service:api enabled_extensions_admin $DESIGNATE_ENABLED_EXTENSIONS_ADMIN iniset $DESIGNATE_CONF service:api api_host $DESIGNATE_SERVICE_HOST iniset $DESIGNATE_CONF service:api api_base_uri $DESIGNATE_SERVICE_PROTOCOL://$DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT/ iniset $DESIGNATE_CONF service:api enable_api_v1 True iniset $DESIGNATE_CONF service:api enable_api_v2 True iniset $DESIGNATE_CONF service:api enable_api_admin True # mDNS Configuration iniset $DESIGNATE_CONF service:mdns host $DESIGNATE_SERVICE_HOST iniset $DESIGNATE_CONF service:mdns port $DESIGNATE_SERVICE_PORT_MDNS # Set up Notifications/Ceilometer Integration iniset $DESIGNATE_CONF DEFAULT notification_driver "$DESIGNATE_NOTIFICATION_DRIVER" iniset $DESIGNATE_CONF DEFAULT notification_topics "$DESIGNATE_NOTIFICATION_TOPICS" # Root Wrap sudo cp $DESIGNATE_DIR/etc/designate/rootwrap.conf.sample $DESIGNATE_ROOTWRAP_CONF iniset $DESIGNATE_ROOTWRAP_CONF DEFAULT filters_path $DESIGNATE_DIR/etc/designate/rootwrap.d root-helper # Oslo Concurrency iniset $DESIGNATE_CONF oslo_concurrency lock_path "$DESIGNATE_STATE_PATH" # Set up the rootwrap sudoers for designate local rootwrap_sudoer_cmd="$DESIGNATE_BIN_DIR/designate-rootwrap $DESIGNATE_ROOTWRAP_CONF *" local tempfile=`mktemp` echo "$STACK_USER ALL=(root) NOPASSWD: $rootwrap_sudoer_cmd" >$tempfile chmod 0440 $tempfile sudo chown root:root $tempfile sudo mv $tempfile /etc/sudoers.d/designate-rootwrap # TLS Proxy Configuration if is_service_enabled tls-proxy; then # Set the service port for a proxy to take the original iniset $DESIGNATE_CONF service:api api_port $DESIGNATE_SERVICE_PORT_INT else iniset $DESIGNATE_CONF service:api api_port $DESIGNATE_SERVICE_PORT fi # Setup the Keystone Integration if is_service_enabled key; then iniset $DESIGNATE_CONF service:api auth_strategy keystone configure_auth_token_middleware $DESIGNATE_CONF designate $DESIGNATE_AUTH_CACHE_DIR fi # Logging Configuration if [ "$SYSLOG" != "False" ]; then iniset $DESIGNATE_CONF DEFAULT use_syslog True fi # Format logging if [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ]; then setup_colorized_logging_designate $DESIGNATE_CONF DEFAULT "tenant" "user" fi # Backend Plugin Configuation configure_designate_backend } function configure_designatedashboard { # Compile message catalogs if [ -d ${DESIGNATEDASHBOARD_DIR}/designatedashboard/locale ]; then (cd ${DESIGNATEDASHBOARD_DIR}/designatedashboard; DJANGO_SETTINGS_MODULE=openstack_dashboard.settings ../manage.py compilemessages) fi } # Configure the needed tempest options function configure_designate_tempest() { if is_service_enabled tempest; then nameservers=$DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT_DNS case $DESIGNATE_BACKEND_DRIVER in bind9|powerdns) nameservers="$DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT_DNS" ;; akamai) nameservers="$DESIGNATE_AKAMAI_NAMESERVERS" ;; dynect) nameservers="$DESIGNATE_DYNECT_NAMESERVERS" ;; esac if [ ! -z "$DESIGNATE_NAMESERVERS" ]; then nameservers=$DESIGNATE_NAMESERVERS fi iniset $TEMPEST_CONFIG designate nameservers $nameservers fi } # create_designate_accounts - Set up common required designate accounts # Tenant User Roles # ------------------------------------------------------------------ # service designate admin # if enabled function create_designate_accounts { if is_service_enabled designate-api; then create_service_user "designate" if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then get_or_create_service "designate" "dns" "Designate DNS Service" get_or_create_endpoint "dns" \ "$REGION_NAME" \ "$DESIGNATE_SERVICE_PROTOCOL://$DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT/" \ "$DESIGNATE_SERVICE_PROTOCOL://$DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT/" \ "$DESIGNATE_SERVICE_PROTOCOL://$DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT/" fi fi } # create_designate_pool_configuration - Create Pool Configuration function create_designate_pool_configuration { # Sync Pools Config designate-manage pool update --file $DESIGNATE_CONF_DIR/pools.yaml # Allow Backends to do backend specific tasks if function_exists create_designate_pool_configuration_backend; then create_designate_pool_configuration_backend fi } # init_designate - Initialize etc. function init_designate { # Create cache dir sudo mkdir -p $DESIGNATE_AUTH_CACHE_DIR sudo chown $STACK_USER $DESIGNATE_AUTH_CACHE_DIR rm -f $DESIGNATE_AUTH_CACHE_DIR/* # Some Designate Backends require mdns be bound to port 53, make that # doable. sudo setcap 'cap_net_bind_service=+ep' $(readlink -f /usr/bin/python) # (Re)create designate database recreate_database designate utf8 # Init and migrate designate database designate-manage database sync if [ "$DESIGNATE_POOL_MANAGER_CACHE_DRIVER" == "sqlalchemy" ]; then # (Re)create designate_pool_manager cache recreate_database designate_pool_manager utf8 # Init and migrate designate pool-manager-cache designate-manage pool-manager-cache sync fi init_designate_backend } # install_designate - Collect source and prepare function install_designate { install_package libcap2-bin if is_fedora; then # This package provides `dig` install_package bind-utils fi git_clone $DESIGNATE_REPO $DESIGNATE_DIR $DESIGNATE_BRANCH setup_develop $DESIGNATE_DIR install_designate_backend } # install_designateclient - Collect source and prepare function install_designateclient { if use_library_from_git "python-designateclient"; then git_clone_by_name "python-designateclient" setup_dev_lib "python-designateclient" else pip_install_gr "python-designateclient" fi } # install_designatedashboard - Collect source and prepare function install_designatedashboard { git_clone $DESIGNATEDASHBOARD_REPO $DESIGNATEDASHBOARD_DIR $DESIGNATEDASHBOARD_BRANCH setup_develop $DESIGNATEDASHBOARD_DIR ln -fs $DESIGNATEDASHBOARD_DIR/designatedashboard/enabled/_1710_project_dns_panel_group.py $HORIZON_DIR/openstack_dashboard/local/enabled/_1710_project_dns_panel_group.py ln -fs $DESIGNATEDASHBOARD_DIR/designatedashboard/enabled/_1720_project_dns_panel.py $HORIZON_DIR/openstack_dashboard/local/enabled/_1720_project_dns_panel.py } # start_designate - Start running processes, including screen function start_designate { start_designate_backend run_process designate-central "$DESIGNATE_BIN_DIR/designate-central --config-file $DESIGNATE_CONF" run_process designate-api "$DESIGNATE_BIN_DIR/designate-api --config-file $DESIGNATE_CONF" run_process designate-pool-manager "$DESIGNATE_BIN_DIR/designate-pool-manager --config-file $DESIGNATE_CONF" run_process designate-zone-manager "$DESIGNATE_BIN_DIR/designate-zone-manager --config-file $DESIGNATE_CONF" run_process designate-mdns "$DESIGNATE_BIN_DIR/designate-mdns --config-file $DESIGNATE_CONF" run_process designate-agent "$DESIGNATE_BIN_DIR/designate-agent --config-file $DESIGNATE_CONF" run_process designate-sink "$DESIGNATE_BIN_DIR/designate-sink --config-file $DESIGNATE_CONF" # Start proxies if enabled if is_service_enabled designate-api && is_service_enabled tls-proxy; then start_tls_proxy '*' $DESIGNATE_SERVICE_PORT $DESIGNATE_SERVICE_HOST $DESIGNATE_SERVICE_PORT_INT & fi if ! timeout $SERVICE_TIMEOUT sh -c "while ! wget --no-proxy -q -O- $DESIGNATE_SERVICE_PROTOCOL://$DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT; do sleep 1; done"; then die $LINENO "Designate did not start" fi } # stop_designate - Stop running processes function stop_designate { # Kill the designate screen windows stop_process designate-central stop_process designate-api stop_process designate-pool-manager stop_process designate-zone-manager stop_process designate-mdns stop_process designate-agent stop_process designate-sink stop_designate_backend } # This is the main for plugin.sh if is_service_enabled designate; then if [[ "$1" == "stack" && "$2" == "install" ]]; then echo_summary "Installing Designate client" install_designateclient echo_summary "Installing Designate" install_designate if is_service_enabled horizon; then echo_summary "Installing Designate dashboard" install_designatedashboard fi elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then echo_summary "Configuring Designate" configure_designate configure_designatedashboard if is_service_enabled key; then echo_summary "Creating Designate Keystone accounts" create_designate_accounts fi elif [[ "$1" == "stack" && "$2" == "extra" ]]; then echo_summary "Initializing Designate" init_designate echo_summary "Configuring Tempest options for Designate" configure_designate_tempest echo_summary "Starting Designate" start_designate echo_summary "Creating Pool Configuration" create_designate_pool_configuration fi if [[ "$1" == "unstack" ]]; then stop_designate fi if [[ "$1" == "clean" ]]; then echo_summary "Cleaning Designate" cleanup_designate fi fi # Restore xtrace $XTRACE designate-2.0.0/devstack/designate_plugins/0000775000567000056710000000000012701406373022130 5ustar jenkinsjenkins00000000000000designate-2.0.0/devstack/designate_plugins/backend-dynect0000664000567000056710000001071712701406241024726 0ustar jenkinsjenkins00000000000000# Configure the dynect backend # Requirements: # An active DynECT account / contract will be requied to use this DevStack # plugin. # Enable with: # DESIGNATE_BACKEND_DRIVER=dynect # Dependencies: # ``functions`` file # ``designate`` configuration # install_designate_backend - install any external requirements # configure_designate_backend - make configuration changes, including those to other services # init_designate_backend - initialize databases, etc. # start_designate_backend - start any external services # stop_designate_backend - stop any external services # cleanup_designate_backend - remove transient data and cache # Save trace setting DP_DYNECT_XTRACE=$(set +o | grep xtrace) set +o xtrace # Defaults # -------- DESIGNATE_DYNECT_CUSTOMER=${DESIGNATE_DYNECT_CUSTOMER:-customer} DESIGNATE_DYNECT_USERNAME=${DESIGNATE_DYNECT_USERNAME:-username} DESIGNATE_DYNECT_PASSWORD=${DESIGNATE_DYNECT_PASSWORD:-password} DESIGNATE_DYNECT_CONTACT_NICKNAME=${DESIGNATE_DYNECT_CONTACT_NICKNAME:-} DESIGNATE_DYNECT_JOB_TIMEOUT=${DESIGNATE_DYNECT_JOB_TIMEOUT:-} DESIGNATE_DYNECT_TIMEOUT=${DESIGNATE_DYNECT_TIMEOUT:-} DESIGNATE_DYNECT_MASTERS=${DESIGNATE_DYNECT_MASTERS:-"$DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT_MDNS"} DESIGNATE_DYNECT_NAMESERVERS=${DESIGNATE_DYNECT_NAMESERVERS:-""} DESIGNATE_DYNECT_ALSO_NOTIFIES=${DESIGNATE_DYNECT_ALSO_NOTIFIES:-"204.13.249.65,208.78.68.65"} # Pull in DESIGNATE_3RDPARTY_CREDS user/pass if set if [ -n "$DESIGNATE_3RDPARTY_CREDS" ]; then DESIGNATE_DYNECT_CUSTOMER=`echo $DESIGNATE_3RDPARTY_CREDS | cut -f1 -d:` DESIGNATE_DYNECT_USERNAME=`echo $DESIGNATE_3RDPARTY_CREDS | cut -f2 -d:` DESIGNATE_DYNECT_PASSWORD=`echo $DESIGNATE_3RDPARTY_CREDS | cut -f3- -d:` fi # Sanity Checks # ------------- if [ -z "$DESIGNATE_DYNECT_NAMESERVERS" ]; then die $LINENO "You must configure DESIGNATE_DYNECT_NAMESERVERS" fi if [ "$DESIGNATE_SERVICE_PORT_MDNS" != "53" ]; then die $LINENO "DynECT requires DESIGNATE_SERVICE_PORT_MDNS is set to '53'" fi # Entry Points # ------------ # install_designate_backend - install any external requirements function install_designate_backend { : } # configure_designate_backend - make configuration changes, including those to other services function configure_designate_backend { # Generate Designate pool.yaml file sudo tee $DESIGNATE_CONF_DIR/pools.yaml > /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null < /dev/null </dev/null; then sudo groupadd $BIND_GROUP fi add_user_to_group $STACK_USER $BIND_GROUP if [[ ! -d $BIND_CFG_DIR ]]; then sudo mkdir -p $BIND_CFG_DIR sudo chown $BIND_USER:$BIND_GROUP $BIND_CFG_DIR fi sudo chown -R $BIND_USER:$BIND_GROUP $BIND_CFG_DIR $BIND_VAR_DIR sudo chmod -R g+r $BIND_CFG_DIR sudo chmod -R g+rw $BIND_VAR_DIR # Customize Bind9 apparmor profile if installed if [[ -d /etc/apparmor.d ]]; then sudo tee /etc/apparmor.d/local/usr.sbin.named > /dev/null << EOF $DESIGNATE_STATE_PATH/bind9/** rw, EOF restart_service apparmor || : fi } # configure_designate_backend - make configuration changes, including those to other services function configure_designate_backend { # Generate Designate pool.yaml file sudo tee $DESIGNATE_CONF_DIR/pools.yaml > /dev/null < /dev/null < /dev/null << EOF include "$BIND_CFG_DIR/rndc.key"; options { default-key "rndc-key"; default-server $DESIGNATE_SERVICE_HOST; default-port $DESIGNATE_SERVICE_PORT_RNDC; }; EOF sudo chown $BIND_USER:$BIND_GROUP $BIND_CFG_FILE $BIND_CFG_DIR/rndc.conf sudo chmod g+r $BIND_CFG_FILE $BIND_CFG_DIR/rndc.conf restart_service $BIND_SERVICE_NAME } # init_designate_backend - initialize databases, etc. function init_designate_backend { : } # start_designate_backend - start any external services function start_designate_backend { start_service bind9 } # stop_designate_backend - stop any external services function stop_designate_backend { stop_service bind9 } # cleanup_designate_backend - remove transient data and cache function cleanup_designate_backend { sudo sh -c "rm -rf $BIND_VAR_DIR/*.nzf" sudo sh -c "rm -rf $BIND_VAR_DIR/slave.*" sudo rm -f $BIND_CFG_DIR/rndc.key } # Restore xtrace $DP_BIND9_XTRACE designate-2.0.0/devstack/gate/0000775000567000056710000000000012701406373017344 5ustar jenkinsjenkins00000000000000designate-2.0.0/devstack/gate/gate_hook.sh0000775000567000056710000000143512701406241021640 0ustar jenkinsjenkins00000000000000#!/bin/bash set -ex pushd $BASE/new/devstack DEVSTACK_GATE_DESIGNATE_DRIVER=${DEVSTACK_GATE_DESIGNATE_DRIVER:-powerdns} export KEEP_LOCALRC=1 export ENABLED_SERVICES=designate,designate-api,designate-central,designate-sink,designate-mdns,designate-pool-manager,designate-zone-manager echo "DESIGNATE_SERVICE_PORT_DNS=5322" >> $BASE/new/devstack/localrc echo "DESIGNATE_BACKEND_DRIVER=$DEVSTACK_GATE_DESIGNATE_DRIVER" >> $BASE/new/devstack/localrc echo "DESIGNATE_PERIODIC_RECOVERY_INTERVAL=20" >> $BASE/new/devstack/localrc echo "DESIGNATE_PERIODIC_SYNC_INTERVAL=20" >> $BASE/new/devstack/localrc # Pass through any DESIGNATE_ env vars to the localrc file env | grep -E "^DESIGNATE_" >> $BASE/new/devstack/localrc || : popd # Run DevStack Gate $BASE/new/devstack-gate/devstack-vm-gate.sh designate-2.0.0/devstack/gate/post_test_hook.sh0000775000567000056710000000301212701406243022737 0ustar jenkinsjenkins00000000000000#!/bin/bash set -ex # Run the Designate DevStack exercises $BASE/new/designate/devstack/exercise.sh # Import functions needed for the below workaround source $BASE/new/devstack/functions # Workaround for Tempest architectural changes # See bugs: # 1) https://bugs.launchpad.net/manila/+bug/1531049 # 2) https://bugs.launchpad.net/tempest/+bug/1524717 TEMPEST_CONFIG=$BASE/new/tempest/etc/tempest.conf ADMIN_TENANT_NAME=${ADMIN_TENANT_NAME:-"admin"} ADMIN_PASSWORD=${ADMIN_PASSWORD:-"secretadmin"} sudo chown -R jenkins:stack $BASE/new/tempest sudo chown -R jenkins:stack $BASE/data/tempest iniset $TEMPEST_CONFIG auth admin_username ${ADMIN_USERNAME:-"admin"} iniset $TEMPEST_CONFIG auth admin_password $ADMIN_PASSWORD iniset $TEMPEST_CONFIG auth admin_tenant_name $ADMIN_TENANT_NAME iniset $TEMPEST_CONFIG auth admin_domain_name ${ADMIN_DOMAIN_NAME:-"Default"} iniset $TEMPEST_CONFIG identity username ${TEMPEST_USERNAME:-"demo"} iniset $TEMPEST_CONFIG identity password $ADMIN_PASSWORD iniset $TEMPEST_CONFIG identity tenant_name ${TEMPEST_TENANT_NAME:-"demo"} iniset $TEMPEST_CONFIG identity alt_username ${ALT_USERNAME:-"alt_demo"} iniset $TEMPEST_CONFIG identity alt_password $ADMIN_PASSWORD iniset $TEMPEST_CONFIG identity alt_tenant_name ${ALT_TENANT_NAME:-"alt_demo"} iniset $TEMPEST_CONFIG validation ip_version_for_ssh 4 iniset $TEMPEST_CONFIG validation ssh_timeout $BUILD_TIMEOUT iniset $TEMPEST_CONFIG validation network_for_ssh ${PRIVATE_NETWORK_NAME:-"private"} # Run the Designate Tempest tests sudo ./run_tempest_tests.sh designate-2.0.0/devstack/gate/run_tempest_tests.sh0000775000567000056710000000227612701406243023475 0ustar jenkinsjenkins00000000000000#!/bin/bash -e # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. # How many seconds to wait for the API to be responding before giving up API_RESPONDING_TIMEOUT=20 if ! timeout ${API_RESPONDING_TIMEOUT} sh -c "while ! curl -s http://127.0.0.1:9001/ 2>/dev/null | grep -q 'v1' ; do sleep 1; done"; then echo "The Designate API failed to respond within ${API_RESPONDING_TIMEOUT} seconds" exit 1 fi echo "Successfully contacted the Designate API" # Where Designate and Tempest code lives DESIGNATE_DIR=${DESIGNATE_DIR:-/opt/stack/new/designate} TEMPEST_DIR=${TEMPEST_DIR:-/opt/stack/new/tempest} pushd $DESIGNATE_DIR export TEMPEST_CONFIG=$TEMPEST_DIR/etc/tempest.conf tox -e functional -- --concurrency 4 designate-2.0.0/devstack/README.rst0000664000567000056710000000106312701406241020105 0ustar jenkinsjenkins00000000000000==================== Enabling in Devstack ==================== **WARNING**: the stack.sh script must be run in a disposable VM that is not being created automatically, see the README.md file in the "devstack" repository. See contrib/vagrant to create a vagrant VM. 1. Download DevStack:: git clone https://git.openstack.org/openstack-dev/devstack.git cd devstack 2. Add this repo as an external repository:: > cat local.conf [[local|localrc]] enable_plugin designate https://git.openstack.org/openstack/designate 3. run ``stack.sh`` designate-2.0.0/etc/0000775000567000056710000000000012701406373015373 5ustar jenkinsjenkins00000000000000designate-2.0.0/etc/designate/0000775000567000056710000000000012701406373017336 5ustar jenkinsjenkins00000000000000designate-2.0.0/etc/designate/rootwrap.conf.sample0000664000567000056710000000166512701406241023344 0ustar jenkinsjenkins00000000000000# Configuration for designate-rootwrap # This file should be owned by (and only-writeable by) the root user [DEFAULT] # List of directories to load filter definitions from (separated by ','). # These directories MUST all be only writeable by root ! filters_path=/etc/designate/rootwrap.d,/usr/share/designate/rootwrap # List of directories to search executables in, in case filters do not # explicitely specify a full path (separated by ',') # If not specified, defaults to system PATH environment variable. # These directories MUST all be only writeable by root ! exec_dirs=/sbin,/usr/sbin,/bin,/usr/bin # Enable logging to syslog # Default value is False use_syslog=False # Which syslog facility to use. # Valid values include auth, authpriv, syslog, user0, user1... # Default value is 'syslog' syslog_log_facility=syslog # Which messages to log. # INFO means log all usage # ERROR means only log unsuccessful attempts syslog_log_level=ERROR designate-2.0.0/etc/designate/rootwrap.d/0000775000567000056710000000000012701406373021435 5ustar jenkinsjenkins00000000000000designate-2.0.0/etc/designate/rootwrap.d/bind9.filters0000664000567000056710000000044612701406241024032 0ustar jenkinsjenkins00000000000000# designate-rootwrap command filters for nodes on which designate is # expected to control network # # This file should be owned by (and only-writeable by) the root user # format seems to be # cmd-name: filter-name, raw-command, user, args [Filters] rndc: CommandFilter, /usr/sbin/rndc, root designate-2.0.0/etc/designate/pools.yaml.sample-bind0000664000567000056710000000345312701406241023547 0ustar jenkinsjenkins00000000000000 - name: default-bind # The name is immutable. There will be no option to change the name after # creation and the only way will to change it will be to delete it # (and all zones associated with it) and recreate it. description: Default BIND9 Pool attributes: {} # List out the NS records for zones hosted within this pool ns_records: - hostname: ns1-1.example.org. priority: 1 - hostname: ns1-2.example.org. priority: 2 # List out the nameservers for this pool. These are the actual BIND servers. # We use these to verify changes have propagated to all nameservers. nameservers: - host: 192.0.2.2 port: 53 - host: 192.0.2.3 port: 53 # List out the targets for this pool. For BIND, most often, there will be one # entry for each BIND server. targets: - type: bind description: BIND9 Server 1 # List out the designate-mdns servers from which BIND servers should # request zone transfers (AXFRs) from. masters: - host: 192.0.2.1 port: 5354 # BIND Configuration options options: host: 192.0.2.2 port: 53 rndc_host: 192.0.2.2 rndc_port: 953 rndc_key_file: /etc/designate/rndc.key - type: bind description: BIND9 Server 2 # List out the designate-mdns servers from which BIND servers should # request zone transfers (AXFRs) from. masters: - host: 192.0.2.1 port: 5354 # BIND Configuration options options: host: 192.0.2.3 port: 53 rndc_host: 192.0.2.3 rndc_port: 953 rndc_key_file: /etc/designate/rndc.key # Optional list of additional IP/Port's for which designate-mdns will send # DNS NOTIFY packets to # also_notifies: # - host: 192.0.2.4 # port: 53 designate-2.0.0/etc/designate/policy.json0000664000567000056710000001101112701406241021514 0ustar jenkinsjenkins00000000000000{ "admin": "role:admin or is_admin:True", "primary_zone": "target.zone_type:SECONDARY", "owner": "tenant:%(tenant_id)s", "admin_or_owner": "rule:admin or rule:owner", "target": "tenant:%(target_tenant_id)s", "owner_or_target":"rule:target or rule:owner", "admin_or_owner_or_target":"rule:owner_or_target or rule:admin", "admin_or_target":"rule:admin or rule:target", "zone_primary_or_admin": "('PRIMARY':%(zone_type)s and rule:admin_or_owner) OR ('SECONDARY':%(zone_type)s AND is_admin:True)", "default": "rule:admin_or_owner", "all_tenants": "rule:admin", "edit_managed_records" : "rule:admin", "use_low_ttl": "rule:admin", "get_quotas": "rule:admin_or_owner", "get_quota": "rule:admin_or_owner", "set_quota": "rule:admin", "reset_quotas": "rule:admin", "create_tld": "rule:admin", "find_tlds": "rule:admin", "get_tld": "rule:admin", "update_tld": "rule:admin", "delete_tld": "rule:admin", "create_tsigkey": "rule:admin", "find_tsigkeys": "rule:admin", "get_tsigkey": "rule:admin", "update_tsigkey": "rule:admin", "delete_tsigkey": "rule:admin", "find_tenants": "rule:admin", "get_tenant": "rule:admin", "count_tenants": "rule:admin", "create_zone": "rule:admin_or_owner", "get_zones": "rule:admin_or_owner", "get_zone": "rule:admin_or_owner", "get_zone_servers": "rule:admin_or_owner", "find_zones": "rule:admin_or_owner", "find_zone": "rule:admin_or_owner", "update_zone": "rule:admin_or_owner", "delete_zone": "rule:admin_or_owner", "xfr_zone": "rule:admin_or_owner", "abandon_zone": "rule:admin", "count_zones": "rule:admin_or_owner", "count_zones_pending_notify": "rule:admin_or_owner", "purge_zones": "rule:admin", "touch_zone": "rule:admin_or_owner", "create_recordset": "rule:zone_primary_or_admin", "get_recordsets": "rule:admin_or_owner", "get_recordset": "rule:admin_or_owner", "find_recordsets": "rule:admin_or_owner", "find_recordset": "rule:admin_or_owner", "update_recordset": "rule:zone_primary_or_admin", "delete_recordset": "rule:zone_primary_or_admin", "count_recordset": "rule:admin_or_owner", "create_record": "rule:admin_or_owner", "get_records": "rule:admin_or_owner", "get_record": "rule:admin_or_owner", "find_records": "rule:admin_or_owner", "find_record": "rule:admin_or_owner", "update_record": "rule:admin_or_owner", "delete_record": "rule:admin_or_owner", "count_records": "rule:admin_or_owner", "use_sudo": "rule:admin", "create_blacklist": "rule:admin", "find_blacklist": "rule:admin", "find_blacklists": "rule:admin", "get_blacklist": "rule:admin", "update_blacklist": "rule:admin", "delete_blacklist": "rule:admin", "use_blacklisted_zone": "rule:admin", "create_pool": "rule:admin", "find_pools": "rule:admin", "find_pool": "rule:admin", "get_pool": "rule:admin", "update_pool": "rule:admin", "delete_pool": "rule:admin", "zone_create_forced_pool": "rule:admin", "diagnostics_ping": "rule:admin", "diagnostics_sync_zones": "rule:admin", "diagnostics_sync_zone": "rule:admin", "diagnostics_sync_record": "rule:admin", "create_zone_transfer_request": "rule:admin_or_owner", "get_zone_transfer_request": "rule:admin_or_owner or tenant:%(target_tenant_id)s or None:%(target_tenant_id)s", "get_zone_transfer_request_detailed": "rule:admin_or_owner", "find_zone_transfer_requests": "@", "find_zone_transfer_request": "@", "update_zone_transfer_request": "rule:admin_or_owner", "delete_zone_transfer_request": "rule:admin_or_owner", "create_zone_transfer_accept": "rule:admin_or_owner or tenant:%(target_tenant_id)s or None:%(target_tenant_id)s", "get_zone_transfer_accept": "rule:admin_or_owner", "find_zone_transfer_accepts": "rule:admin", "find_zone_transfer_accept": "rule:admin", "update_zone_transfer_accept": "rule:admin", "delete_zone_transfer_accept": "rule:admin", "create_zone_import": "rule:admin_or_owner", "find_zone_imports": "rule:admin_or_owner", "get_zone_import": "rule:admin_or_owner", "update_zone_import": "rule:admin_or_owner", "delete_zone_import": "rule:admin_or_owner", "zone_export": "rule:admin_or_owner", "create_zone_export": "rule:admin_or_owner", "find_zone_exports": "rule:admin_or_owner", "get_zone_export": "rule:admin_or_owner", "update_zone_export": "rule:admin_or_owner", "delete_zone_export": "rule:admin_or_owner" } designate-2.0.0/etc/designate/api-paste.ini0000664000567000056710000000561112701406241021717 0ustar jenkinsjenkins00000000000000[composite:osapi_dns] use = egg:Paste#urlmap /: osapi_dns_versions /v1: osapi_dns_v1 /v2: osapi_dns_v2 /admin: osapi_dns_admin [composite:osapi_dns_versions] use = call:designate.api.middleware:auth_pipeline_factory noauth = http_proxy_to_wsgi cors maintenance faultwrapper osapi_dns_app_versions keystone = http_proxy_to_wsgi cors maintenance faultwrapper osapi_dns_app_versions [app:osapi_dns_app_versions] paste.app_factory = designate.api.versions:factory [composite:osapi_dns_v1] use = call:designate.api.middleware:auth_pipeline_factory noauth = http_proxy_to_wsgi cors request_id noauthcontext maintenance validation_API_v1 faultwrapper_v1 normalizeuri osapi_dns_app_v1 keystone = http_proxy_to_wsgi cors request_id authtoken keystonecontext maintenance validation_API_v1 faultwrapper_v1 normalizeuri osapi_dns_app_v1 [app:osapi_dns_app_v1] paste.app_factory = designate.api.v1:factory [composite:osapi_dns_v2] use = call:designate.api.middleware:auth_pipeline_factory noauth = http_proxy_to_wsgi cors request_id faultwrapper validation_API_v2 noauthcontext maintenance normalizeuri osapi_dns_app_v2 keystone = http_proxy_to_wsgi cors request_id faultwrapper validation_API_v2 authtoken keystonecontext maintenance normalizeuri osapi_dns_app_v2 [app:osapi_dns_app_v2] paste.app_factory = designate.api.v2:factory [composite:osapi_dns_admin] use = call:designate.api.middleware:auth_pipeline_factory noauth = http_proxy_to_wsgi cors request_id faultwrapper noauthcontext maintenance normalizeuri osapi_dns_app_admin keystone = http_proxy_to_wsgi cors request_id faultwrapper authtoken keystonecontext maintenance normalizeuri osapi_dns_app_admin [app:osapi_dns_app_admin] paste.app_factory = designate.api.admin:factory [filter:cors] paste.filter_factory = oslo_middleware.cors:filter_factory oslo_config_project = designate [filter:request_id] paste.filter_factory = oslo_middleware:RequestId.factory [filter:http_proxy_to_wsgi] paste.filter_factory = oslo_middleware:HTTPProxyToWSGI.factory [filter:noauthcontext] paste.filter_factory = designate.api.middleware:NoAuthContextMiddleware.factory [filter:authtoken] paste.filter_factory = keystonemiddleware.auth_token:filter_factory [filter:keystonecontext] paste.filter_factory = designate.api.middleware:KeystoneContextMiddleware.factory [filter:maintenance] paste.filter_factory = designate.api.middleware:MaintenanceMiddleware.factory [filter:normalizeuri] paste.filter_factory = designate.api.middleware:NormalizeURIMiddleware.factory [filter:faultwrapper] paste.filter_factory = designate.api.middleware:FaultWrapperMiddleware.factory [filter:faultwrapper_v1] paste.filter_factory = designate.api.middleware:FaultWrapperMiddlewareV1.factory [filter:validation_API_v1] paste.filter_factory = designate.api.middleware:APIv1ValidationErrorMiddleware.factory [filter:validation_API_v2] paste.filter_factory = designate.api.middleware:APIv2ValidationErrorMiddleware.factory designate-2.0.0/etc/designate/pools.yaml.sample0000664000567000056710000000327012701406241022632 0ustar jenkinsjenkins00000000000000--- - name: default # The name is immutable. There will be no option to change the name after # creation and the only way will to change it will be to delete it # (and all zones associated with it) and recreate it. description: Default PowerDNS Pool # Attributes are Key:Value pairs that describe the pool. for example the level # of service (i.e. service_tier:GOLD), capabilities (i.e. anycast: true) or # other metadata. Users can use this infomation to point their zones to the # correct pool attributes: {} # List out the NS records for zones hosted within this pool ns_records: - hostname: ns1-1.example.org. priority: 1 - hostname: ns1-2.example.org. priority: 2 # List out the nameservers for this pool. These are the actual PowerDNS # servers. We use these to verify changes have propagated to all nameservers. nameservers: - host: 192.0.2.2 port: 53 - host: 192.0.2.3 port: 53 # List out the targets for this pool. For PowerDNS, this is the database # (or databases, if you deploy a separate DB for each PowerDNS server) targets: - type: powerdns description: PowerDNS Database Cluster # List out the designate-mdns servers from which PowerDNS servers should # request zone transfers (AXFRs) from. masters: - host: 192.0.2.1 port: 5354 # PowerDNS Configuration options options: host: 192.0.2.1 port: 53 connection: 'mysql+pymysql://designate:password@127.0.0.1/designate_pdns?charset=utf8' # Optional list of additional IP/Port's for which designate-mdns will send # DNS NOTIFY packets to also_notifies: - host: 192.0.2.4 port: 53 designate-2.0.0/etc/designate/pools.yaml.sample-multiple-pools0000664000567000056710000000636512701406241025625 0ustar jenkinsjenkins00000000000000--- - name: pool-1 # The name is immutable. There will be no option to change the name after # creation and the only way will to change it will be to delete it # (and all zones associated with it) and recreate it. description: Default PowerDNS Pool attributes: internal: true # List out the NS records for zones hosted within this pool ns_records: - hostname: ns1-1.example.org. priority: 1 - hostname: ns1-2.example.org. priority: 2 # List out the nameservers for this pool. These are the actual PowerDNS # servers. We use these to verify changes have propagated to all nameservers. nameservers: - host: 192.0.2.2 port: 53 - host: 192.0.2.3 port: 53 # List out the targets for this pool. For PowerDNS, this is the database # (or databases, if you deploy a separate DB for each PowerDNS server) targets: - type: powerdns description: PowerDNS Database Cluster # List out the designate-mdns servers from which PowerDNS servers should # request zone transfers (AXFRs) from. masters: - host: 192.0.2.1 port: 5354 # PowerDNS Configuration options options: host: 192.0.2.2 port: 53 connection: 'mysql+pymysql://designate:password@127.0.0.1/designate_pdns?charset=utf8' # Optional list of additional IP/Port's for which designate-mdns will send # DNS NOTIFY packets to also_notifies: - host: 192.0.2.4 port: 53 - name: pool-2 # The name is immutable. There will be no option to change the name after # creation and the only way will to change it will be to delete it # (and all zones associated with it) and recreate it. description: Default PowerDNS Pool attributes: external: true # List out the NS records for zones hosted within this pool ns_records: - hostname: ns1-1.example.org. priority: 1 - hostname: ns1-2.example.org. priority: 2 # List out the nameservers for this pool. These are the actual BIND servers. # We use these to verify changes have propagated to all nameservers. nameservers: - host: 192.0.2.2 port: 53 - host: 192.0.2.3 port: 53 # List out the targets for this pool. For BIND, most often, there will be one # entry for each BIND server. targets: - type: bind description: BIND9 Server 1 # List out the designate-mdns servers from which BIND servers should # request zone transfers (AXFRs) from. masters: - host: 192.0.2.1 port: 5354 # BIND Configuration options options: host: 192.0.2.2 port: 53 rndc_host: 192.0.2.2 rndc_port: 953 rndc_key_file: /etc/designate/rndc.key - type: bind description: BIND9 Server 2 # List out the designate-mdns servers from which BIND servers should # request zone transfers (AXFRs) from. masters: - host: 192.0.2.1 port: 5354 # BIND Configuration options options: host: 192.0.2.3 port: 53 rndc_host: 192.0.2.3 rndc_port: 953 rndc_key_file: /etc/designate/rndc.key # Optional list of additional IP/Port's for which designate-mdns will send # DNS NOTIFY packets to also_notifies: - host: 192.0.2.4 port: designate-2.0.0/etc/designate/designate.conf.sample0000664000567000056710000003352212701406243023431 0ustar jenkinsjenkins00000000000000[DEFAULT] # Where an option is commented out, but filled in this shows the default # value of that option ######################## ## General Configuration ######################## # Show more verbose log output (sets INFO log level output) verbose = True # Show debugging output in logs (sets DEBUG log level output) debug = False # Top-level directory for maintaining designate's state #state_path = /var/lib/designate # Log Configuration #log_config = None # Log directory #logdir = /var/log/designate # Driver used for issuing notifications #notification_driver = messaging # Notification Topics #notification_topics = notifications # Use "sudo designate-rootwrap /etc/designate/rootwrap.conf" to use the real # root filter facility. # Change to "sudo" to skip the filtering and just run the comand directly #root_helper = sudo designate-rootwrap /etc/designate/rootwrap.conf # Which networking API to use, Defaults to neutron #network_api = neutron # Supported record types #supported_record_type = A, AAAA, CNAME, MX, SRV, TXT, SPF, NS, PTR, SSHFP, SOA #----------------------- # RabbitMQ Config #----------------------- [oslo_messaging_rabbit] #rabbit_userid = guest #rabbit_password = guest #rabbit_virtual_host = / #rabbit_use_ssl = False #rabbit_hosts = 127.0.0.1:5672 ######################## ## Service Configuration ######################## #----------------------- # Central Service #----------------------- [service:central] # Number of central worker processes to spawn #workers = None # Number of central greenthreads to spawn #threads = 1000 # Maximum domain name length #max_domain_name_len = 255 # Maximum recordset name length #max_recordset_name_len = 255 # Minimum TTL #min_ttl = None # The name of the default pool #default_pool_id = '794ccc2c-d751-44fe-b57f-8894c9f5c842' ## Managed resources settings # Email to use for managed resources like domains created by the FloatingIP API #managed_resource_email = hostmaster@example.com. # Tenant ID to own all managed resources - like auto-created records etc. #managed_resource_tenant_id = 123456 # What filters to use. They are applied in order listed in the option, from # left to right #scheduler_filters = default_pool #----------------------- # API Service #----------------------- [service:api] # Number of api worker processes to spawn #workers = None # Number of api greenthreads to spawn #threads = 1000 # Enable host request headers #enable_host_header = False # The base uri used in responses #api_base_uri = 'http://127.0.0.1:9001/' # Address to bind the API server #api_host = 0.0.0.0 # Port the bind the API server to #api_port = 9001 # Maximum line size of message headers to be accepted. max_header_line may # need to be increased when using large tokens (typically those generated by # the Keystone v3 API with big service catalogs). #max_header_line = 16384 # Authentication strategy to use - can be either "noauth" or "keystone" #auth_strategy = keystone # Enable Version 1 API (deprecated) #enable_api_v1 = True # Enabled API Version 1 extensions # Can be one or more of : diagnostics, quotas, reports, sync, touch #enabled_extensions_v1 = # Enable Version 2 API #enable_api_v2 = True # Enabled API Version 2 extensions #enabled_extensions_v2 = # Default per-page limit for the V2 API, a value of None means show all results # by default #default_limit_v2 = 20 # Max page size in the V2 API #max_limit_v2 = 1000 # Enable Admin API (experimental) #enable_api_admin = False # Enabled Admin API extensions # Can be one or more of : reports, quotas, counts, tenants, target_sync # zone export is in zones extension #enabled_extensions_admin = # Default per-page limit for the Admin API, a value of None means show all results # by default #default_limit_admin = 20 # Max page size in the Admin API #max_limit_admin = 1000 # Show the pecan HTML based debug interface (v2 only) # This is only useful for development, and WILL break python-designateclient # if an error occurs #pecan_debug = False #----------------------- # Keystone Middleware #----------------------- [keystone_authtoken] #auth_host = 127.0.0.1 #auth_port = 35357 #auth_protocol = http #admin_tenant_name = service #admin_user = designate #admin_password = designate #memcached_servers = localhost:11211 #----------------------- # CORS Middleware #----------------------- [cors] # Indicate whether this resource may be shared with the domain received in the # requests "origin" header. (list value) #allowed_origin = # Indicate that the actual request can include user credentials (boolean value) #allow_credentials = true # Indicate which headers are safe to expose to the API. Defaults to HTTP Simple # Headers. (list value) #expose_headers = X-OpenStack-Request-ID,Host # Maximum cache age of CORS preflight requests. (integer value) #max_age = 3600 # Indicate which methods can be used during the actual request. (list value) #allow_methods = GET,PUT,POST,DELETE,PATCH,HEAD # Indicate which header field names may be used during the actual request. # (list value) #allow_headers = X-Auth-Token,X-Auth-Sudo-Tenant-ID,X-Auth-Sudo-Project-ID,X-Auth-All-Projects,X-Designate-Edit-Managed-Records [cors.subdomain] # Indicate whether this resource may be shared with the domain received in the # requests "origin" header. (list value) #allowed_origin = # Indicate that the actual request can include user credentials (boolean value) #allow_credentials = true # Indicate which headers are safe to expose to the API. Defaults to HTTP Simple # Headers. (list value) #expose_headers = X-OpenStack-Request-ID,Host # Maximum cache age of CORS preflight requests. (integer value) #max_age = 3600 # Indicate which methods can be used during the actual request. (list value) #allow_methods = GET,PUT,POST,DELETE,PATCH,HEAD # Indicate which header field names may be used during the actual request. # (list value) #allow_headers = X-Auth-Token,X-Auth-Sudo-Tenant-ID,X-Auth-Sudo-Project-ID,X-Auth-All-Projects,X-Designate-Edit-Managed-Records #----------------------- # Sink Service #----------------------- [service:sink] # List of notification handlers to enable, configuration of these needs to # correspond to a [handler:my_driver] section below or else in the config # Can be one or more of : nova_fixed, neutron_floatingip #enabled_notification_handlers = #----------------------- # mDNS Service #----------------------- [service:mdns] # Number of mdns worker processes to spawn #workers = None # Number of mdns greenthreads to spawn #threads = 1000 # mDNS Bind Host #host = 0.0.0.0 # mDNS Port Number #port = 5354 # mDNS TCP Backlog #tcp_backlog = 100 # mDNS TCP Receive Timeout #tcp_recv_timeout = 0.5 # Enforce all incoming queries (including AXFR) are TSIG signed #query_enforce_tsig = False # Send all traffic over TCP #all_tcp = False # Maximum message size to emit #max_message_size = 65535 #----------------------- # Agent Service #----------------------- [service:agent] #workers = None #host = 0.0.0.0 #port = 5358 #tcp_backlog = 100 #allow_notify = 127.0.0.1 #masters = 127.0.0.1:5354 #backend_driver = fake #transfer_source = None #notify_delay = 0 #----------------------- # Zone Manager Service #----------------------- [service:zone_manager] # Number of Zone Manager worker processes to spawn #workers = None # Number of Zone Manager greenthreads to spawn #threads = 1000 # List of Zone Manager tasks to enable, a value of None will enable all tasks. # Can be one or more of: periodic_exists #enabled_tasks = None # Whether to allow synchronous zone exports #export_synchronous = True #------------------------ # Deleted domains purging #------------------------ [zone_manager_task:domain_purge] # How frequently to purge deleted domains, in seconds #interval = 3600 # 1h # How many records to be deleted on each run #batch_size = 100 # How old deleted records should be (deleted_at) to be purged, in seconds #time_threshold = 604800 # 7 days #------------------------ # Delayed zones NOTIFY #------------------------ [zone_manager_task:delayed_notify] # How frequently to scan for zones pending NOTIFY, in seconds #interval = 5 # How many zones to receive NOTIFY on each run #batch_size = 100 #----------------------- # Pool Manager Service #----------------------- [service:pool_manager] # Number of Pool Manager worker processes to spawn #workers = None # Number of Pool Manager greenthreads to spawn #threads = 1000 # The ID of the pool managed by this instance of the Pool Manager #pool_id = 794ccc2c-d751-44fe-b57f-8894c9f5c842 # The percentage of servers requiring a successful update for a domain change # to be considered active #threshold_percentage = 100 # The time to wait for a response from a server #poll_timeout = 30 # The time between retrying to send a request and waiting for a response from a # server #poll_retry_interval = 15 # The maximum number of times to retry sending a request and wait for a # response from a server #poll_max_retries = 10 # The time to wait before sending the first request to a server #poll_delay = 5 # Enable the recovery thread #enable_recovery_timer = True # The time between recovering from failures #periodic_recovery_interval = 120 # Enable the sync thread #enable_sync_timer = True # The time between synchronizing the servers with storage #periodic_sync_interval = 1800 # Zones Updated within last N seconds will be syncd. Use None to sync all zones #periodic_sync_seconds = None # Perform multiple update attempts during periodic_sync #periodic_sync_max_attempts = 3 #periodic_sync_retry_interval = 30 # The cache driver to use #cache_driver = memcache ################################### ## Pool Manager Cache Configuration ################################### #----------------------- # SQLAlchemy Pool Manager Cache #----------------------- [pool_manager_cache:sqlalchemy] #connection = sqlite:///$state_path/designate_pool_manager.sqlite #connection_debug = 100 #connection_trace = False #sqlite_synchronous = True #idle_timeout = 3600 #max_retries = 10 #retry_interval = 10 #----------------------- # Memcache Pool Manager Cache #----------------------- [pool_manager_cache:memcache] #memcached_servers = None #expiration = 3600 ##################### ## Pool Configuration ##################### # This section does not have the defaults filled in but demonstrates an # example pool / server set up. Different backends will have different options. #[pool:794ccc2c-d751-44fe-b57f-8894c9f5c842] #nameservers = 0f66b842-96c2-4189-93fc-1dc95a08b012 #targets = f26e0b32-736f-4f0a-831b-039a415c481e #also_notifies = 192.0.2.1:53, 192.0.2.2:53 #[pool_nameserver:0f66b842-96c2-4189-93fc-1dc95a08b012] #port = 53 #host = 192.168.27.100 #[pool_target:f26e0b32-736f-4f0a-831b-039a415c481e] #options = rndc_host: 192.168.27.100, rndc_port: 953, rndc_config_file: /etc/bind/rndc.conf, rndc_key_file: /etc/bind/rndc.key, port: 53, host: 192.168.27.100, clean_zonefile: false #masters = 192.168.27.100:5354 #type = bind9 ############## ## Network API ############## [network_api:neutron] # Comma separated list of values, formatted "|" #endpoints = RegionOne|http://localhost:9696 #endpoint_type = publicURL #timeout = 30 #admin_username = designate #admin_password = designate #admin_tenant_name = designate #auth_url = http://localhost:35357/v2.0 #insecure = False #auth_strategy = keystone #ca_certificates_file = ######################## ## Storage Configuration ######################## #----------------------- # SQLAlchemy Storage #----------------------- [storage:sqlalchemy] # Database connection string - to configure options for a given implementation # like sqlalchemy or other see below #connection = sqlite:///$state_path/designate.sqlite #connection_debug = 0 #connection_trace = False #sqlite_synchronous = True #idle_timeout = 3600 #max_retries = 10 #retry_interval = 10 ######################## ## Handler Configuration ######################## #----------------------- # Nova Fixed Handler #----------------------- [handler:nova_fixed] # Domain ID of domain to create records in. Should be pre-created #domain_id = #notification_topics = notifications #control_exchange = 'nova' #format = '%(octet0)s-%(octet1)s-%(octet2)s-%(octet3)s.%(domain)s' #format = '%(hostname)s.%(project)s.%(domain)s' #format = '%(hostname)s.%(domain)s' #------------------------ # Neutron Floating Handler #------------------------ [handler:neutron_floatingip] # Domain ID of domain to create records in. Should be pre-created #domain_id = #notification_topics = notifications #control_exchange = 'neutron' #format = '%(octet0)s-%(octet1)s-%(octet2)s-%(octet3)s.%(domain)s' #format = '%(hostname)s.%(project)s.%(domain)s' #format = '%(hostname)s.%(domain)s' ############################# ## Agent Backend Configuration ############################# [backend:agent:bind9] #rndc_host = 127.0.0.1 #rndc_port = 953 #rndc_config_file = /etc/rndc.conf #rndc_key_file = /etc/rndc.key #zone_file_path = $state_path/zones #query_destination = 127.0.0.1 # [backend:agent:denominator] #name = dynect #config_file = /etc/denominator.conf ######################## ## Library Configuration ######################## [oslo_concurrency] # Path for Oslo Concurrency to store lock files, defaults to the value # of the state_path setting. #lock_path = $state_path ######################## ## Coordination ######################## [coordination] # URL for the coordination backend to use. #backend_url = kazoo://127.0.0.1/ ######################## ## Hook Points ######################## # Hook Points are enabled when added to the config and there has been # a package that provides the corresponding named designate.hook_point # entry point. # [hook_point:name_of_hook_point] # some_param_for_hook = 42 # Hooks can be disabled in the config # enabled = False # Hook can also be applied to the import path when the hook has not # been given an explicit name. The name is created from the hook # target function / method: # # name = '%s.%s' % (func.__module__, func.__name__) # [hook_point:designate.api.v2.controllers.zones.get_one] designate-2.0.0/babel.cfg0000664000567000056710000000002112701406241016331 0ustar jenkinsjenkins00000000000000[python: **.py] designate-2.0.0/openstack-common.conf0000664000567000056710000000036712701406241020744 0ustar jenkinsjenkins00000000000000[DEFAULT] # The list of scriptss to copy from oslo-incubator.git script=tools/install_venv_common.py # The list of modules to copy from oslo-incubator.git module=memorycache # The base module to hold the copy of openstack.common base=designate designate-2.0.0/.coveragerc0000664000567000056710000000016512701406241016735 0ustar jenkinsjenkins00000000000000[run] branch = True source = designate omit = designate/tests/*,designate/openstack/* [report] ignore_errors = True designate-2.0.0/setup.cfg0000664000567000056710000001230012701406373016435 0ustar jenkinsjenkins00000000000000[metadata] name = designate summary = DNS as a Service description-file = README.rst author = Kiall Mac Innes author-email = kiall@managedit.ie home-page = https://launchpad.net/designate classifier = Environment :: OpenStack Environment :: No Input/Output (Daemon) Intended Audience :: Information Technology Intended Audience :: System Administrators License :: OSI Approved :: Apache Software License Operating System :: POSIX :: Linux Programming Language :: Python Programming Language :: Python :: 2 Programming Language :: Python :: 2.7 Topic :: Internet :: Name Service (DNS) [global] setup-hooks = pbr.hooks.setup_hook [files] packages = designate data_files = etc/designate = etc/designate/api-paste.ini etc/designate/policy.json etc/designate/designate.conf.sample etc/designate/rootwrap.conf.sample etc/designate/rootwrap.d = etc/designate/rootwrap.d/bind9.filters [entry_points] console_scripts = designate-rootwrap = oslo_rootwrap.cmd:main designate-api = designate.cmd.api:main designate-central = designate.cmd.central:main designate-manage = designate.cmd.manage:main designate-mdns = designate.cmd.mdns:main designate-pool-manager = designate.cmd.pool_manager:main designate-zone-manager = designate.cmd.zone_manager:main designate-sink = designate.cmd.sink:main designate-agent = designate.cmd.agent:main designate.api.v1 = domains = designate.api.v1.domains:blueprint limits = designate.api.v1.limits:blueprint records = designate.api.v1.records:blueprint servers = designate.api.v1.servers:blueprint tsigkeys = designate.api.v1.tsigkeys:blueprint designate.api.v1.extensions = diagnostics = designate.api.v1.extensions.diagnostics:blueprint quotas = designate.api.v1.extensions.quotas:blueprint sync = designate.api.v1.extensions.sync:blueprint reports = designate.api.v1.extensions.reports:blueprint touch = designate.api.v1.extensions.touch:blueprint designate.api.admin.extensions = reports = designate.api.admin.controllers.extensions.reports:ReportsController quotas = designate.api.admin.controllers.extensions.quotas:QuotasController zones = designate.api.admin.controllers.extensions.zones:ZonesController target_sync = designate.api.admin.controllers.extensions.target_sync:TargetSyncController designate.storage = sqlalchemy = designate.storage.impl_sqlalchemy:SQLAlchemyStorage designate.pool_manager.cache = memcache = designate.pool_manager.cache.impl_memcache:MemcachePoolManagerCache noop = designate.pool_manager.cache.impl_noop:NoopPoolManagerCache sqlalchemy = designate.pool_manager.cache.impl_sqlalchemy:SQLAlchemyPoolManagerCache designate.notification.handler = nova_fixed = designate.notification_handler.nova:NovaFixedHandler neutron_floatingip = designate.notification_handler.neutron:NeutronFloatingHandler designate.backend = bind9 = designate.backend.impl_bind9:Bind9Backend designate = designate.backend.impl_designate:DesignateBackend powerdns = designate.backend.impl_powerdns:PowerDNSBackend dynect = designate.backend.impl_dynect:DynECTBackend akamai = designate.backend.impl_akamai:AkamaiBackend nsd4 = designate.backend.impl_nsd4:NSD4Backend infoblox = designate.backend.impl_infoblox:InfobloxBackend fake = designate.backend.impl_fake:FakeBackend agent = designate.backend.agent:AgentPoolBackend designate.backend.agent_backend = bind9 = designate.backend.agent_backend.impl_bind9:Bind9Backend denominator = designate.backend.agent_backend.impl_denominator:DenominatorBackend fake = designate.backend.agent_backend.impl_fake:FakeBackend designate.network_api = fake = designate.network_api.fake:FakeNetworkAPI neutron = designate.network_api.neutron:NeutronNetworkAPI designate.quota = noop = designate.quota.impl_noop:NoopQuota storage = designate.quota.impl_storage:StorageQuota designate.scheduler.filters = fallback = designate.scheduler.filters.fallback_filter:FallbackFilter random = designate.scheduler.filters.random_filter:RandomFilter pool_id_attribute = designate.scheduler.filters.pool_id_attribute_filter:PoolIDAttributeFilter default_pool = designate.scheduler.filters.default_pool_filter:DefaultPoolFilter designate.manage = database = designate.manage.database:DatabaseCommands akamai = designate.manage.akamai:AkamaiCommands pool = designate.manage.pool:PoolCommands pool-manager-cache = designate.manage.pool_manager_cache:DatabaseCommands powerdns = designate.manage.powerdns:DatabaseCommands tlds = designate.manage.tlds:TLDCommands designate.zone_manager_tasks = zone_purge = designate.zone_manager.tasks:DeletedZonePurgeTask periodic_exists = designate.zone_manager.tasks:PeriodicExistsTask periodic_secondary_refresh = designate.zone_manager.tasks:PeriodicSecondaryRefreshTask delayed_notify = designate.zone_manager.tasks:PeriodicGenerateDelayedNotifyTask [build_sphinx] all_files = 1 build-dir = doc/build source-dir = doc/source [egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 [compile_catalog] directory = designate/locale domain = designate [update_catalog] domain = designate output_dir = designate/locale input_file = designate/locale/designate.pot [extract_messages] keywords = _ gettext ngettext l_ lazy_gettext mapping_file = babel.cfg output_file = designate/locale/designate.pot [wheel] universal = 1 designate-2.0.0/designate.egg-info/0000775000567000056710000000000012701406373020255 5ustar jenkinsjenkins00000000000000designate-2.0.0/designate.egg-info/requires.txt0000664000567000056710000000175712701406372022666 0ustar jenkinsjenkins00000000000000Babel>=1.3 eventlet!=0.18.3,>=0.18.2 Flask<1.0,>=0.10 greenlet>=0.3.2 Jinja2>=2.8 jsonschema!=2.5.0,<3.0.0,>=2.0.0 keystoneauth1>=2.1.0 keystonemiddleware!=4.1.0,>=4.0.0 netaddr!=0.7.16,>=0.7.12 oslo.config>=3.7.0 oslo.concurrency>=3.5.0 oslo.messaging>=4.0.0 oslo.middleware>=3.0.0 oslo.log>=1.14.0 oslo.reports>=0.6.0 oslo.rootwrap>=2.0.0 oslo.serialization>=1.10.0 oslo.service>=1.0.0 oslo.utils>=3.5.0 Paste PasteDeploy>=1.5.0 pbr>=1.6 pecan>=1.0.0 python-designateclient>=1.5.0 python-neutronclient!=4.1.0,>=2.6.0 requests!=2.9.0,>=2.8.1 six>=1.9.0 SQLAlchemy<1.1.0,>=1.0.10 sqlalchemy-migrate>=0.9.6 stevedore>=1.5.0 suds-jurko>=0.6 setuptools>=16.0 WebOb>=1.2.3 oslo.db>=4.1.0 oslo.i18n>=2.1.0 oslo.context>=0.2.0 oslo.policy>=0.5.0 Werkzeug>=0.7 python-memcached>=1.56 tooz>=1.28.0 debtcollector>=1.2.0 [:(python_version!='2.7')] Routes!=2.0,>=1.12.3 [:(python_version<'3.0')] dnspython>=1.12.0 [:(python_version=='2.7')] Routes!=2.0,!=2.1,>=1.12.3 [:(python_version>='3.0')] dnspython3>=1.12.0 designate-2.0.0/designate.egg-info/dependency_links.txt0000664000567000056710000000000112701406372024322 0ustar jenkinsjenkins00000000000000 designate-2.0.0/designate.egg-info/not-zip-safe0000664000567000056710000000000112701406367022506 0ustar jenkinsjenkins00000000000000 designate-2.0.0/designate.egg-info/SOURCES.txt0000664000567000056710000007773612701406373022165 0ustar jenkinsjenkins00000000000000.coveragerc .testr.conf AUTHORS ChangeLog LICENSE README.rst babel.cfg bandit.yaml designate.sublime-project ipa-requirements.txt openstack-common.conf requirements.txt setup.cfg setup.py test-requirements.txt tests-py3.txt tox.ini contrib/dns_dump_dnspy.py contrib/dns_dump_hex_to_text.py contrib/dns_dump_raw.py contrib/dns_dump_server.py contrib/ipaextractor.py contrib/records_mass_create.py contrib/zoneextractor.py contrib/archive/backends/impl_multi.py contrib/archive/backends/impl_ipa/__init__.py contrib/archive/backends/impl_ipa/auth.py contrib/designate-ext-samplehandler/.gitignore contrib/designate-ext-samplehandler/MANIFEST.in contrib/designate-ext-samplehandler/README.rst contrib/designate-ext-samplehandler/requirements.txt contrib/designate-ext-samplehandler/setup.cfg contrib/designate-ext-samplehandler/setup.py contrib/designate-ext-samplehandler/test-requirements.txt contrib/designate-ext-samplehandler/designate_ext_samplehandler/__init__.py contrib/designate-ext-samplehandler/designate_ext_samplehandler/version.py contrib/designate-ext-samplehandler/designate_ext_samplehandler/notification_handler/__init__.py contrib/designate-ext-samplehandler/designate_ext_samplehandler/notification_handler/sample.py contrib/tempest/README.rst contrib/tempest/clients.py contrib/tempest/config.py contrib/tempest/tempest.conf.sample contrib/tempest/dns_clients/__init__.py contrib/tempest/dns_clients/json/__init__.py contrib/tempest/dns_clients/json/domains_client.py contrib/tempest/dns_clients/json/records_client.py contrib/tempest/dns_clients/json/server_client.py contrib/tempest/dns_schema/__init__.py contrib/tempest/dns_schema/domains.py contrib/tempest/dns_schema/parameter_types.py contrib/tempest/dns_schema/records.py contrib/tempest/dns_schema/servers.py contrib/tempest/dns_tests/__init__.py contrib/tempest/dns_tests/base.py contrib/tempest/dns_tests/test_domains.py contrib/tempest/dns_tests/test_records.py contrib/tempest/dns_tests/admin/__init__.py contrib/tempest/dns_tests/admin/test_servers.py contrib/vagrant/Vagrantfile contrib/vagrant/local.conf designate/__init__.py designate/context.py designate/coordination.py designate/debug.py designate/dnsutils.py designate/exceptions.py designate/hookpoints.py designate/i18n.py designate/notifications.py designate/plugin.py designate/policy.py designate/rpc.py designate/service.py designate/utils.py designate/version.py designate.egg-info/PKG-INFO designate.egg-info/SOURCES.txt designate.egg-info/dependency_links.txt designate.egg-info/entry_points.txt designate.egg-info/not-zip-safe designate.egg-info/pbr.json designate.egg-info/requires.txt designate.egg-info/top_level.txt designate/agent/__init__.py designate/agent/handler.py designate/agent/service.py designate/api/__init__.py designate/api/middleware.py designate/api/service.py designate/api/versions.py designate/api/admin/__init__.py designate/api/admin/app.py designate/api/admin/controllers/__init__.py designate/api/admin/controllers/root.py designate/api/admin/controllers/extensions/__init__.py designate/api/admin/controllers/extensions/counts.py designate/api/admin/controllers/extensions/export.py designate/api/admin/controllers/extensions/quotas.py designate/api/admin/controllers/extensions/reports.py designate/api/admin/controllers/extensions/target_sync.py designate/api/admin/controllers/extensions/tenants.py designate/api/admin/controllers/extensions/zones.py designate/api/admin/views/__init__.py designate/api/admin/views/base.py designate/api/admin/views/extensions/__init__.py designate/api/admin/views/extensions/quotas.py designate/api/admin/views/extensions/reports.py designate/api/v1/__init__.py designate/api/v1/domains.py designate/api/v1/limits.py designate/api/v1/records.py designate/api/v1/servers.py designate/api/v1/tsigkeys.py designate/api/v1/extensions/__init__.py designate/api/v1/extensions/diagnostics.py designate/api/v1/extensions/quotas.py designate/api/v1/extensions/reports.py designate/api/v1/extensions/sync.py designate/api/v1/extensions/touch.py designate/api/v2/__init__.py designate/api/v2/app.py designate/api/v2/patches.py designate/api/v2/controllers/__init__.py designate/api/v2/controllers/blacklists.py designate/api/v2/controllers/errors.py designate/api/v2/controllers/floatingips.py designate/api/v2/controllers/limits.py designate/api/v2/controllers/pools.py designate/api/v2/controllers/recordsets.py designate/api/v2/controllers/rest.py designate/api/v2/controllers/reverse.py designate/api/v2/controllers/root.py designate/api/v2/controllers/tlds.py designate/api/v2/controllers/tsigkeys.py designate/api/v2/controllers/zones/__init__.py designate/api/v2/controllers/zones/nameservers.py designate/api/v2/controllers/zones/tasks/__init__.py designate/api/v2/controllers/zones/tasks/abandon.py designate/api/v2/controllers/zones/tasks/exports.py designate/api/v2/controllers/zones/tasks/imports.py designate/api/v2/controllers/zones/tasks/transfer_accepts.py designate/api/v2/controllers/zones/tasks/transfer_requests.py designate/api/v2/controllers/zones/tasks/xfr.py designate/backend/__init__.py designate/backend/agent.py designate/backend/base.py designate/backend/impl_akamai.py designate/backend/impl_bind9.py designate/backend/impl_designate.py designate/backend/impl_dynect.py designate/backend/impl_fake.py designate/backend/impl_nsd4.py designate/backend/agent_backend/__init__.py designate/backend/agent_backend/base.py designate/backend/agent_backend/impl_bind9.py designate/backend/agent_backend/impl_denominator.py designate/backend/agent_backend/impl_fake.py designate/backend/impl_infoblox/__init__.py designate/backend/impl_infoblox/config.py designate/backend/impl_infoblox/connector.py designate/backend/impl_infoblox/ibexceptions.py designate/backend/impl_infoblox/object_manipulator.py designate/backend/impl_powerdns/__init__.py designate/backend/impl_powerdns/tables.py designate/backend/impl_powerdns/migrate_repo/README designate/backend/impl_powerdns/migrate_repo/__init__.py designate/backend/impl_powerdns/migrate_repo/manage.py designate/backend/impl_powerdns/migrate_repo/migrate.cfg designate/backend/impl_powerdns/migrate_repo/versions/001_add_initial_schema.py designate/backend/impl_powerdns/migrate_repo/versions/002_add_moniker_id_cols.py designate/backend/impl_powerdns/migrate_repo/versions/003_correct_master_column_length.py designate/backend/impl_powerdns/migrate_repo/versions/004_correct_content_column_length.py designate/backend/impl_powerdns/migrate_repo/versions/005_rename_moniker_id_columns.py designate/backend/impl_powerdns/migrate_repo/versions/006_add_inherit_ttl_col.py designate/backend/impl_powerdns/migrate_repo/versions/007_add_recordset_id_col.py designate/backend/impl_powerdns/migrate_repo/versions/008_record_add_designate_recordset_id_index.py designate/backend/impl_powerdns/migrate_repo/versions/009_cascade_domain_deletes.py designate/backend/impl_powerdns/migrate_repo/versions/010_records_add_disabled_column.py designate/backend/impl_powerdns/migrate_repo/versions/011_records_drop_designate_ids.py designate/backend/impl_powerdns/migrate_repo/versions/012_placeholder.py designate/backend/impl_powerdns/migrate_repo/versions/013_placeholder.py designate/backend/impl_powerdns/migrate_repo/versions/014_placeholder.py designate/backend/impl_powerdns/migrate_repo/versions/015_placeholder.py designate/backend/impl_powerdns/migrate_repo/versions/016_placeholder.py designate/backend/impl_powerdns/migrate_repo/versions/017_records_drop_duped_index.py designate/backend/impl_powerdns/migrate_repo/versions/__init__.py designate/central/__init__.py designate/central/rpcapi.py designate/central/service.py designate/cmd/__init__.py designate/cmd/agent.py designate/cmd/api.py designate/cmd/central.py designate/cmd/manage.py designate/cmd/mdns.py designate/cmd/pool_manager.py designate/cmd/sink.py designate/cmd/zone_manager.py designate/common/__init__.py designate/common/config.py designate/hacking/__init__.py designate/hacking/checks.py designate/manage/__init__.py designate/manage/akamai.py designate/manage/base.py designate/manage/database.py designate/manage/pool.py designate/manage/pool_manager_cache.py designate/manage/powerdns.py designate/manage/tlds.py designate/mdns/__init__.py designate/mdns/base.py designate/mdns/handler.py designate/mdns/notify.py designate/mdns/rpcapi.py designate/mdns/service.py designate/mdns/xfr.py designate/network_api/__init__.py designate/network_api/base.py designate/network_api/fake.py designate/network_api/neutron.py designate/notification_handler/__init__.py designate/notification_handler/base.py designate/notification_handler/neutron.py designate/notification_handler/nova.py designate/objects/__init__.py designate/objects/base.py designate/objects/blacklist.py designate/objects/floating_ip.py designate/objects/pool.py designate/objects/pool_also_notify.py designate/objects/pool_attribute.py designate/objects/pool_manager_status.py designate/objects/pool_nameserver.py designate/objects/pool_ns_record.py designate/objects/pool_target.py designate/objects/pool_target_master.py designate/objects/pool_target_option.py designate/objects/quota.py designate/objects/record.py designate/objects/recordset.py designate/objects/rrdata_a.py designate/objects/rrdata_aaaa.py designate/objects/rrdata_cname.py designate/objects/rrdata_mx.py designate/objects/rrdata_ns.py designate/objects/rrdata_ptr.py designate/objects/rrdata_soa.py designate/objects/rrdata_spf.py designate/objects/rrdata_srv.py designate/objects/rrdata_sshfp.py designate/objects/rrdata_txt.py designate/objects/server.py designate/objects/tenant.py designate/objects/tld.py designate/objects/tsigkey.py designate/objects/validation_error.py designate/objects/zone.py designate/objects/zone_attribute.py designate/objects/zone_export.py designate/objects/zone_import.py designate/objects/zone_master.py designate/objects/zone_transfer_accept.py designate/objects/zone_transfer_request.py designate/objects/adapters/__init__.py designate/objects/adapters/base.py designate/objects/adapters/api_v1/__init__.py designate/objects/adapters/api_v1/base.py designate/objects/adapters/api_v2/__init__.py designate/objects/adapters/api_v2/base.py designate/objects/adapters/api_v2/blacklist.py designate/objects/adapters/api_v2/floating_ip.py designate/objects/adapters/api_v2/pool.py designate/objects/adapters/api_v2/pool_attribute.py designate/objects/adapters/api_v2/pool_ns_record.py designate/objects/adapters/api_v2/quota.py designate/objects/adapters/api_v2/record.py designate/objects/adapters/api_v2/recordset.py designate/objects/adapters/api_v2/tld.py designate/objects/adapters/api_v2/tsigkey.py designate/objects/adapters/api_v2/validation_error.py designate/objects/adapters/api_v2/zone.py designate/objects/adapters/api_v2/zone_attribute.py designate/objects/adapters/api_v2/zone_export.py designate/objects/adapters/api_v2/zone_import.py designate/objects/adapters/api_v2/zone_master.py designate/objects/adapters/api_v2/zone_transfer_accept.py designate/objects/adapters/api_v2/zone_transfer_request.py designate/objects/adapters/yaml/__init__.py designate/objects/adapters/yaml/base.py designate/objects/adapters/yaml/pool.py designate/objects/adapters/yaml/pool_also_notify.py designate/objects/adapters/yaml/pool_attribute.py designate/objects/adapters/yaml/pool_nameserver.py designate/objects/adapters/yaml/pool_ns_record.py designate/objects/adapters/yaml/pool_target.py designate/objects/adapters/yaml/pool_target_master.py designate/objects/adapters/yaml/pool_target_option.py designate/openstack/__init__.py designate/openstack/common/__init__.py designate/openstack/common/memorycache.py designate/pool_manager/__init__.py designate/pool_manager/rpcapi.py designate/pool_manager/service.py designate/pool_manager/cache/__init__.py designate/pool_manager/cache/base.py designate/pool_manager/cache/impl_memcache/__init__.py designate/pool_manager/cache/impl_noop/__init__.py designate/pool_manager/cache/impl_sqlalchemy/__init__.py designate/pool_manager/cache/impl_sqlalchemy/tables.py designate/pool_manager/cache/impl_sqlalchemy/migrate_repo/README designate/pool_manager/cache/impl_sqlalchemy/migrate_repo/__init__.py designate/pool_manager/cache/impl_sqlalchemy/migrate_repo/manage.py designate/pool_manager/cache/impl_sqlalchemy/migrate_repo/migrate.cfg designate/pool_manager/cache/impl_sqlalchemy/migrate_repo/versions/001_add_pool_manager_status.py designate/pool_manager/cache/impl_sqlalchemy/migrate_repo/versions/002_rename_server_to_nameserver.py designate/pool_manager/cache/impl_sqlalchemy/migrate_repo/versions/003_placeholder.py designate/pool_manager/cache/impl_sqlalchemy/migrate_repo/versions/004_placeholder.py designate/pool_manager/cache/impl_sqlalchemy/migrate_repo/versions/005_placeholder.py designate/pool_manager/cache/impl_sqlalchemy/migrate_repo/versions/006_placeholder.py designate/pool_manager/cache/impl_sqlalchemy/migrate_repo/versions/007_placeholder.py designate/pool_manager/cache/impl_sqlalchemy/migrate_repo/versions/008_domain_to_zone_rename.py designate/pool_manager/cache/impl_sqlalchemy/migrate_repo/versions/__init__.py designate/quota/__init__.py designate/quota/base.py designate/quota/impl_noop.py designate/quota/impl_storage.py designate/resources/schemas/admin/quota.json designate/resources/schemas/v1/domain.json designate/resources/schemas/v1/domains.json designate/resources/schemas/v1/fault.json designate/resources/schemas/v1/limits.json designate/resources/schemas/v1/record.json designate/resources/schemas/v1/records.json designate/resources/schemas/v1/server.json designate/resources/schemas/v1/servers.json designate/resources/schemas/v1/tsigkey.json designate/resources/schemas/v1/tsigkeys.json designate/resources/templates/bind9-zone.jinja2 designate/resources/templates/dnsmasq-zone.jinja2 designate/resources/templates/export-zone.jinja2 designate/resources/wsdl/EnhancedDNS.xml designate/scheduler/__init__.py designate/scheduler/base.py designate/scheduler/filters/__init__.py designate/scheduler/filters/attribute_filter.py designate/scheduler/filters/base.py designate/scheduler/filters/default_pool_filter.py designate/scheduler/filters/fallback_filter.py designate/scheduler/filters/pool_id_attribute_filter.py designate/scheduler/filters/random_filter.py designate/schema/__init__.py designate/schema/_validators.py designate/schema/format.py designate/schema/resolvers.py designate/schema/validators.py designate/sink/__init__.py designate/sink/service.py designate/sqlalchemy/__init__.py designate/sqlalchemy/base.py designate/sqlalchemy/session.py designate/sqlalchemy/types.py designate/sqlalchemy/utils.py designate/storage/__init__.py designate/storage/base.py designate/storage/impl_sqlalchemy/__init__.py designate/storage/impl_sqlalchemy/tables.py designate/storage/impl_sqlalchemy/migrate_repo/README designate/storage/impl_sqlalchemy/migrate_repo/__init__.py designate/storage/impl_sqlalchemy/migrate_repo/manage.py designate/storage/impl_sqlalchemy/migrate_repo/migrate.cfg designate/storage/impl_sqlalchemy/migrate_repo/utils.py designate/storage/impl_sqlalchemy/migrate_repo/versions/038_icehouse.py designate/storage/impl_sqlalchemy/migrate_repo/versions/039_support_soa_records.py designate/storage/impl_sqlalchemy/migrate_repo/versions/040_fix_record_data.py designate/storage/impl_sqlalchemy/migrate_repo/versions/041_server_pools_storage.py designate/storage/impl_sqlalchemy/migrate_repo/versions/042_priority_to_data.py designate/storage/impl_sqlalchemy/migrate_repo/versions/043_modify_domains_and_records.py designate/storage/impl_sqlalchemy/migrate_repo/versions/044_add_pool_id_to_domains.py designate/storage/impl_sqlalchemy/migrate_repo/versions/045_add_uniqueconstraint_to_pool_attributes.py designate/storage/impl_sqlalchemy/migrate_repo/versions/046_add_indices.py designate/storage/impl_sqlalchemy/migrate_repo/versions/047_add_reverse_name.py designate/storage/impl_sqlalchemy/migrate_repo/versions/048_add_zone_ownership_transfers_tables.py designate/storage/impl_sqlalchemy/migrate_repo/versions/049_migrate_servers.py designate/storage/impl_sqlalchemy/migrate_repo/versions/050_drop_servers.py designate/storage/impl_sqlalchemy/migrate_repo/versions/051_scoped_tsig.py designate/storage/impl_sqlalchemy/migrate_repo/versions/052_secondary_zones.py designate/storage/impl_sqlalchemy/migrate_repo/versions/053_pool_nameservers.py designate/storage/impl_sqlalchemy/migrate_repo/versions/054_allow_duplicate_domains.py designate/storage/impl_sqlalchemy/migrate_repo/versions/055_add_created_indices.py designate/storage/impl_sqlalchemy/migrate_repo/versions/056_placeholder.py designate/storage/impl_sqlalchemy/migrate_repo/versions/057_placeholder.py designate/storage/impl_sqlalchemy/migrate_repo/versions/058_placeholder.py designate/storage/impl_sqlalchemy/migrate_repo/versions/059_placeholder.py designate/storage/impl_sqlalchemy/migrate_repo/versions/060_placeholder.py designate/storage/impl_sqlalchemy/migrate_repo/versions/061_placeholder.py designate/storage/impl_sqlalchemy/migrate_repo/versions/062_placeholder.py designate/storage/impl_sqlalchemy/migrate_repo/versions/063_placeholder.py designate/storage/impl_sqlalchemy/migrate_repo/versions/064_placeholder.py designate/storage/impl_sqlalchemy/migrate_repo/versions/065_placeholder.py designate/storage/impl_sqlalchemy/migrate_repo/versions/066_add_update_status_index.py designate/storage/impl_sqlalchemy/migrate_repo/versions/067_zone_tasks.py designate/storage/impl_sqlalchemy/migrate_repo/versions/068_add_shard_column.py designate/storage/impl_sqlalchemy/migrate_repo/versions/069_zone_tasks_location.py designate/storage/impl_sqlalchemy/migrate_repo/versions/070_placeholder.py designate/storage/impl_sqlalchemy/migrate_repo/versions/071_placeholder.py designate/storage/impl_sqlalchemy/migrate_repo/versions/072_placeholder.py designate/storage/impl_sqlalchemy/migrate_repo/versions/073_placeholder.py designate/storage/impl_sqlalchemy/migrate_repo/versions/074_placeholder.py designate/storage/impl_sqlalchemy/migrate_repo/versions/075_placeholder.py designate/storage/impl_sqlalchemy/migrate_repo/versions/076_placeholder.py designate/storage/impl_sqlalchemy/migrate_repo/versions/077_placeholder.py designate/storage/impl_sqlalchemy/migrate_repo/versions/078_placeholder.py designate/storage/impl_sqlalchemy/migrate_repo/versions/079_placeholder.py designate/storage/impl_sqlalchemy/migrate_repo/versions/080_domain_to_zone_rename.py designate/storage/impl_sqlalchemy/migrate_repo/versions/081_add_FKs.py designate/storage/impl_sqlalchemy/migrate_repo/versions/082_unique_ns_record.py designate/storage/impl_sqlalchemy/migrate_repo/versions/083_change_managed_column_types.py designate/storage/impl_sqlalchemy/migrate_repo/versions/084_add_delayed_notify_column.py designate/storage/impl_sqlalchemy/migrate_repo/versions/085_add_zone_attributes.py designate/storage/impl_sqlalchemy/migrate_repo/versions/086_new_pools_tables.py designate/storage/impl_sqlalchemy/migrate_repo/versions/__init__.py designate/tests/__init__.py designate/tests/fixtures.py designate/tests/test_context.py designate/tests/test_coordination.py designate/tests/test_dnsutils.py designate/tests/test_hookpoints.py designate/tests/test_sqlalchemy.py designate/tests/test_utils.py designate/tests/resources/__init__.py designate/tests/resources/pools_yaml/multiple-pools.yaml designate/tests/resources/pools_yaml/pools.yaml designate/tests/resources/pools_yaml/sample_output.yaml designate/tests/resources/sample_notifications/neutron/floatingip.delete.start.json designate/tests/resources/sample_notifications/neutron/floatingip.update.end_associate.json designate/tests/resources/sample_notifications/neutron/floatingip.update.end_disassociate.json designate/tests/resources/sample_notifications/neutron/port.create.end.json designate/tests/resources/sample_notifications/neutron/port.create.start.josn designate/tests/resources/sample_notifications/neutron/port.delete.end.json designate/tests/resources/sample_notifications/neutron/port.delete.start.json designate/tests/resources/sample_notifications/nova/compute.instance.create.end.json designate/tests/resources/sample_notifications/nova/compute.instance.create.start.json designate/tests/resources/sample_notifications/nova/compute.instance.delete.start.json designate/tests/resources/sample_notifications/nova/compute.instance.shutdown.end.json designate/tests/resources/sample_notifications/nova/compute.instance.shutdown.start.json designate/tests/resources/sample_notifications/nova/network.floating_ip.allocate.json designate/tests/resources/sample_notifications/nova/network.floating_ip.associate.json designate/tests/resources/sample_notifications/nova/network.floating_ip.deallocate.json designate/tests/resources/sample_notifications/nova/network.floating_ip.disassociate.json designate/tests/resources/sample_notifications/nova/scheduler.run_instance.end.json designate/tests/resources/sample_notifications/nova/scheduler.run_instance.scheduled.json designate/tests/resources/sample_notifications/nova/scheduler.run_instance.start.json designate/tests/resources/ssl/nsd_control.key designate/tests/resources/ssl/nsd_control.pem designate/tests/resources/ssl/nsd_server.key designate/tests/resources/ssl/nsd_server.pem designate/tests/resources/zonefiles/example.com.zone designate/tests/resources/zonefiles/malformed_example.com.zone designate/tests/resources/zonefiles/noorigin_example.com.zone designate/tests/resources/zonefiles/nosoa_example.com.zone designate/tests/resources/zonefiles/two_example.com.zone designate/tests/test_agent/__init__.py designate/tests/test_agent/test_handler.py designate/tests/test_agent/test_service.py designate/tests/test_agent/test_backends/__init__.py designate/tests/test_agent/test_backends/test_bind9.py designate/tests/test_agent/test_backends/test_denominator.py designate/tests/test_agent/test_backends/test_fake.py designate/tests/test_api/__init__.py designate/tests/test_api/test_middleware.py designate/tests/test_api/test_service.py designate/tests/test_api/test_admin/__init__.py designate/tests/test_api/test_admin/extensions/__init__.py designate/tests/test_api/test_admin/extensions/test_quotas.py designate/tests/test_api/test_admin/extensions/test_reports.py designate/tests/test_api/test_v1/__init__.py designate/tests/test_api/test_v1/test_domains.py designate/tests/test_api/test_v1/test_limits.py designate/tests/test_api/test_v1/test_records.py designate/tests/test_api/test_v1/test_servers.py designate/tests/test_api/test_v1/test_tsigkeys.py designate/tests/test_api/test_v2/__init__.py designate/tests/test_api/test_v2/test_blacklists.py designate/tests/test_api/test_v2/test_floatingips.py designate/tests/test_api/test_v2/test_hostheaders.py designate/tests/test_api/test_v2/test_import_export.py designate/tests/test_api/test_v2/test_limits.py designate/tests/test_api/test_v2/test_pools.py designate/tests/test_api/test_v2/test_recordsets.py designate/tests/test_api/test_v2/test_tlds.py designate/tests/test_api/test_v2/test_tsigkeys.py designate/tests/test_api/test_v2/test_zone_transfers.py designate/tests/test_api/test_v2/test_zones.py designate/tests/test_backend/__init__.py designate/tests/test_backend/test_bind9.py designate/tests/test_backend/test_dynect.py designate/tests/test_backend/test_infoblox.py designate/tests/test_backend/test_nsd4.py designate/tests/test_backend/test_powerdns.py designate/tests/test_central/__init__.py designate/tests/test_central/_test_service_ipa.py designate/tests/test_central/test_service.py designate/tests/test_mdns/__init__.py designate/tests/test_mdns/test_handler.py designate/tests/test_mdns/test_notify.py designate/tests/test_mdns/test_service.py designate/tests/test_network_api/__init__.py designate/tests/test_network_api/test_neutron.py designate/tests/test_notification_handler/__init__.py designate/tests/test_notification_handler/test_neutron.py designate/tests/test_notification_handler/test_nova.py designate/tests/test_objects/__init__.py designate/tests/test_objects/test_mx_object.py designate/tests/test_objects/test_sshfp_object.py designate/tests/test_pool_manager/__init__.py designate/tests/test_pool_manager/test_rpcapi.py designate/tests/test_pool_manager/test_service.py designate/tests/test_pool_manager/cache/__init__.py designate/tests/test_pool_manager/cache/test_memcache.py designate/tests/test_pool_manager/cache/test_noop.py designate/tests/test_pool_manager/cache/test_sqlalchemy.py designate/tests/test_quota/__init__.py designate/tests/test_quota/test_quota.py designate/tests/test_quota/test_storage.py designate/tests/test_resources/__init__.py designate/tests/test_resources/test_templates/__init__.py designate/tests/test_resources/test_templates/test_bind9.py designate/tests/test_schema/__init__.py designate/tests/test_schema/test_format.py designate/tests/test_storage/__init__.py designate/tests/test_storage/test_sqlalchemy.py designate/tests/test_zone_manager/__init__.py designate/tests/test_zone_manager/test_service.py designate/tests/test_zone_manager/test_tasks.py designate/tests/unit/README designate/tests/unit/__init__.py designate/tests/unit/test_pool.py designate/tests/unit/test_api/__init__.py designate/tests/unit/test_api/test_admin_api.py designate/tests/unit/test_api/test_api_v2.py designate/tests/unit/test_api/test_middleware.py designate/tests/unit/test_backend/__init__.py designate/tests/unit/test_backend/test_agent.py designate/tests/unit/test_backend/test_designate.py designate/tests/unit/test_central/__init__.py designate/tests/unit/test_central/test_basic.py designate/tests/unit/test_mdns/__init__.py designate/tests/unit/test_mdns/test_handler.py designate/tests/unit/test_mdns/test_notify.py designate/tests/unit/test_mdns/test_service.py designate/tests/unit/test_objects/__init__.py designate/tests/unit/test_objects/test_adapters.py designate/tests/unit/test_objects/test_base.py designate/tests/unit/test_objects/test_domain.py designate/tests/unit/test_objects/test_recordset.py designate/tests/unit/test_objects/test_yaml_adapters.py designate/tests/unit/test_pool_manager/__init__.py designate/tests/unit/test_pool_manager/test_service.py designate/tests/unit/test_scheduler/__init__.py designate/tests/unit/test_scheduler/test_basic.py designate/tests/unit/test_scheduler/test_filters.py designate/tests/unit/test_zone_manager/__init__.py designate/tests/unit/test_zone_manager/test_service.py designate/tests/unit/test_zone_manager/test_tasks.py designate/zone_manager/__init__.py designate/zone_manager/rpcapi.py designate/zone_manager/service.py designate/zone_manager/tasks.py devstack/README.rst devstack/exercise.sh devstack/plugin.sh devstack/settings devstack/designate_plugins/backend-akamai devstack/designate_plugins/backend-bind9 devstack/designate_plugins/backend-designate devstack/designate_plugins/backend-dynect devstack/designate_plugins/backend-fake devstack/designate_plugins/backend-infoblox devstack/designate_plugins/backend-powerdns devstack/gate/gate_hook.sh devstack/gate/post_test_hook.sh devstack/gate/run_tempest_tests.sh doc/requirements.txt doc/ext/__init__.py doc/ext/support_matrix.py doc/source/api.rst doc/source/architecture.rst doc/source/backend.rst doc/source/backends.rst doc/source/central.rst doc/source/conf.py doc/source/configuration.rst doc/source/developer-guidelines.rst doc/source/devstack.rst doc/source/functional-tests.rst doc/source/getting-involved.rst doc/source/glossary.rst doc/source/gmr.rst doc/source/index.rst doc/source/integrations.rst doc/source/mdns.rst doc/source/objects.rst doc/source/pools.rst doc/source/production-architecture.rst doc/source/production-guidelines.rst doc/source/quota.rst doc/source/related.rst doc/source/rest.rst doc/source/sink.rst doc/source/storage.rst doc/source/support-matrix.ini doc/source/support-matrix.rst doc/source/backends/bind9.rst doc/source/backends/infoblox.rst doc/source/backends/powerdns.rst doc/source/diagrams/Designate-MultiZone.dia doc/source/diagrams/Designate-PowerDNS-Detail.dia doc/source/diagrams/Designate-Simple.dia doc/source/diagrams/README doc/source/examples/basic-config-sample-juno.conf doc/source/examples/basic-config-sample-kilo.conf doc/source/examples/basic-config-sample.conf doc/source/howtos/manage-domains.rst doc/source/howtos/manage-ptr-records.rst doc/source/howtos/secondary_zones.rst doc/source/images/Designate-MultiZone.png doc/source/images/Designate-PowerDNS-Detail.png doc/source/images/Designate-Simple.svg doc/source/install/ubuntu-dev.rst doc/source/install/ubuntu-juno.rst doc/source/install/ubuntu-kilo.rst doc/source/install/ubuntu-liberty.rst doc/source/pools/scheduler.rst doc/source/rest/admin/quotas.rst doc/source/rest/v1/diagnostics.rst doc/source/rest/v1/domains.rst doc/source/rest/v1/quotas.rst doc/source/rest/v1/records.rst doc/source/rest/v1/reports.rst doc/source/rest/v1/servers.rst doc/source/rest/v1/sync.rst doc/source/rest/v2/blacklists.rst doc/source/rest/v2/collections.rst doc/source/rest/v2/limits.rst doc/source/rest/v2/pools.rst doc/source/rest/v2/recordsets.rst doc/source/rest/v2/reverse.rst doc/source/rest/v2/tlds.rst doc/source/rest/v2/tsigkeys.rst doc/source/rest/v2/zones.rst doc/source/upgrade/kilo.rst doc/source/upgrade/mitaka.rst etc/designate/api-paste.ini etc/designate/designate.conf.sample etc/designate/policy.json etc/designate/pools.yaml.sample etc/designate/pools.yaml.sample-bind etc/designate/pools.yaml.sample-multiple-pools etc/designate/rootwrap.conf.sample etc/designate/rootwrap.d/bind9.filters functionaltests/__init__.py functionaltests/api/__init__.py functionaltests/api/v2/__init__.py functionaltests/api/v2/base.py functionaltests/api/v2/fixtures.py functionaltests/api/v2/test_blacklist.py functionaltests/api/v2/test_blacklist_unauthed.py functionaltests/api/v2/test_pool.py functionaltests/api/v2/test_pool_unauthed.py functionaltests/api/v2/test_recordset.py functionaltests/api/v2/test_recordset_unauthed.py functionaltests/api/v2/test_recordset_validation.py functionaltests/api/v2/test_tld.py functionaltests/api/v2/test_zone.py functionaltests/api/v2/test_zone_ownership_transfers.py functionaltests/api/v2/test_zone_unauthed.py functionaltests/api/v2/clients/__init__.py functionaltests/api/v2/clients/blacklist_client.py functionaltests/api/v2/clients/pool_client.py functionaltests/api/v2/clients/quotas_client.py functionaltests/api/v2/clients/recordset_client.py functionaltests/api/v2/clients/tld_client.py functionaltests/api/v2/clients/transfer_accepts_client.py functionaltests/api/v2/clients/transfer_requests_client.py functionaltests/api/v2/clients/zone_client.py functionaltests/api/v2/clients/zone_export_client.py functionaltests/api/v2/clients/zone_import_client.py functionaltests/api/v2/models/__init__.py functionaltests/api/v2/models/blacklist_model.py functionaltests/api/v2/models/pool_model.py functionaltests/api/v2/models/quotas_model.py functionaltests/api/v2/models/recordset_model.py functionaltests/api/v2/models/tld_model.py functionaltests/api/v2/models/transfer_accepts_model.py functionaltests/api/v2/models/transfer_requests_model.py functionaltests/api/v2/models/zone_export_model.py functionaltests/api/v2/models/zone_import_model.py functionaltests/api/v2/models/zone_model.py functionaltests/common/__init__.py functionaltests/common/base.py functionaltests/common/client.py functionaltests/common/config.py functionaltests/common/datagen.py functionaltests/common/dnsclient.py functionaltests/common/models.py functionaltests/common/noauth.py functionaltests/common/test_meta.py functionaltests/common/utils.py functionaltests/common/hooks/__init__.py functionaltests/common/hooks/base.py rally-jobs/README.rst rally-jobs/designate-designate.yaml rally-jobs/extra/README.rst rally-jobs/plugins/README.rst rally-jobs/plugins/__init__.py releasenotes/notes/.placeholder releasenotes/notes/api-dot-json-324038360202e86b.yaml releasenotes/notes/mini-dns-tcp-c1a15742f5c71739.yaml releasenotes/notes/pool-config-db-45a2cad74e22d95e.yaml releasenotes/notes/pool_scheduler-32e34dda9484ef9a.yaml releasenotes/notes/soa_refresh_interval_randomization-fcc1d0d63124699b.yaml releasenotes/source/conf.py releasenotes/source/index.rst releasenotes/source/liberty.rst releasenotes/source/unreleased.rst releasenotes/source/_static/.placeholder releasenotes/source/_templates/.placeholder tools/designate-keystone-setup tools/install_venv.py tools/install_venv_common.py tools/pretty_flake8.py tools/pretty_flake8.sh tools/pretty_tox.sh tools/with_venv.sh tools/mysql_pending_notify_bench/README tools/mysql_pending_notify_bench/runnerdesignate-2.0.0/designate.egg-info/PKG-INFO0000664000567000056710000000650312701406372021355 0ustar jenkinsjenkins00000000000000Metadata-Version: 1.1 Name: designate Version: 2.0.0 Summary: DNS as a Service Home-page: https://launchpad.net/designate Author: Kiall Mac Innes Author-email: kiall@managedit.ie License: UNKNOWN Description: =================== OpenStack Designate =================== Designate is an OpenStack project, providing DNSaaS. IRC: #openstack-dns Installation: http://docs.openstack.org/developer/designate/getting-started.html Development =========== Designate follows the `OpenStack Gerrit Workflow`_ Setup ----- Setup a working environment: .. code-block:: shell git clone https://github.com/openstack/designate.git cd designate virtualenv .venv . .venv/bin/activate pip install -r requirements.txt -r test-requirements.txt python setup.py develop Building Docs ------------- To build the documentation from the restructured text source, do the following: .. code-block:: shell cd doc pip install -r requirements.txt sphinx-build source/ build/html/ now point your browser at html/index.html (the official documentation is published to `docs.openstack.org`_ by the maintainers. Contributing ------------ Install the git-review package to make life easier .. code-block:: shell pip install git-review Branch, work, & submit: .. code-block:: shell # cut a new branch, tracking master git checkout --track -b bug/id origin/master # work work work git add stuff git commit # rebase/squash to a single commit before submitting git rebase -i # submit git-review Testing ------- Execute a single test using py27 (test is CentralServiceTest.test_count_domains) .. code-block:: shell tox -e py27 -- designate.tests.test_central.test_service.CentralServiceTest.test_count_zones_policy_check * Free software: Apache license * Documentation: http://docs.openstack.org/developer/designate * Source: http://git.openstack.org/cgit/openstack/designate * Bugs: http://bugs.launchpad.net/designate .. _OpenStack Gerrit Workflow: http://docs.openstack.org/infra/manual/developers.html#development-workflow .. _docs.openstack.org: http://docs.openstack.org/developer/designate Platform: UNKNOWN Classifier: Environment :: OpenStack Classifier: Environment :: No Input/Output (Daemon) Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Topic :: Internet :: Name Service (DNS) designate-2.0.0/designate.egg-info/top_level.txt0000664000567000056710000000001212701406372022777 0ustar jenkinsjenkins00000000000000designate designate-2.0.0/designate.egg-info/pbr.json0000664000567000056710000000005612701406372021733 0ustar jenkinsjenkins00000000000000{"is_release": true, "git_version": "f35da84"}designate-2.0.0/designate.egg-info/entry_points.txt0000664000567000056710000000742312701406372023560 0ustar jenkinsjenkins00000000000000[console_scripts] designate-agent = designate.cmd.agent:main designate-api = designate.cmd.api:main designate-central = designate.cmd.central:main designate-manage = designate.cmd.manage:main designate-mdns = designate.cmd.mdns:main designate-pool-manager = designate.cmd.pool_manager:main designate-rootwrap = oslo_rootwrap.cmd:main designate-sink = designate.cmd.sink:main designate-zone-manager = designate.cmd.zone_manager:main [designate.api.admin.extensions] quotas = designate.api.admin.controllers.extensions.quotas:QuotasController reports = designate.api.admin.controllers.extensions.reports:ReportsController target_sync = designate.api.admin.controllers.extensions.target_sync:TargetSyncController zones = designate.api.admin.controllers.extensions.zones:ZonesController [designate.api.v1] domains = designate.api.v1.domains:blueprint limits = designate.api.v1.limits:blueprint records = designate.api.v1.records:blueprint servers = designate.api.v1.servers:blueprint tsigkeys = designate.api.v1.tsigkeys:blueprint [designate.api.v1.extensions] diagnostics = designate.api.v1.extensions.diagnostics:blueprint quotas = designate.api.v1.extensions.quotas:blueprint reports = designate.api.v1.extensions.reports:blueprint sync = designate.api.v1.extensions.sync:blueprint touch = designate.api.v1.extensions.touch:blueprint [designate.backend] agent = designate.backend.agent:AgentPoolBackend akamai = designate.backend.impl_akamai:AkamaiBackend bind9 = designate.backend.impl_bind9:Bind9Backend designate = designate.backend.impl_designate:DesignateBackend dynect = designate.backend.impl_dynect:DynECTBackend fake = designate.backend.impl_fake:FakeBackend infoblox = designate.backend.impl_infoblox:InfobloxBackend nsd4 = designate.backend.impl_nsd4:NSD4Backend powerdns = designate.backend.impl_powerdns:PowerDNSBackend [designate.backend.agent_backend] bind9 = designate.backend.agent_backend.impl_bind9:Bind9Backend denominator = designate.backend.agent_backend.impl_denominator:DenominatorBackend fake = designate.backend.agent_backend.impl_fake:FakeBackend [designate.manage] akamai = designate.manage.akamai:AkamaiCommands database = designate.manage.database:DatabaseCommands pool = designate.manage.pool:PoolCommands pool-manager-cache = designate.manage.pool_manager_cache:DatabaseCommands powerdns = designate.manage.powerdns:DatabaseCommands tlds = designate.manage.tlds:TLDCommands [designate.network_api] fake = designate.network_api.fake:FakeNetworkAPI neutron = designate.network_api.neutron:NeutronNetworkAPI [designate.notification.handler] neutron_floatingip = designate.notification_handler.neutron:NeutronFloatingHandler nova_fixed = designate.notification_handler.nova:NovaFixedHandler [designate.pool_manager.cache] memcache = designate.pool_manager.cache.impl_memcache:MemcachePoolManagerCache noop = designate.pool_manager.cache.impl_noop:NoopPoolManagerCache sqlalchemy = designate.pool_manager.cache.impl_sqlalchemy:SQLAlchemyPoolManagerCache [designate.quota] noop = designate.quota.impl_noop:NoopQuota storage = designate.quota.impl_storage:StorageQuota [designate.scheduler.filters] default_pool = designate.scheduler.filters.default_pool_filter:DefaultPoolFilter fallback = designate.scheduler.filters.fallback_filter:FallbackFilter pool_id_attribute = designate.scheduler.filters.pool_id_attribute_filter:PoolIDAttributeFilter random = designate.scheduler.filters.random_filter:RandomFilter [designate.storage] sqlalchemy = designate.storage.impl_sqlalchemy:SQLAlchemyStorage [designate.zone_manager_tasks] delayed_notify = designate.zone_manager.tasks:PeriodicGenerateDelayedNotifyTask periodic_exists = designate.zone_manager.tasks:PeriodicExistsTask periodic_secondary_refresh = designate.zone_manager.tasks:PeriodicSecondaryRefreshTask zone_purge = designate.zone_manager.tasks:DeletedZonePurgeTask designate-2.0.0/tools/0000775000567000056710000000000012701406373015760 5ustar jenkinsjenkins00000000000000designate-2.0.0/tools/pretty_tox.sh0000775000567000056710000000026512701406241020535 0ustar jenkinsjenkins00000000000000#! /bin/sh TESTRARGS=$1 exec 3>&1 status=$(exec 4>&1 >&3; ( python setup.py testr --slowest --testr-args="--subunit $TESTRARGS"; echo $? >&4 ) | subunit-trace -f) && exit $status designate-2.0.0/tools/designate-keystone-setup0000664000567000056710000001314712701406241022643 0ustar jenkinsjenkins00000000000000#!/bin/bash # NOTE: Copied from Heat set +e KEYSTONE_CONF=${KEYSTONE_CONF:-/etc/keystone/keystone.conf} # Extract some info from Keystone's configuration file if [[ -r "$KEYSTONE_CONF" ]]; then CONFIG_SERVICE_TOKEN=$(sed 's/[[:space:]]//g' $KEYSTONE_CONF | grep ^admin_token= | cut -d'=' -f2) CONFIG_ADMIN_PORT=$(sed 's/[[:space:]]//g' $KEYSTONE_CONF | grep ^admin_port= | cut -d'=' -f2) fi SERVICE_TOKEN=${SERVICE_TOKEN:-$CONFIG_SERVICE_TOKEN} SERVICE_ENDPOINT=${SERVICE_ENDPOINT:-http://127.0.0.1:${CONFIG_ADMIN_PORT:-35357}/v2.0} if [[ -z "$SERVICE_TOKEN" ]]; then echo "No service token found." >&2 echo "Set SERVICE_TOKEN manually from keystone.conf admin_token." >&2 exit 1 fi get_data() { local match_column=$(($1 + 1)) local regex="$2" local output_column=$(($3 + 1)) shift 3 echo $("$@" | \ gawk -F'|' \ "! /^+/ && \$${match_column} ~ \"^ *${regex} *\$\" \ { print \$${output_column} }") } get_id () { get_data 1 id 2 "$@" } get_column_num() { local name=$1 shift $@ | grep -v "WARNING:" | gawk -F'|' "NR == 2 { for (i=2; i&2 echo $user_id else echo "Creating $username user..." >&2 get_id keystone user-create --name=$username \ --pass="$SERVICE_PASSWORD" \ --tenant_id $SERVICE_TENANT \ --email=designate@example.com fi } add_role() { local user_id=$1 local tenant=$2 local role_id=$3 local username=$4 # The keystone argument format changed between essex and folsom # so we use the fact that the folsom keystone version has a new # option "user-role-list" to detect we're on that newer version # This also allows us to detect when the user already has the # requested role_id, preventing an error on folsom user_roles=$(keystone user-role-list \ --user_id $user_id\ --tenant_id $tenant 2>/dev/null) if [ $? == 0 ]; then # Folsom existing_role=$(get_data 1 $role_id 1 echo "$user_roles") if [ -n "$existing_role" ] then echo "User $username already has role $role_id" >&2 return fi keystone user-role-add --tenant_id $tenant \ --user_id $user_id \ --role_id $role_id else # Essex keystone user-role-add --tenant_id $tenant \ --user $user_id \ --role $role_id fi } create_role() { local role_name=$1 role_id=$(get_data 2 $role_name 1 keystone role-list) if [ -n "$role_id" ] then echo "Role $role_name already exists : $role_id" >&2 else keystone role-create --name $role_name fi } get_endpoint() { local service_type=$1 keystone endpoint-get --service $service_type } delete_endpoint() { local service_type=$1 local url=$(get_data 1 "${service_type}[.]publicURL" 2 \ get_endpoint $service_type 2>/dev/null) if [ -n "$url" ]; then local endpoints=$(get_data 3 $url 1 keystone endpoint-list) for endpoint in $endpoints; do echo "Removing $service_type endpoint ${endpoint}..." >&2 keystone endpoint-delete "$endpoint" >&2 done if [ -z "$endpoints" ]; then false; fi else false fi } delete_all_endpoints() { while delete_endpoint $1; do true done } delete_service() { local service_type=$1 delete_all_endpoints $service_type local service_ids=$(get_data 3 $service_type 1 keystone service-list) for service in $service_ids; do local service_name=$(get_data 1 $service 2 keystone service-list) echo "Removing $service_name:$service_type service..." >&2 keystone service-delete $service >&2 done } get_service() { local service_name=$1 local service_type=$2 local description="$3" delete_service $service_type get_id keystone service-create --name=$service_name \ --type=$service_type \ --description="$description" } add_endpoint() { local service_id=$1 local url="$2" keystone endpoint-create --region RegionOne --service_id $service_id \ --publicurl "$url" --adminurl "$url" --internalurl "$url" >&2 } ADMIN_ROLE=$(get_data 2 admin 1 keystone role-list) SERVICE_TENANT=$(get_data 2 service 1 keystone tenant-list) SERVICE_PASSWORD=${SERVICE_PASSWORD:-$OS_PASSWORD} if [[ "$SERVICE_PASSWORD" == "$OS_PASSWORD" ]]; then echo "Using the OS_PASSWORD for the SERVICE_PASSWORD." >&2 fi echo ADMIN_ROLE $ADMIN_ROLE echo SERVICE_TENANT $SERVICE_TENANT echo SERVICE_PASSWORD $SERVICE_PASSWORD echo SERVICE_TOKEN $SERVICE_TOKEN DESIGNATE_USERNAME="designate" DESIGNATE_USERID=$(get_user $DESIGNATE_USERNAME) add_role $DESIGNATE_USERID $SERVICE_TENANT $ADMIN_ROLE $DESIGNATE_USERNAME DESIGNATE_SERVICE=$(get_service designate dns \ "Designate DNSaaS") API_URL=${API_URL:-http://localhost:9001/} add_endpoint $DESIGNATE_SERVICE $API_URL designate-2.0.0/tools/install_venv_common.py0000664000567000056710000001350712701406241022406 0ustar jenkinsjenkins00000000000000# Copyright 2013 OpenStack Foundation # Copyright 2013 IBM Corp. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """Provides methods needed by installation script for OpenStack development virtual environments. Since this script is used to bootstrap a virtualenv from the system's Python environment, it should be kept strictly compatible with Python 2.6. Synced in from openstack-common """ from __future__ import print_function import optparse import os import subprocess import sys class InstallVenv(object): def __init__(self, root, venv, requirements, test_requirements, py_version, project): self.root = root self.venv = venv self.requirements = requirements self.test_requirements = test_requirements self.py_version = py_version self.project = project def die(self, message, *args): print(message % args, file=sys.stderr) sys.exit(1) def check_python_version(self): if sys.version_info < (2, 6): self.die("Need Python Version >= 2.6") def run_command_with_code(self, cmd, redirect_output=True, check_exit_code=True): """Runs a command in an out-of-process shell. Returns the output of that command. Working directory is self.root. """ if redirect_output: stdout = subprocess.PIPE else: stdout = None proc = subprocess.Popen(cmd, cwd=self.root, stdout=stdout) output = proc.communicate()[0] if check_exit_code and proc.returncode != 0: self.die('Command "%s" failed.\n%s', ' '.join(cmd), output) return (output, proc.returncode) def run_command(self, cmd, redirect_output=True, check_exit_code=True): return self.run_command_with_code(cmd, redirect_output, check_exit_code)[0] def get_distro(self): if (os.path.exists('/etc/fedora-release') or os.path.exists('/etc/redhat-release')): return Fedora( self.root, self.venv, self.requirements, self.test_requirements, self.py_version, self.project) else: return Distro( self.root, self.venv, self.requirements, self.test_requirements, self.py_version, self.project) def check_dependencies(self): self.get_distro().install_virtualenv() def create_virtualenv(self, no_site_packages=True): """Creates the virtual environment and installs PIP. Creates the virtual environment and installs PIP only into the virtual environment. """ if not os.path.isdir(self.venv): print('Creating venv...', end=' ') if no_site_packages: self.run_command(['virtualenv', '-q', '--no-site-packages', self.venv]) else: self.run_command(['virtualenv', '-q', self.venv]) print('done.') else: print("venv already exists...") pass def pip_install(self, *args): self.run_command(['tools/with_venv.sh', 'pip', 'install', '--upgrade'] + list(args), redirect_output=False) def install_dependencies(self): print('Installing dependencies with pip (this can take a while)...') # First things first, make sure our venv has the latest pip and # setuptools and pbr self.pip_install('pip>=1.4') self.pip_install('setuptools') self.pip_install('pbr') self.pip_install('-r', self.requirements, '-r', self.test_requirements) def parse_args(self, argv): """Parses command-line arguments.""" parser = optparse.OptionParser() parser.add_option('-n', '--no-site-packages', action='store_true', help="Do not inherit packages from global Python " "install.") return parser.parse_args(argv[1:])[0] class Distro(InstallVenv): def check_cmd(self, cmd): return bool(self.run_command(['which', cmd], check_exit_code=False).strip()) def install_virtualenv(self): if self.check_cmd('virtualenv'): return if self.check_cmd('easy_install'): print('Installing virtualenv via easy_install...', end=' ') if self.run_command(['easy_install', 'virtualenv']): print('Succeeded') return else: print('Failed') self.die('ERROR: virtualenv not found.\n\n%s development' ' requires virtualenv, please install it using your' ' favorite package management tool' % self.project) class Fedora(Distro): """This covers all Fedora-based distributions. Includes: Fedora, RHEL, CentOS, Scientific Linux """ def check_pkg(self, pkg): return self.run_command_with_code(['rpm', '-q', pkg], check_exit_code=False)[1] == 0 def install_virtualenv(self): if self.check_cmd('virtualenv'): return if not self.check_pkg('python-virtualenv'): self.die("Please install 'python-virtualenv'.") super(Fedora, self).install_virtualenv() designate-2.0.0/tools/install_venv.py0000664000567000056710000000444512701406241021037 0ustar jenkinsjenkins00000000000000# Copyright 2010 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Copyright 2010 OpenStack Foundation # Copyright 2013 IBM Corp. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import os import sys import install_venv_common as install_venv # noqa def print_help(venv, root): help = """ Designate development environment setup is complete. Designate development uses virtualenv to track and manage Python dependencies while in development and testing. To activate the Designate virtualenv for the extent of your current shell session you can run: $ source %s/bin/activate Or, if you prefer, you can run commands in the virtualenv on a case by case basis by running: $ %s/tools/with_venv.sh """ print(help % (venv, root)) def main(argv): root = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) if os.environ.get('tools_path'): root = os.environ['tools_path'] venv = os.path.join(root, '.venv') if os.environ.get('venv'): venv = os.environ['venv'] pip_requires = os.path.join(root, 'requirements.txt') test_requires = os.path.join(root, 'test-requirements.txt') py_version = "python%s.%s" % (sys.version_info[0], sys.version_info[1]) project = 'Designate' install = install_venv.InstallVenv(root, venv, pip_requires, test_requires, py_version, project) options = install.parse_args(argv) install.check_python_version() install.check_dependencies() install.create_virtualenv(no_site_packages=options.no_site_packages) install.install_dependencies() print_help(venv, root) if __name__ == '__main__': main(sys.argv) designate-2.0.0/tools/pretty_flake8.py0000775000567000056710000001060712701406241021114 0ustar jenkinsjenkins00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. from __future__ import print_function import re import sys import linecache from prettytable import PrettyTable PEP8_LINE = r'^((?P.*):(?P\d*):(?P\d*):) ' \ '(?P(?P\w\d{1,3})(?P.*$))' HTML = True def main(): raw_errors = [] max_filename_len = 0 for line in sys.stdin: m = re.match(PEP8_LINE, line) if m: m = m.groupdict() raw_errors.append(m) if len(m['file']) > max_filename_len: max_filename_len = len(m['file']) else: print(line) if len(raw_errors) > 0: print('Flake8 Results') ct = PrettyTable([ "File", "Line", "Column", "Error Code", "Error Message", "Code" ]) ct.align["File"] = "l" ct.align["Error Message"] = "l" ct.align["Code"] = "l" for line in raw_errors: ct.add_row(format_dict(line)) print(ct) with open('flake8_results.html', 'w') as f: f.write('%s' % ct.get_html_string(attributes = {"cellspacing": 0})) # noqa def format_dict(raw): output = [] if raw['file'].startswith('./'): output.append(raw['file'][2:]) else: output.append(raw['file']) output.append(raw['line']) output.append(raw['col']) output.append(raw['error_code']) output.append(raw['error_desc'].lstrip()) code_string = linecache.getline( output[0], int(raw['line'])).lstrip().rstrip() output.append(code_string) return output if __name__ == '__main__': main() designate-2.0.0/tools/pretty_flake8.sh0000775000567000056710000000020412701406241021066 0ustar jenkinsjenkins00000000000000#!/bin/sh TESTARGS=$1 exec 3>&1 status=$(exec 4>&1 >&3; ( flake8 ; echo $? >&4 ) | python tools/pretty_flake8.py) && exit $status designate-2.0.0/tools/with_venv.sh0000775000567000056710000000033212701406241020320 0ustar jenkinsjenkins00000000000000#!/bin/bash TOOLS_PATH=${TOOLS_PATH:-$(dirname $0)} VENV_PATH=${VENV_PATH:-${TOOLS_PATH}} VENV_DIR=${VENV_NAME:-/../.venv} TOOLS=${TOOLS_PATH} VENV=${VENV:-${VENV_PATH}/${VENV_DIR}} source ${VENV}/bin/activate && "$@" designate-2.0.0/tools/mysql_pending_notify_bench/0000775000567000056710000000000012701406373023360 5ustar jenkinsjenkins00000000000000designate-2.0.0/tools/mysql_pending_notify_bench/README0000664000567000056710000000611412701406241024234 0ustar jenkinsjenkins00000000000000 A simple benchmark was run on 2015-11-24 to measure the effectiveness of adding an index on pending_notify $ sudo ./runner Creating DB and table Populating non-pending rows Populating pending rows +-----------+ | COUNT(id) | +-----------+ | 5000 | +-----------+ +-----------+ | COUNT(id) | +-----------+ | 200000 | +-----------+ Without any index +----+-------------+-------+------+---------------+------+---------+------+--------+-----------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+--------+-----------------------------+ | 1 | SIMPLE | zones | ALL | NULL | NULL | NULL | NULL | 204013 | Using where; Using filesort | +----+-------------+-------+------+---------------+------+---------+------+--------+-----------------------------+ Benchmark Average number of seconds to run all queries: 0.137 seconds Minimum number of seconds to run all queries: 0.122 seconds Maximum number of seconds to run all queries: 0.158 seconds Number of clients running queries: 3 Average number of queries per client: 1 With pending_notify index +----+-------------+-------+------+--------------------+--------------------+---------+-------+------+-----------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+--------------------+--------------------+---------+-------+------+-----------------------------+ | 1 | SIMPLE | zones | ref | pending_notify_idx | pending_notify_idx | 2 | const | 4999 | Using where; Using filesort | +----+-------------+-------+------+--------------------+--------------------+---------+-------+------+-----------------------------+ Benchmark Average number of seconds to run all queries: 0.012 seconds Minimum number of seconds to run all queries: 0.010 seconds Maximum number of seconds to run all queries: 0.019 seconds Number of clients running queries: 3 Average number of queries per client: 1 With created_at and pending_notify index +----+-------------+-------+------+--------------------+--------------------+---------+-------+------+-----------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+--------------------+--------------------+---------+-------+------+-----------------------------+ | 1 | SIMPLE | zones | ref | pending_notify_idx | pending_notify_idx | 2 | const | 4999 | Using where; Using filesort | +----+-------------+-------+------+--------------------+--------------------+---------+-------+------+-----------------------------+ Benchmark Average number of seconds to run all queries: 0.012 seconds Minimum number of seconds to run all queries: 0.010 seconds Maximum number of seconds to run all queries: 0.018 seconds Number of clients running queries: 3 Average number of queries per client: 1 designate-2.0.0/tools/mysql_pending_notify_bench/runner0000775000567000056710000000456412701406241024622 0ustar jenkinsjenkins00000000000000#!/bin/bash # # Copyright 2015 Hewlett-Packard Development Company, L.P. # Licensed under the Apache License, Version 2.0, see LICENSE file echo "Creating DB and table" mysql < /dev/null # warmup mysql mysqlslap -e "EXPLAIN $query" mysqlslap -C --iterations=100 --concurrency 3 --query "$query" } populate 5000 200000 # mysql mysqlslap -e "$query" echo "Without any index" run_bench echo "With pending_notify index" mysql mysqlslap -e "CREATE INDEX pending_notify_idx ON zones (pending_notify);" run_bench echo "With created_at and pending_notify index" mysql mysqlslap -e "CREATE INDEX created_at_idx ON zones (created_at);" run_bench echo "Drop DB" mysql -e "DROP DATABASE mysqlslap" designate-2.0.0/doc/0000775000567000056710000000000012701406373015365 5ustar jenkinsjenkins00000000000000designate-2.0.0/doc/source/0000775000567000056710000000000012701406373016665 5ustar jenkinsjenkins00000000000000designate-2.0.0/doc/source/backends/0000775000567000056710000000000012701406373020437 5ustar jenkinsjenkins00000000000000designate-2.0.0/doc/source/backends/bind9.rst0000664000567000056710000000356212701406243022200 0ustar jenkinsjenkins00000000000000.. Copyright 2013 Hewlett-Packard Development Company, L.P. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Bind9 Backend ============= This page documents using the Pool Manager Bind 9 backend. The backend uses the rndc utility to create and delete zones remotely. The traffic between rndc and Bind is authenticated with a key. Designate Configuration ----------------------- Example configuration required for Bind9 operation. One section for each pool target .. code-block:: ini [pool_target:f26e0b32-736f-4f0a-831b-039a415c481e] options = rndc_host: 192.168.27.100, rndc_port: 953, rndc_config_file: /etc/bind/rndc.conf, rndc_key_file: /etc/bind/rndc.key, port: 53, host: 192.168.27.100, clean_zonefile: false masters = 192.168.27.100:5354 type = bind9 The key and config files are relative to the host running Pool Manager (and can be different from the hosts running Bind) Bind9 Configuration ------------------- Ensure Bind can access the /etc/bind/rndc.conf and /etc/bind/rndc.key files and receive rndc traffic from Pool Manager. Enable rndc addzone/delzone functionality by editing named.conf.options or named.conf and add this line under options .. code-block:: c allow-new-zones yes; Example configuration of /etc/bind/rndc.key .. code-block:: c key "rndc-key" { algorithm hmac-md5; secret ""; }; designate-2.0.0/doc/source/backends/powerdns.rst0000664000567000056710000000756012701406243023036 0ustar jenkinsjenkins00000000000000.. Copyright 2013 Hewlett-Packard Development Company, L.P. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. .. _backend-powerdns: PowerDNS Backend ================ Designate Configuration ----------------------- =============================== ====================================== ============================================================== Parameter Default Note =============================== ====================================== ============================================================== domain_type NATIVE PowerDNS Domain Type also_notify [] List of additional IPs to send NOTIFYs to. connection sqlite:///$pystatepath/powerdns.sqlite Database connection string connection_debug 0 Verbosity of SQL debugging information. 0=None, 100=Everything connection_trace False Add python stack traces to SQL as comment strings idle_timeout 3600 timeout before idle sql connections are reaped max_retries 10 maximum db connection retries during startup. (setting -1 implies an infinite retry count) retry_interval 10 interval between retries of opening a sql connection mysql_engine InnoDB MySQL engine to use sqlite_synchronous True If passed, use synchronous mode for sqlite =============================== ====================================== ============================================================== PowerDNS Configuration ---------------------- You need to configure PowerDNS to use the MySQL backend. 1. First enable the MySQL backend: .. code-block:: ini launch = gmysql 2. Configure the MySQL database settings:: .. code-block:: ini gmysql-host= gmysql-port= gmysql-dbname= gmysql-user= gmysql-password= gmysql-dnssec=yes #gmysql-socket= .. note:: PowerDNS can connect via socket or host/port. 3. Configure the options for designate-central - specifically "connection" to point to your MySQL database .. code-block:: ini [backend:powerdns] connection = mysql+pymysql://:@:/ 4. Setup the database schema. .. code-block:: console $ designate-manage powerdns init $ designate-manage powerdns sync 5. Restart PowerDNS and it should be ready to serve queries using the MySQL database as the backing store. PowerDNS deployment as hidden Master ------------------------------------ One deployment scenario can be that the PowerDNS backend will be used as a "hidden" Master DNS for other DNS servers to consume via AXFR. Say you have 10.0.0.1 and 10.0.0.2 as slaves then configure the backend as follows in addition to other options .. code-block:: ini [backend:powernds] domain_type = MASTER also_notify = 10.0.0.1,10.0.0.2 .. note:: This should mostly be used in connection with another backend acting as slave. designate-2.0.0/doc/source/backends/infoblox.rst0000664000567000056710000001054312701406243023010 0ustar jenkinsjenkins00000000000000.. Copyright 2015 Infoblox, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Infoblox Backend ================ Provides an integration between Designate and Infoblox grids. Features -------- The Infoblox Designate backend allows an Infoblox grid to be used for serving zones controlled by OpenStack Designate. The Infoblox backend may be setup to map a specific Designate pool to a single DNS view, or it may be setup to map individual tenants to per-tenant DNS views. Infoblox Configuration ---------------------- * Create a user for use by Designate. * Set up one or more name server groups to be used to serve Designate zones. * Set the Designate mDNS servers as external primaries * Add a grid member as a grid secondary; select the "Lead Secondary" option for this member * Add additional grid secondaries as desired Designate Backend Configuration ------------------------------- * Designate may be configured to talk to any number of grid API service points (GM or Cloud appliance). * Setup a pool for each combination of DNS view and nameserver group you wish to manage. * Setup a pool target for each API service point that Designate should talk to. * A single Designate pool should point to only one API service point in any single grid. That is, do not point a pool at more than one API service point in the same grid. * It is OK to point a pool at multiple grids, just not to multiple service points on the same grid. * You may specify the DNS view and nameserver group on a per-target basis. * The ``[infoblox:backend]`` stanza in the designate configuration file can be used to set default values for the grid connectivity and other information. * These values can be overridden on a per-target basis with the "options" element of the target configuration. * Set the mDNS port to 53 in the ``[service:mdns]`` stanza. * Designate always puts any servers associated with the pool as NS records for the domain. So, if you wish for any Infoblox nameservers to be listed in NS records, they must be added via Designate. *Example Designate Configuration* .. code-block:: ini [pool:794ccc2c-d751-44fe-b57f-8894c9f5c842] #Specify the API service points for each grid targets = f26e0b32-736f-4f0a-831b-039a415c481e # Specify the lead secondary servers configured in the NS groups # for each target. nameservers = ffedb95e-edc1-11e4-9ae6-000c29db281b [pool_target:f26e0b32-736f-4f0a-831b-039a415c481e] type = infoblox # wapi_url, username, password can all be overridden from the defaults # allowing targets to point to different grids options = dns_view: default, ns_group: Designate [pool_nameserver:ffedb95e-edc1-11e4-9ae6-000c29db281b] host=172.16.98.200 port=53 [backend:infoblox] # The values below will be used for all targets unless overridden # in the target configuration. http_* options may only be set here, # not at the target level. http_pool_maxsize = 100 http_pool_connections = 100 wapi_url = https://172.16.98.200/wapi/v2.1/ sslverify = False password = infoblox username = admin multi_tenant = False Multi-tenant Configuration -------------------------- When configured with ``multi_tenant = True`` in the designate.conf file, the DNS view will be chosen as follows: * A search will be made for a network view with the EA "TenantID", with the value of the OpenStack tenant_id. * If found, then then DNS view used will be ., where is the value specified in designate.conf, and is the name of the view found in the search. * If no such network view is found, then a network view will be created with the name ., where is the value specified in designate.conf. This network view will be tagged with the TenantID EA. * If the DNS view does not exist (in either case above), then it will be created. designate-2.0.0/doc/source/index.rst0000664000567000056710000000312012701406243020516 0ustar jenkinsjenkins00000000000000Designate, a DNSaaS component for OpenStack =========================================== Designate provides DNSaaS services for OpenStack: * REST API for domain & record management * Multi-tenant * Integrated with Keystone for authentication * Framework in place to integrate with Nova and Neutron notifications (for auto-generated records) * Support for PowerDNS and Bind9 out of the box This document describes Designate for users & contributors of the project. This documentation is generated by the Sphinx toolkit and lives in the `source tree`_. Additional documentation on Designate may also be found on the `OpenStack wiki`_. Install Guides ============== .. toctree:: :maxdepth: 1 :glob: install/* Upgrade Guides ============== .. toctree:: :maxdepth: 1 :glob: upgrade/* How To Guides ============= .. toctree:: :maxdepth: 1 :glob: howtos/* Reference Documentation ======================= .. toctree:: :maxdepth: 1 architecture getting-involved developer-guidelines production-guidelines production-architecture configuration rest devstack related glossary backends integrations functional-tests gmr support-matrix pools Source Documentation ==================== .. toctree:: :maxdepth: 3 api backend central mdns objects quota sink storage Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` .. _OpenStack Wiki: https://wiki.openstack.org/wiki/Designate .. _source tree: https://git.openstack.org/cgit/openstack/designate designate-2.0.0/doc/source/upgrade/0000775000567000056710000000000012701406373020314 5ustar jenkinsjenkins00000000000000designate-2.0.0/doc/source/upgrade/kilo.rst0000664000567000056710000000263312701406241022002 0ustar jenkinsjenkins00000000000000.. Copyright 2015 Hewlett-Packard Development Company, L.P. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. *************************** Upgrading to Kilo form Juno *************************** .. note:: This doc section is a work in progress, for now, we have some smaller hints and tips for watchout for during the upgrade. Tips and Tricks =============== 1. Two new Designate services Two new Designate services were added in Kilo, designate-pool-manager and designate-mdns. Please ensure to configure and enable these services as part of the upgrade. 2. Post-Migration, existing DNS domains hosted by PowerDNS must have their "masters" column manually populated with the list of designate-mdns ip and port pairs, and their type switched to SECONDARY. For example: .. code-block:: ruby UPDATE powerdns.domains SET type = "SECONDARY", masters = "192.0.2.1:5354,192.0.2.2:5354" WHERE masters IS NULL; designate-2.0.0/doc/source/upgrade/mitaka.rst0000664000567000056710000000564712701406241022322 0ustar jenkinsjenkins00000000000000.. Copyright 2016 Hewlett Packard Enterprise Development Company, L.P. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ******************************** Upgrading to Mitaka from Liberty ******************************** .. note:: This is a WIP - it will be updated as more items are added to Mitaka Pools Configuration =================== We have updated how the config data for pools is now stored. Previously there was a mix of content in the ``designate.conf`` file and in the designate database. We have moved all of the data to the database in Mitaka, to avoid confusion, and avoid the massive complexity that exists in the config file. .. warning:: This part of the upgrade **requires** downtime. We have 2 new commands in the ``designate-manage`` utility that are able to assist the migration. To make the config syntax simpler we have a new YAML based config file that is used to load information into the database. .. literalinclude:: ../../../etc/designate/pools.yaml.sample :language: yaml We have a command that will allow you to take your current running config, and export it to the new YAML format. .. note:: You will need to have at least one instance of central running, and machine ``designate-manage`` is running on will need access to the messageing queue .. code-block:: console designate-manage pool generate_file --file output.yml This will create a YAML file, with all the currently defined pools, and all of their config. We suggest this is then migrated into a config management system, or other document management system. From this point on all updated to pools should be one by updating this file, and running: .. code-block:: console designate-manage pool update --file /path/to/file.yml Pools - Step by Step -------------------- 1. Ensure there is not 2 pools with the same name. 2. Stop all Designate Services. 3. Deploy new Mitaka code 4. Start ``designate-central`` 5. Run .. code-block:: console designate-manage pool export_from_config --file output.yml 6. Ensure the output file is correct (reference sample file for each value) 7. Run .. code-block:: console designate-manage pool update --file output.yml --dry_run True --delete True 8. Ensure the output of this command is not removing any Pools 9. Run .. code-block:: console designate-manage pool generate_file --file output.yml --delete True 10. Start the remaining designate services. designate-2.0.0/doc/source/glossary.rst0000664000567000056710000000725112701406241021261 0ustar jenkinsjenkins00000000000000.. Copyright 2012 Endre Karlson for Bouvet ASA Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ============ Glossary ============ .. glossary:: agent The Agent would be a standalone service that acts as a sort of mirror to mdns. It would receive AXFR/IXFR, NOTIFYs, and other notifications and perform changes to a DNS server through a plugin-style backend. The agent is intended for deployments that may not be able to use mdns as a true DNS Master. api HTTP REST API service for Designate central Software service running on a central management node that stores information persistently in a backend storage using a configurable driver like SQLAlchemy or other. mdns Also known as mini dns. This is a dns server with limited capabilities like NOTIFY's, AXFR's and record queries. The pool manager uses mdns to transfer data to/from the pool servers. mq A message queue, typically something like RabbitMQ or ZeroMQ name server A FQDN (or IP, but usually a FQDN) that is used to populate the NS Records of a Designate Managed Zone. Each Pool will have a set of Name Servers, which users then delegate to from their registrar. node A server, physical or virtual, running some aspect of the designate system. pool A collection of pool servers sharing similar attributes. Different pools could have different capabilities - such as GeoIP / Round Robin DNS / Anycast. pool manager This is a service that is responsible for notifying pool servers of the changes that have occurred. It also updates central once the changes are live on the pool servers. pool manager backend A backend is used by the pool manager to transfer the data from storage to name servers. There are backends that support PowerDNS, BIND, & NSD. pool server The DNS servers that are updated by the pool manager. These need not be the same as the name servers. When they are different a mechanism outside of designate is needed to ensure the data on pool servers is consistent with that on the name servers. private pool A pool of ‘private’ DNS servers. These servers would typically allow non standard TLDs (.dev , .local etc), and may not have the same level of blacklist restrictions. They would be aimed at people with Neutron Networking, and VPC style set ups, where access to the DNS server would come from trusted networks (E.G. in-cloud - owned instances, and onsite resources connect by VPN) This would allow customers to set DNS entries for internal servers, on domains that would not be available on the public pools, and have them accessible by internal users secondary zone A zone within Designate that has external Masters. sink Optional Software Service that is configured to listen to events from the Nova or Neutron event queue and use the central service to generate simple A records for instances as they are created, and delete A records as they are deleted. storage A backend for storing data/information persistently. Typically MongoDB or a SQL based server software. designate-2.0.0/doc/source/devstack.rst0000664000567000056710000001120412701406241021213 0ustar jenkinsjenkins00000000000000.. Copyright 2013 Hewlett-Packard Development Company, L.P. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. .. _devstack: ======== DevStack ======== The Designate team maintains a fork of devstack with Designate integration. Instructions ++++++++++++ .. note:: If you want to use local sources for development then you should consider using the contrib/vagrant folder in the `repository `_. 1. Get a clean Ubuntu 14.04 VM. DevStack "takes over". Don't use your desktop! 2. Clone DevStack inside the VM:: $ git clone https://git.openstack.org/openstack-dev/devstack.git 3. Move to ``devstack`` directory:: $ cd devstack 4. Create a `local.conf` config file: .. literalinclude:: ../../contrib/vagrant/local.conf :language: bash 5. Run DevStack:: $ ./stack.sh 6. Enter the screen sessions "shell" window:: $ ./rejoin-stack.sh Then press Ctrl+A followed by 0 7. Load credentials into the shell:: $ source openrc admin admin # For the admin user, admin tenant $ source openrc admin demo # For the admin user, demo tenant $ source openrc demo demo # For the demo user, demo tenant 8. Try out the designate client:: $ designate domain-create --name example.net. --email kiall@hp.com +------------+--------------------------------------+ | Field | Value | +------------+--------------------------------------+ | name | example.net. | | created_at | 2013-07-12T13:36:03.110727 | | updated_at | None | | id | 1fb5d17c-efaf-4e3c-aac0-482875d24b3e | | ttl | 3600 | | serial | 1373636163 | | email | kiall@hp.com | +------------+--------------------------------------+ $ designate record-create 1fb5d17c-efaf-4e3c-aac0-482875d24b3e --type A --name www.example.net. --data 127.0.0.1 +------------+--------------------------------------+ | Field | Value | +------------+--------------------------------------+ | name | www.example.net. | | data | 127.0.0.1 | | created_at | 2013-07-12T13:39:51.236025 | | updated_at | None | | id | d50c21d0-a13c-48e2-889e-0b9852a05acb | | priority | None | | ttl | None | | type | A | | domain_id | 1fb5d17c-efaf-4e3c-aac0-482875d24b3e | +------------+--------------------------------------+ $ designate record-list 1fb5d17c-efaf-4e3c-aac0-482875d24b3e +--------------------------------------+------+------------------+ | id | type | name | +--------------------------------------+------+------------------+ | d50c21d0-a13c-48e2-889e-0b9852a05acb | A | www.example.net. | +--------------------------------------+------+------------------+ $ designate record-get 1fb5d17c-efaf-4e3c-aac0-482875d24b3e d50c21d0-a13c-48e2-889e-0b9852a05acb +------------+--------------------------------------+ | Field | Value | +------------+--------------------------------------+ | name | www.example.net. | | data | 127.0.0.1 | | created_at | 2013-07-12T13:39:51.000000 | | updated_at | None | | id | d50c21d0-a13c-48e2-889e-0b9852a05acb | | priority | None | | ttl | None | | type | A | | domain_id | 1fb5d17c-efaf-4e3c-aac0-482875d24b3e | +------------+--------------------------------------+ designate-2.0.0/doc/source/configuration.rst0000664000567000056710000000174112701406241022263 0ustar jenkinsjenkins00000000000000.. Copyright 2012 Endre Karlson for Bouvet ASA Copyright 2012 New Dream Network, LLC (DreamHost) Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. .. |br| raw:: html
.. _configuration: ======================= Configuration Options ======================= We provide a sample configuration file in `etc/designate/designate.conf.sample` The majority of the options are OK to be left as default values, but may need to be tweaked depending on your deployment. designate-2.0.0/doc/source/support-matrix.ini0000664000567000056710000000732612701406243022410 0ustar jenkinsjenkins00000000000000# Copyright 2015 Hewlett-Packard Development Company, L.P. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. # # # # ============================================== # Designate DNS Driver Feature Capability Matrix # ============================================== # # The 'status' field takes possible values # # - mandatory - unconditionally required to be implemented # - optional - optional to support, nice to have # - choice(group) - at least one of the options within the named group # must be implemented # - conditional(cond) - required, if the referenced condition is met. # # The value against each 'driver-impl-XXXX' entry refers to the level # of the implementation of the feature in that driver # # - complete - fully implemented, expected to work at all times # - partial - implemented, but with caveats about when it will work # eg some configurations or hardware or guest OS may not # support it # - missing - not implemented at all [DEFAULT] repository=Designate Repository maintainers=Designate Team notes=None type=xfr in-tree=True [backends] backend-impl-bind9=Bind9 backend-impl-powerdns-mysql=Power DNS (MySQL) backend-impl-powerdns-pgsql=Power DNS (pgSQL) backend-impl-dynect=DynECT backend-impl-akamai=Akamai eDNS backend-impl-msdns=Microsoft DNS Server backend-impl-infoblox-xfr=Infoblox (XFR) backend-impl-nsd4=NSD4 backend-impl-agent=Agent backend-impl-bind9-agent=Bind9 (Agent) backend-impl-denominator=Denominator [backends.backend-impl-bind9] [backends.backend-impl-powerdns-mysql] [backends.backend-impl-powerdns-pgsql] status=untested [backends.backend-impl-dynect] maintainers=HP DNSaaS Team [backends.backend-impl-akamai] maintainers=HP DNSaaS Team [backends.backend-impl-agent] [backends.backend-impl-bind9-agent] type=agent [backends.backend-impl-infoblox-xfr] status=release-compatible maintainers=Infoblox OpenStack Team [backends.backend-impl-nsd4] [backends.backend-impl-denominator] type=agent [backends.backend-impl-msdns] in-tree=False status=untested repository=https://git.openstack.org/openstack/designate-msdnsagent maintainers=Graham Hayes [grades] valid-grades=integrated,master-compatible,release-compatible,untested,failing,known-broken [grades.integrated] title=Integrated notes=Tested on every commit by the OpenStack CI Infrastructure, and maintained by designate developers as a reference backend in-tree=True [grades.master-compatible] title=Master Compatible notes=Tested on every commit by 3rd party testing, and has a person or group dedicated to maintaining compatibility on a regular basis in-tree=optional [grades.release-compatible] title=Release Compatible notes=Not necessarily tested on every commit, but has a maintainer committed to ensuring compatibility for each release in-tree=optional [grades.untested] title=Untested notes=All other backends in the designate repository in-tree=optional [grades.failing] title=Failing notes=Backends that were previously "Compatible", but tests are now failing on a regular basis. in-tree=optional [grades.known-broken] title=Known Broken notes=Backends that do not work, and have been broken with no sign of any fixes in-tree=optional designate-2.0.0/doc/source/pools.rst0000664000567000056710000000703012701406243020547 0ustar jenkinsjenkins00000000000000.. Copyright 2016 Hewlett Packard Enterprise Development Company LP Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. .. _pools: ===== Pools ===== Contents: .. toctree:: :maxdepth: 2 :glob: pools/scheduler Overview ======== In designate we support the concept of multiple "pools" of DNS Servers. This allows operators to scale out their DNS Service by adding more pools, avoiding the scalling problems that some DNS servers have for number of zones, and the total number of records hosted by a single server. This also allows providers to have tiers of service (i.e. the difference between GOLD vs SILVER tiers may be the number of DNS Servers, and how they are distributed around the world.) In a private cloud situation, it allows operators to separate internal and external facing zones. To help users create zones on the correct pool we have a "scheduler" that is responsible for examining the zone being created and the pools that are availible for use, and matching the zone to a pool. The filters are plugable (i.e. operator replaceable) and all follow a simple interface. The zones are matched using "zone attributes" and "pool attributes". These are key: value pairs that are attached to the zone when it is being created, and the pool. The pool attributes can be updated by the operator in the future, but it will **not** trigger zones to be moved from one pool to another. .. note:: Currently the only zone attribute that is accepted is the `pool_id` attribute. As more filters are merged there will be support for dynamic filters. Managing Pools ============== In mitaka we moved the method of updating pools to a CLI in `designate-manage` There is a YAML file that defines the pool, and is used to load this information into the database. .. literalinclude:: ../../etc/designate/pools.yaml.sample :language: yaml Designate Manage Pools Command Reference ---------------------------------------- Update Pools Information ^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: language designate-manage pool update [options] Options: """""""" --file Input file (Default: ``/etc/designate/pools.yaml``) --dry_run Simulate an update. (Default: False) --delete Delete Pools that are not in the input file (Defaults: False) .. warning:: | Running with ``--delete True`` can be **extremely** dangerous. | It will delete any pools that are not in the supplied YAML file, and any | zones that are in that Pool. | Before running with ``--delete True`` we recommend operators run with | ``--delete True --dry_run True`` to view the outcome. Generate YAML File ^^^^^^^^^^^^^^^^^^ .. code-block:: language designate-manage pool generate_file [options] Options: """""""" --file YAML file output too (Default: ``/etc/designate/pools.yaml``) Generate YAML File from Liberty Config ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: language designate-manage pool export_from_config [options] Options: """""""" --file YAML file output too (Default: ``/etc/designate/pools.yaml``) designate-2.0.0/doc/source/rest/0000775000567000056710000000000012701406373017642 5ustar jenkinsjenkins00000000000000designate-2.0.0/doc/source/rest/admin/0000775000567000056710000000000012701406373020732 5ustar jenkinsjenkins00000000000000designate-2.0.0/doc/source/rest/admin/quotas.rst0000664000567000056710000000716212701406241023000 0ustar jenkinsjenkins00000000000000.. Copyright (c) 2014 Rackspace Hosting All Rights Reserved. Author: Jordan Cazamias Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Quotas ====== Overview -------- The quotas extension can be used to retrieve a tenant's absolute limits. *Note*: Quotas is an extension and needs to be enabled before it can be used. If Designate returns a 404 error, ensure that the following line has been added to the designate.conf file under "[service:api]" section :: enable_api_admin = True enabled_extensions_admin = quotas Once these lines have been added, restart the designate-central and designate-api services. Get Quotas ---------- .. http:get:: /quotas/TENANT_ID Retrieves quotas for tenant with the specified TENANT_ID. The following example retrieves the quotas for tenant 12345. **Example request:** .. sourcecode:: http GET /admin/quotas/12345 HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json **Example response:** .. sourcecode:: http HTTP/1.1 201 Created Content-Type: application/json { "quota": { "api_export_size: 1000, "zones": 10, "recordset_records": 20, "zone_records": 500, "zone_recordsets": 500 } } :api_export_size: Number of records allowed in a synchronous zone export done via API :form zones: Number of zones the tenant is allowed to own :form recordset_records: Number of records allowed per recordset :form zone_records: Number of records allowed per zone :form zone_recordsets: Number of recordsets allowed per zone :statuscode 200: Success :statuscode 401: Access Denied Update Quotas ------------- .. http:patch:: /quotas/TENANT_ID Updates the specified quota(s) to their new values. **Example request:** .. sourcecode:: http PATCH /admin/quotas/12345 HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json { "quota": { "zones": 1000, "zone_records": 50 } } **Example response:** .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json { "quota": { "api_export_size: 1000, "zones": 1000, "recordset_records": 20, "zone_records": 50, "zone_recordsets": 500 } } :statuscode 200: Success :statuscode 401: Access Denied Reset Quotas to Default ----------------------- .. http:delete:: /quotas/TENANT_ID Restores the tenant's quotas back to their default values. **Example request:** .. sourcecode:: http DELETE /admin/quotas/12345 HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json **Example response:** .. sourcecode:: http HTTP/1.1 204 No Content :statuscode 204: No Content :statuscode 401: Access Denied designate-2.0.0/doc/source/rest/v2/0000775000567000056710000000000012701406373020171 5ustar jenkinsjenkins00000000000000designate-2.0.0/doc/source/rest/v2/collections.rst0000664000567000056710000004005412701406243023240 0ustar jenkinsjenkins00000000000000.. Copyright 2014 Rackspace Hosting Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. .. Collections =========== The following conventions apply to all collections, unless otherwise noted below. Links ----- A links object will exist at the root of all Collection responses. At the minimum, it will contain a "self" link. If the collection resultset is not complete, a "next" link will be included for pagination. **Request:** .. sourcecode:: http GET /v2/zones?limit=2 HTTP/1.1 Host: dns.provider.com Accept: application/json **Response:** .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json { "zones": [{ "status": "ACTIVE", "description": null, "updated_at": "2014-07-08T20:28:31.000000", "ttl": 86400, "serial": 1404851315, "id": "a4e29ed3-d7a4-4e4d-945d-ce64678d3b94", "name": "example.com.", "created_at": "2014-07-08T20:28:19.000000", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "version": 1, "project_id": "noauth-project", "email": "hostmaster@example.com", "links": { "self": "http://dns.provider.com/v2/zones/a4e29ed3-d7a4-4e4d-945d-ce64678d3b94" } }, { "status": "ACTIVE", "description": null, "updated_at": null, "ttl": 3600, "serial": 1405435099, "id": "13db810b-917d-4898-bc28-4d4ee370d20d", "name": "abc.example.com.", "created_at": "2014-07-15T14:38:19.000000", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "version": 1, "project_id": "noauth-project", "email": "hostmaster@example.com", "links": { "self": "http://dns.provider.com/v2/zones/13db810b-917d-4898-bc28-4d4ee370d20d" } }], "links": { "self": "https://dns.provider.com/v2/zones?limit=2", "next": "https://dns.provider.com/v2/zones?limit=2&marker=13db810b-917d-4898-bc28-4d4ee370d20d" } } Pagination and Sorting ---------------------- Pagination is available on all collections and is controlled using a combination of four optional query parameters: * `marker` - denotes the ID of the last item in the previous list. * `limit` - use to set the maximum number of items per page, use "max" to return the upper limit of results as defined by the operator. If not supplied, the default per page limit as defined by the operator will be used. * `sort_key` - sorts the results by the specified attribute * By default, elements will be sorted by their creation date. * `sort_dir` - determines whether sorted results are displayed in ascending or descending order. * If explicitly used, the value of sort_dir must be either 'asc' or 'desc'. Otherwise, the default is 'asc'. To navigate the collection, the parameters limit and marker can be set in the URI (e.g.?limit=100&marker=). Items are sorted, as a default, by create time in ascending order. Collection responses will include a `links` object containing absolute URLs for the current and next page. These links may be omitted, or null, at the edges of a paginated collection. The following example takes a collection of zones and sorts it in descending order, using ID as the sort key rather than creation date. **Request:** .. sourcecode:: http GET /v2/zones?sort_key=id&sort_dir=desc HTTP/1.1 Host: dns.provider.com Accept: application/json **Response:** .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json { "zones": [{ "status": "ACTIVE", "description": null, "updated_at": null, "ttl": 3600, "serial": 1405435156, "id": "c316def0-8599-4030-9dcd-2ce566348115", "name": "abc.example.net.", "created_at": "2014-07-15T14:39:16.000000", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "version": 1, "project_id": "noauth-project", "email": "hostmaster@example.net", "links": { "self": "http://dns.provider.com/v2/zones/c316def0-8599-4030-9dcd-2ce566348115" } }, { "status": "ACTIVE", "description": null, "updated_at": "2014-07-08T20:28:31.000000", "ttl": 86400, "serial": 1404851315, "id": "a4e29ed3-d7a4-4e4d-945d-ce64678d3b94", "name": "example.com.", "created_at": "2014-07-08T20:28:19.000000", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "version": 1, "project_id": "noauth-project", "email": "hostmaster@example.com", "links": { "self": "http://dns.provider.com/v2/zones/a4e29ed3-d7a4-4e4d-945d-ce64678d3b94" } }, { "status": "ACTIVE", "description": null, "updated_at": null, "ttl": 3600, "serial": 1405435142, "id": "38dbf635-45cb-4873-8300-6c273f0283c7", "name": "example.org.", "created_at": "2014-07-15T14:39:02.000000", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "version": 1, "project_id": "noauth-project", "email": "hostmaster@example.org", "links": { "self": "http://dns.provider.com/v2/zones/38dbf635-45cb-4873-8300-6c273f0283c7" } }, { "status": "ACTIVE", "description": null, "updated_at": null, "ttl": 3600, "serial": 1405435099, "id": "13db810b-917d-4898-bc28-4d4ee370d20d", "name": "abc.example.com.", "created_at": "2014-07-15T14:38:19.000000", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "version": 1, "project_id": "noauth-project", "email": "hostmaster@example.com", "links": { "self": "http://dns.provider.com/v2/zones/13db810b-917d-4898-bc28-4d4ee370d20d" } }], "links": { "self": "https://dns.provider.com/v2/zones?sort_key=id&sort_dir=desc" } } This example takes the previously sorted list and displays only the middle two resources. .. sourcecode:: http GET /v2/zones?sort_key=id&sort_dir=desc&marker=c316def0-8599-4030-9dcd-2ce566348115&limit=2 HTTP/1.1 Host: dns.provider.com Accept: application/json **Response:** .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json { "zones": [{ "status": "ACTIVE", "description": null, "updated_at": "2014-07-08T20:28:31.000000", "ttl": 86400, "serial": 1404851315, "id": "a4e29ed3-d7a4-4e4d-945d-ce64678d3b94", "name": "example.com.", "created_at": "2014-07-08T20:28:19.000000", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "version": 1, "project_id": "noauth-project", "email": "hostmaster@example.com", "links": { "self": "http://dns.provider.com/v2/zones/a4e29ed3-d7a4-4e4d-945d-ce64678d3b94" } }, { "status": "ACTIVE", "description": null, "updated_at": null, "ttl": 3600, "serial": 1405435142, "id": "38dbf635-45cb-4873-8300-6c273f0283c7", "name": "example.org.", "created_at": "2014-07-15T14:39:02.000000", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "version": 1, "project_id": "noauth-project", "email": "hostmaster@example.org", "links": { "self": "http://dns.provider.com/v2/zones/38dbf635-45cb-4873-8300-6c273f0283c7" } }], "links": { "self": "https://dns.provider.com/v2/zones?sort_key=id&sort_dir=desc&marker=c316def0-8599-4030-9dcd-2ce566348115&limit=2", "next": "https://dns.provider.com/v2/zones?sort_key=id&sort_dir=desc&limit=2&marker=38dbf635-45cb-4873-8300-6c273f0283c7" } } Filtering --------- Filtering is available on all collections and is controlled using query parameters which match the name of the attribute being filtered. It is *not* required that all attributes are available as filter targets, but the majority will be. Currently, the following attributes support filtering: * **Blacklists**: pattern * **Recordsets**: name, type, ttl, data, description, status * **TLDs**: name * **Zones**: name, email, ttl, description, status Filters can be an exact match search or a wildcard search. Currently, wildcard search is supported using the '*' character. The following example takes a collection of zones and filters it by the "name" parameter. **Request:** .. sourcecode:: http GET /v2/zones?name=example.com. HTTP/1.1 Host: dns.provider.com Accept: application/json **Response:** .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json { "zones": [{ "status": "ACTIVE", "description": null, "updated_at": "2014-07-08T20:28:31.000000", "ttl": 86400, "serial": 1404851315, "id": "a4e29ed3-d7a4-4e4d-945d-ce64678d3b94", "name": "example.com.", "created_at": "2014-07-08T20:28:19.000000", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "version": 1, "project_id": "noauth-project", "email": "hostmaster@example.com", "links": { "self": "http://dns.provider.com/v2/zones/a4e29ed3-d7a4-4e4d-945d-ce64678d3b94" } }], "links": { "self": "https://dns.provider.com/v2/zones?name=example.com." } } Wildcards can be placed anywhere within the query. The following example demonstrates the use of wildcards on the right side of a query: **Request:** .. sourcecode:: http GET /v2/zones?name=example* HTTP/1.1 Host: dns.provider.com Accept: application/json **Response:** .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json { "zones": [{ "status": "ACTIVE", "description": null, "updated_at": "2014-07-08T20:28:31.000000", "ttl": 86400, "serial": 1404851315, "id": "a4e29ed3-d7a4-4e4d-945d-ce64678d3b94", "name": "example.com.", "created_at": "2014-07-08T20:28:19.000000", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "version": 1, "project_id": "noauth-project", "email": "hostmaster@example.com", "links": { "self": "http://dns.provider.com/v2/zones/a4e29ed3-d7a4-4e4d-945d-ce64678d3b94" } }, { "status": "ACTIVE", "description": null, "updated_at": null, "ttl": 3600, "serial": 1405435142, "id": "38dbf635-45cb-4873-8300-6c273f0283c7", "name": "example.org.", "created_at": "2014-07-15T14:39:02.000000", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "version": 1, "project_id": "noauth-project", "email": "hostmaster@example.org", "links": { "self": "http://dns.provider.com/v2/zones/38dbf635-45cb-4873-8300-6c273f0283c7" } }], "links": { "self": "https://dns.provider.com/v2/zones?name=example*" } } This example demonstrates the use of multiple wildcards: **Request:** .. sourcecode:: http GET /v2/zones?name=*example* HTTP/1.1 Host: dns.provider.com Accept: application/json **Response:** .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json { "zones": [{ "status": "ACTIVE", "description": null, "updated_at": "2014-07-08T20:28:31.000000", "ttl": 86400, "serial": 1404851315, "id": "a4e29ed3-d7a4-4e4d-945d-ce64678d3b94", "name": "example.com.", "created_at": "2014-07-08T20:28:19.000000", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "version": 1, "project_id": "noauth-project", "email": "hostmaster@example.com", "links": { "self": "http://dns.provider.com/v2/zones/a4e29ed3-d7a4-4e4d-945d-ce64678d3b94" } }, { "status": "ACTIVE", "description": null, "updated_at": null, "ttl": 3600, "serial": 1405435099, "id": "13db810b-917d-4898-bc28-4d4ee370d20d", "name": "abc.example.com.", "created_at": "2014-07-15T14:38:19.000000", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "version": 1, "project_id": "noauth-project", "email": "hostmaster@example.com", "links": { "self": "http://dns.provider.com/v2/zones/13db810b-917d-4898-bc28-4d4ee370d20d" } }, { "status": "ACTIVE", "description": null, "updated_at": null, "ttl": 3600, "serial": 1405435142, "id": "38dbf635-45cb-4873-8300-6c273f0283c7", "name": "example.org.", "created_at": "2014-07-15T14:39:02.000000", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "version": 1, "project_id": "noauth-project", "email": "hostmaster@example.org", "links": { "self": "http://dns.provider.com/v2/zones/38dbf635-45cb-4873-8300-6c273f0283c7" } }, { "status": "ACTIVE", "description": null, "updated_at": null, "ttl": 3600, "serial": 1405435156, "id": "c316def0-8599-4030-9dcd-2ce566348115", "name": "abc.example.net.", "created_at": "2014-07-15T14:39:16.000000", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "version": 1, "project_id": "noauth-project", "email": "hostmaster@example.net", "links": { "self": "http://dns.provider.com/v2/zones/c316def0-8599-4030-9dcd-2ce566348115" } }], "links": { "self": "https://dns.provider.com/v2/zones?name=*example*" } } Nested Collections ------------------ A nested collection is a collection without a URI of it's own. The only current example we have of this is the "records" array under the RecordSet resource. By default, Nested Collections shall not be included in the listing of it's parent resource. For example, List RecordSets shall not include the "records" collection for each of the RecordSets returned. designate-2.0.0/doc/source/rest/v2/tsigkeys.rst0000664000567000056710000001532312701406243022565 0ustar jenkinsjenkins00000000000000.. Copyright 2015 NEC Corporation. All rights reserved. Author: Sonu Kumar Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ======= Tsigkey ======= Transaction signatures (TSIG) is a mechanism used to secure DNS messages and to provide secure server-to-server communication (usually between master and slave server, but can be extended for dynamic updates as well). Transaction Signatures, or TSIG for short, add cryptographic signatures as a method of authenticating a DNS conversation. It uses a shared secret to establish trust between the communicating parties. Create Tsigkeys =============== .. http:post:: /tsigkeys Create a new Tsigkey. **Example request**: .. code-block:: http POST /tsigkeys HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json { "name": "Example key", "algorithm": "hmac-sha256", "secret": "SomeSecretKey", "scope": "POOL", "resource_id": "6ca6baef-3305-4ad0-a52b-a82df5752b62" } **Example response**: .. code-block:: http HTTP/1.1 201 Created Location: http://127.0.0.1:9001/v2/tsigkeys/5fa28ce8-68e3-4fdf-89c1-ed9f151b83d2 Content-Length: 350 Content-Type: application/json; charset=UTF-8 { "links": { "self": "http://127.0.0.1:9001/v2/tsigkeys/5fa28ce8-68e3-4fdf-89c1-ed9f151b83d2" }, "name": "test-key", "algorithm": "hmac-sha256", "resource_id": "6ca6baef-3305-4ad0-a52b-a82df5752b62", "created_at": "2015-12-21T09:48:15.000000", "updated_at": null, "secret": "SomeSecretKey", "scope": "POOL", "id": "5fa28ce8-68e3-4fdf-89c1-ed9f151b83d2" } :form name: TSIG Key Name. :form algorithm: TSIG Algorithm. :form resource_id: Pool id or Zone id :form secret: TSIG Secret. :form scope: TSIG Scope. :statuscode 201: Created :statuscode 202: Accepted :statuscode 401: Access Denied Get Tsigkeys ============ .. http:get:: /tsigkeys Get the list of Tsigkeys. **Example request**: .. code-block:: http GET /tsigkeys HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json **Example response**: .. code-block:: http HTTP/1.1 200 OK Content-Length: 776 Content-Type: application/json; charset=UTF-8 { "tsigkeys": [ { "links": { "self": "http://127.0.0.1:9001/v2/tsigkeys/5fa28ce8-68e3-4fdf-89c1-ed9f151b83d2" }, "name": "test-key", "algorithm": "hmac-sha256", "resource_id": "6ca6baef-3305-4ad0-a52b-a82df5752b62", "created_at": "2015-12-21T09:48:15.000000", "updated_at": null, "secret": "SomeSecretKey", "scope": "POOL", "id": "5fa28ce8-68e3-4fdf-89c1-ed9f151b83d2" }, { "links": { "self": "http://127.0.0.1:9001/v2/tsigkeys/319c58fd-a0e0-4d69-a854-98bc49594419" }, "name": "test-key-2", "algorithm": "hmac-sha256", "resource_id": "6ca6baef-3305-4ad0-a52b-a82df5752b62", "created_at": "2015-12-21T09:51:06.000000", "updated_at": null, "secret": "SomeSecretKey", "scope": "POOL", "id": "319c58fd-a0e0-4d69-a854-98bc49594419"} ], "links": { "self": "http://127.0.0.1:9001/v2/tsigkeys"} } :statuscode 200: Success :statuscode 401: Access Denied Get Tsigkey =========== .. http:get:: /tsigkeys/(uuid:id) Retrieves a tsigkey with the specified tsigkey's ID. **Example request:** .. sourcecode:: http GET /v2/tsigkeys/5fa28ce8-68e3-4fdf-89c1-ed9f151b83d2 HTTP/1.1 Host: 127.0.0.1:9001 Content-Type: application/json Accept: application/json **Example response:** Content-Length: 350 Content-Type: application/json; charset=UTF-8 X-Openstack-Request-Id: req-d8cd7f24-a735-400b-9a4b-79e175efc923 Date: Mon, 21 Dec 2015 09:59:26 GMT { "links": { "self": "http://127.0.0.1:9001/v2/tsigkeys/5fa28ce8-68e3-4fdf-89c1-ed9f151b83d2" }, "name": "test-key", "algorithm": "hmac-sha256", "resource_id": "6ca6baef-3305-4ad0-a52b-a82df5752b62", "created_at": "2015-12-21T09:48:15.000000", "updated_at": null, "secret": "SomeSecretKey", "scope": "POOL", "id": "5fa28ce8-68e3-4fdf-89c1-ed9f151b83d2" } Update Tsigkey ============== .. http:patch:: /tsigkeys/(uuid:id) Update a Tsigkey with the specified tsigkey's id. **Example request**: .. code-block:: http PATCH /tsigkeys/5fa28ce8-68e3-4fdf-89c1-ed9f151b83d2 HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json { "name": "example_tsigkey", "scope": "ZONE" } **Example response**: .. code-block:: http HTTP/1.1 200 OK Content-Length: 381 Content-Type: application/json; charset=UTF-8 { "links": { "self": "http://127.0.0.1:9001/v2/tsigkeys/5fa28ce8-68e3-4fdf-89c1-ed9f151b83d2" }, "name": "example_tsigkey", "algorithm": "hmac-sha256", "resource_id": "6ca6baef-3305-4ad0-a52b-a82df5752b62", "created_at": "2015-12-21T09:48:15.000000", "updated_at": "2015-12-21T10:02:18.000000", "secret": "SomeSecretKey", "scope": "ZONE", "id": "5fa28ce8-68e3-4fdf-89c1-ed9f151b83d2" } :form name: TSIG Key Name. :form algorithm: TSIG Algorithm. :form resource_id: Pool id or Zone id :form secret: TSIG Secret. :form scope: TSIG Scope. :statuscode 200: Success :statuscode 202: Accepted :statuscode 401: Access Denied Remove Tsigkey ============== .. http:delete:: /tsigkeys/(uuid:id) Remove a Tsigkey with the specified tsigkey's id. **Example request**: .. code-block:: http DELETE /tsigkeys/5fa28ce8-68e3-4fdf-89c1-ed9f151b83d2 HTTP/1.1 Accept: application/json **Example response**: .. code-block:: http HTTP/1.1 204 No Content Content-Length: 0 :statuscode 400: Bad Request :statuscode 204: Successfully Deleted designate-2.0.0/doc/source/rest/v2/zones.rst0000664000567000056710000007531112701406243022064 0ustar jenkinsjenkins00000000000000.. Copyright (C) 2014 eNovance SAS Author: Artom Lifshitz Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Zones ===== A zone resource corresponds to the classical DNS zone. Create Zone ----------- .. http:post:: /zones Creates a new zone. **Example request:** .. sourcecode:: http POST /v2/zones HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json { "name": "example.org.", "email": "joe@example.org", "ttl": 7200, "description": "This is an example zone." } **Example response:** .. sourcecode:: http HTTP/1.1 201 Created Content-Type: application/json { "id": "a86dba58-0043-4cc6-a1bb-69d5e86f3ca3", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "project_id": "4335d1f0-f793-11e2-b778-0800200c9a66", "name": "example.org.", "email": "joe@example.org", "ttl": 7200, "serial": 1404757531, "status": "ACTIVE", "description": "This is an example zone.", "masters": [], "type": "PRIMARY", "transferred_at": null, "version": 1, "created_at": "2014-07-07T18:25:31.275934", "updated_at": null, "links": { "self": "https://127.0.0.1:9001/v2/zones/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3" } } :form description: UTF-8 text field. :form name: Valid zone name (Immutable). :form type: Enum PRIMARY/SECONDARY, default PRIMARY (Immutable). :form email: email address, required for type PRIMARY, NULL for SECONDARY. :form ttl: time-to-live numeric value in seconds, NULL for SECONDARY. :form masters: Array of master nameservers. (NULL for type PRIMARY, required for SECONDARY otherwise zone will not be transferred before set). :statuscode 201: Created :statuscode 202: Accepted :statuscode 401: Access Denied Get Zone -------- .. http:get:: /zones/(uuid:id) Retrieves a zone with the specified zone ID. **Example request:** .. sourcecode:: http GET /v2/zones/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3 HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json **Example response:** .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "id": "a86dba58-0043-4cc6-a1bb-69d5e86f3ca3", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "project_id": "4335d1f0-f793-11e2-b778-0800200c9a66", "name": "example.org.", "email": "joe@example.org.", "ttl": 7200, "serial": 1404757531, "status": "ACTIVE", "description": "This is an example zone.", "masters": [], "type": "PRIMARY", "transferred_at": null, "version": 1, "created_at": "2014-07-07T18:25:31.275934", "updated_at": null, "links": { "self": "https://127.0.0.1:9001/v2/zones/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3" } } :statuscode 200: Success :statuscode 401: Access Denied Get Zone Name Servers --------------------- .. http:get:: /zones/(uuid:id)/nameservers Retrieves the nameservers for a zone with zone_id of id **Example request:** .. sourcecode:: http GET /v2/zones/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3/nameservers HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json **Example response:** .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "nameservers": [ { "hostname": "ns1.example.com.", "priority": 1 }, { "hostname": "ns2.example.com.", "priority": 2 } ] } :statuscode 200: Success :statuscode 401: Access Denied List Zones ---------- .. http:get:: /zones Lists all zones. **Example Request:** .. sourcecode:: http GET /v2/zones HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json **Example Response:** .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "zones": [{ "id": "a86dba58-0043-4cc6-a1bb-69d5e86f3ca3", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "project_id": "4335d1f0-f793-11e2-b778-0800200c9a66", "name": "example.org.", "email": "joe@example.org.", "ttl": 7200, "serial": 1404757531, "status": "ACTIVE", "description": "This is an example zone.", "masters": [], "type": "PRIMARY", "transferred_at": null, "version": 1, "created_at": "2014-07-07T18:25:31.275934", "updated_at": null, "links": { "self": "https://127.0.0.1:9001/v2/zones/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3" } }, { "id": "fdd7b0dc-52a3-491e-829f-41d18e1d3ada", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "project_id": "4335d1f0-f793-11e2-b778-0800200c9a66", "name": "example.net.", "email": "joe@example.net.", "ttl": 7200, "serial": 1404756682, "status": "ACTIVE", "description": "This is another example zone.", "masters": [], "type": "PRIMARY", "transferred_at": null, "version": 1, "created_at": "2014-07-07T18:22:08.287743", "updated_at": null, "links": { "self": "https://127.0.0.1:9001/v2/zones/fdd7b0dc-52a3-491e-829f-41d18e1d3ada" } }], "links": { "self": "https://127.0.0.1:9001/v2/zones" } } :statuscode 200: Success :statuscode 401: Access Denied Update Zone ----------- .. http:patch:: /zones/(uuid:id) Changes the specified attribute(s) for an existing zone. In the example below, we update the TTL to 3600. **Request:** .. sourcecode:: http PATCH /v2/zones/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3 HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json { "ttl": 3600 } **Response:** .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json { "id": "a86dba58-0043-4cc6-a1bb-69d5e86f3ca3", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "project_id": "4335d1f0-f793-11e2-b778-0800200c9a66", "name": "example.org.", "email": "joe@example.org.", "ttl": 3600, "serial": 1404760160, "status": "ACTIVE", "description": "This is an example zone.", "masters": [], "type": "PRIMARY", "transferred_at": null, "version": 1, "created_at": "2014-07-07T18:25:31.275934", "updated_at": "2014-07-07T19:09:20.876366", "links": { "self": "https://127.0.0.1:9001/v2/zones/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3" } } :form description: UTF-8 text field. :form name: Valid zone name (Immutable). :form type: Enum PRIMARY/SECONDARY, default PRIMARY (Immutable). :form email: email address, required for type PRIMARY, NULL for SECONDARY. :form ttl: time-to-live numeric value in seconds, NULL for SECONDARY :form masters: Array of master nameservers. (NULL for type PRIMARY, required for SECONDARY otherwise zone will not be transferred before set.) :statuscode 200: Success :statuscode 202: Accepted :statuscode 401: Access Denied Delete Zone ----------- .. http:delete:: zones/(uuid:id) Deletes a zone with the specified zone ID. Deleting a zone is asynchronous. Once pool manager has deleted the zone from all the pool targets, the zone is deleted from storage. **Example Request:** .. sourcecode:: http DELETE /v2/zones/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3 HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json **Example Response:** .. sourcecode:: http HTTP/1.1 202 Accepted :statuscode 202: Accepted Abandon Zone ------------ .. http:post:: /zones/(uuid:id)/tasks/abandon When a zone is abandoned it removes the zone from Designate's storage. There is no operation done on the pool targets. This is intended to be used in the cases where Designate's storage is incorrect for whatever reason. By default this is restricted by policy (abandon_domain) to admins. **Example Request:** .. sourcecode:: http POST /v2/zones/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3/tasks/abandon HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json **Example Response:** .. sourcecode:: http HTTP/1.1 204 No content :statuscode 204: No content Transfer Zone ------------- Create Zone Transfer Request ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. http:post:: /zones/(uuid:id)/tasks/transfer_requests To initiate a transfer the original owner must create a transfer request. This will return two items that are required to continue: * key: a password that is used to validate the transfer * id: ID of the request. Both of these should be communicated out of band (email / IM / etc) to the intended recipient There is an option of limiting the transfer to a single project. If that is required, the person initiating the transfer will need the Project ID. This will also allow the targeted project to see the transfer in their list of requests. A non-targeted request will not show in a list operation, apart from the owning projects request. An targeted request will only show in the targets and owners lists. An untargeted request can be viewed by any authenticated user. **Example Request** .. sourcecode:: http POST /v2/zones/6b78734a-aef1-45cd-9708-8eb3c2d26ff8/tasks/transfer_requests HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json { "target_project_id": "123456", "description": "Transfer qa.dev.example.com. to QA Team" } **Example Response** .. sourcecode:: http HTTP/1.1 201 Created Content-Type: application/json { "created_at": "2014-07-17T20:34:40.882579", "description": null, "id": "f2ad17b5-807a-423f-a991-e06236c247be", "key": "9Z2R50Y0", "project_id": "1", "status": "ACTIVE", "target_project_id": "123456", "updated_at": null, "zone_id": "6b78734a-aef1-45cd-9708-8eb3c2d26ff8", "zone_name": "qa.dev.example.com.", "links": { "self": "http://127.0.0.1:9001/v2/zones/tasks/transfer_requests/f2ad17b5-807a-423f-a991-e06236c247be" } } :form description: UTF-8 text field :form target_project_id: Optional field to only allow a single tenant to accept the transfer request List Zone Transfer Requests ^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. http:get:: /zones/tasks/transfer_requests List all transfer requests that the requesting project have created, or are targeted to that project The detail shown will differ, based on who the requester is. **Example Request** .. sourcecode:: http GET /zones/tasks/transfer_requests HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json **Example Response** .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json { "transfer_requests": [ { "created_at": "2014-07-17T20:34:40.882579", "description": "This was created by the requesting project", "id": "f2ad17b5-807a-423f-a991-e06236c247be", "key": "9Z2R50Y0", "project_id": "1", "status": "ACTIVE", "target_project_id": "123456", "updated_at": null, "zone_id": "6b78734a-aef1-45cd-9708-8eb3c2d26ff8", "zone_name": "qa.dev.example.com.", "links": { "self": "http://127.0.0.1:9001/v2/zones/tasks/transfer_requests/f2ad17b5-807a-423f-a991-e06236c247be" } }, { "description": "This is scoped to the requesting project", "id": "efd2d720-b0c4-43d4-99f7-d9b53e08860d", "zone_id": "2c4d5e37-f823-4bee-9859-031cb44f80e7", "zone_name": "subdomain.example.com.", "status": "ACTIVE", "links": { "self": "http://127.0.0.1:9001/v2/zones/tasks/transfer_requests/efd2d720-b0c4-43d4-99f7-d9b53e08860d" } } ], "links": { "self": "http://127.0.0.1:9001/v2/zones/tasks/transfer_requests" } } View a Transfer Request ^^^^^^^^^^^^^^^^^^^^^^^ .. http:get:: /zones/tasks/transfer_requests/(uuid:id) Show details about a request. This allows a user to view a transfer request before accepting it **Example Request** .. sourcecode:: http GET /v2/zones/tasks/transfer_requests/f2ad17b5-807a-423f-a991-e06236c247be HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json **Example Response** .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json { "description": "This is scoped to the requesting project", "id": "efd2d720-b0c4-43d4-99f7-d9b53e08860d", "zone_id": "2c4d5e37-f823-4bee-9859-031cb44f80e7", "zone_name": "subdomain.example.com.", "status": "ACTIVE", "links": { "self": "http://127.0.0.1:9001/v2/zones/tasks/transfer_requests/efd2d720-b0c4-43d4-99f7-d9b53e08860d" } } Update a Transfer Request ^^^^^^^^^^^^^^^^^^^^^^^^^ .. http: patch:: /zones/tasks/transfer_requests/(uuid:id) Update a transfer request. This allows a user to update a transfer request before accepting it. **Example Request** .. sourcecode:: http PATCH v2/zones/tasks/transfer_requests/b853202b-22f9-49c1-893d-49cbbf6830bb HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content: application/json { "description": "demo_transfer" } **Example Response** ..sourcecode:: http HTTP/1.1 200 OK Content-Length: 476 Content-Type: application/json charset=UTF-8 { "status": "ACTIVE", "target_project_id": dc685ea10a3a4ddfb9bc2deeca66f131, "zone_id": "08615081-cbfd-445e-9d35-15fccf2be4be", "links": { "self": "http://127.0.0.1:9001/v2/zones/tasks/transfer_requests/b853202b-22f9-49c1-893d-49cbbf6830bb" }, "created_at": "2016-01-28T04:43:00.000000", "updated_at": "2016-01-28T04:45:17.000000", "key": "XWUR5VFL", "zone_name": "example.com.", "project_id": "dc685ea10a3a4ddfb9bc2deeca66f131", "id": "b853202b-22f9-49c1-893d-49cbbf6830bb", "description": "demo_transfer" } :statuscode 200: Success :statuscode 202: Accepted :statuscode 401: Access Denied :form description: UTF-8 text field Delete a transfer request ^^^^^^^^^^^^^^^^^^^^^^^^^ .. http: delete:: /zones/tasks/transfer_requests/(uuid:id) Delete a zone transfer request with the specified id. **Example Request** .. sourcecode:: http DELETE /v2/zones/tasks/transfer_requests/"b853202b-22f9-49c1-893d-49cbbf6830bb HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content: application/json **Example Response** .. sourcecode:: http HTTP/1.1 204 No Content :statuscode 204: No Content Accept a Transfer Request ^^^^^^^^^^^^^^^^^^^^^^^^^ .. http:post:: /zones/tasks/transfer_accepts Accept a zone transfer request. This is called by the project that will own the zone (i.e. the project that will maintain the zone) Once the API returns "Complete" the zone has been transferred to the new project **Example Request** .. sourcecode:: http POST /v2/zones/tasks/transfer_accept HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json { "key":"9Z2R50Y0", "zone_transfer_request_id":"f2ad17b5-807a-423f-a991-e06236c247be" } **Example Response** .. sourcecode:: http HTTP/1.1 201 Created Content-Type: application/json { "id": "581891d5-99f5-49e1-86c3-eec0f44d66fd", "links": { "self": "http://127.0.0.1:9001/v2/zones/tasks/transfer_accepts/581891d5-99f5-49e1-86c3-eec0f44d66fd", "zone": "http://127.0.0.1:9001/v2/zones/6b78734a-aef1-45cd-9708-8eb3c2d26ff8" }, "status": "COMPLETE" } Import Zone ----------- Create a Zone Import ^^^^^^^^^^^^^^^^^^^^ .. http:post:: /zones/tasks/imports To import a zonefile, set the Content-type to **text/dns** . The **zoneextractor.py** tool in the **contrib** folder can generate zonefiles that are suitable for Designate (without any **$INCLUDE** statements for example). An object will be returned that can be queried using the 'self' link the 'links' field. **Example request:** .. sourcecode:: http POST /v2/zones/tasks/imports HTTP/1.1 Host: 127.0.0.1:9001 Content-type: text/dns $ORIGIN example.com. example.com. 42 IN SOA ns.example.com. nsadmin.example.com. 42 42 42 42 42 example.com. 42 IN NS ns.example.com. example.com. 42 IN MX 10 mail.example.com. ns.example.com. 42 IN A 10.0.0.1 mail.example.com. 42 IN A 10.0.0.2 **Example response:** .. sourcecode:: http HTTP/1.1 201 Created Content-Type: application/json { "status": "PENDING", "zone_id": null, "links": { "self": "http://127.0.0.1:9001/v2/zones/tasks/imports/074e805e-fe87-4cbb-b10b-21a06e215d41" }, "created_at": "2015-05-08T15:43:42.000000", "updated_at": null, "version": 1, "message": null, "project_id": "1", "id": "074e805e-fe87-4cbb-b10b-21a06e215d41" } :statuscode 202: Accepted :statuscode 415: Unsupported Media Type View a Zone Import ^^^^^^^^^^^^^^^^^^ .. http:get:: /zones/tasks/imports/(uuid:id) The status of a zone import can be viewed by querying the id given when the request was created. **Example request:** .. sourcecode:: http GET /v2/zones/tasks/imports/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3 HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json **Example response:** .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json { "status": "COMPLETE", "zone_id": "6625198b-d67d-47dc-8d29-f90bd60f3ac4", "links": { "self": "http://127.0.0.1:9001/v2/zones/tasks/imports/074e805e-fe87-4cbb-b10b-21a06e215d41", "href": "http://127.0.0.1:9001/v2/zones/6625198b-d67d-47dc-8d29-f90bd60f3ac4" }, "created_at": "2015-05-08T15:43:42.000000", "updated_at": "2015-05-08T15:43:42.000000", "version": 2, "message": "example.com. imported", "project_id": "noauth-project", "id": "074e805e-fe87-4cbb-b10b-21a06e215d41" } :statuscode 200: Success :statuscode 401: Access Denied :statuscode 404: Not Found Notice the status has been updated, the message field shows that the zone was successfully imported, and there is now a 'href' in the 'links' field that points to the new zone. List Zone Imports ^^^^^^^^^^^^^^^^^ .. http:get:: /zones/tasks/imports/ List all of the zone imports created by this project. **Example request:** .. sourcecode:: http GET /v2/zones/tasks/imports/ HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json **Example response:** .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json { "imports": [ { "status": "COMPLETE", "zone_id": "ea2fd415-dc6d-401c-a8af-90a89d7efcf9", "links": { "self": "http://127.0.0.1:9001/v2/zones/tasks/imports/fb47a23e-eb97-4c86-a3d4-f3e1a4ca9f5e", "href": "http://127.0.0.1:9001/v2/zones/ea2fd415-dc6d-401c-a8af-90a89d7efcf9" }, "created_at": "2015-05-08T15:22:50.000000", "updated_at": "2015-05-08T15:22:50.000000", "version": 2, "message": "example.com. imported", "project_id": "noauth-project", "id": "fb47a23e-eb97-4c86-a3d4-f3e1a4ca9f5e" }, { "status": "COMPLETE", "zone_id": "6625198b-d67d-47dc-8d29-f90bd60f3ac4", "links": { "self": "http://127.0.0.1:9001/v2/zones/tasks/imports/074e805e-fe87-4cbb-b10b-21a06e215d41", "href": "http://127.0.0.1:9001/v2/zones/6625198b-d67d-47dc-8d29-f90bd60f3ac4" }, "created_at": "2015-05-08T15:43:42.000000", "updated_at": "2015-05-08T15:43:42.000000", "version": 2, "message": "example.com. imported", "project_id": "noauth-project", "id": "074e805e-fe87-4cbb-b10b-21a06e215d41" } ], "links": { "self": "http://127.0.0.1:9001/v2/zones/tasks/imports" } } :statuscode 200: Success :statuscode 401: Access Denied :statuscode 404: Not Found Delete Zone Import ^^^^^^^^^^^^^^^^^^ .. http:delete:: /zones/tasks/imports/(uuid:id) Deletes a zone import with the specified ID. This does not affect the zone that was imported, it simply removes the record of the import. **Example Request:** .. sourcecode:: http DELETE /v2/zones/tasks/imports/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3 HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json **Example Response:** .. sourcecode:: http HTTP/1.1 204 No Content :statuscode 204: No Content Export Zone ----------- Create a Zone Export ^^^^^^^^^^^^^^^^^^^^ .. http:post:: /zones/(uuid:id)/tasks/export To export a zone in BIND9 zonefile format, a zone export resource must be created. This is accomplished by initializing an export task. **Example request:** .. sourcecode:: http POST /v2/zones/074e805e-fe87-4cbb-b10b-21a06e215d41/tasks/export HTTP/1.1 Host: 127.0.0.1:9001 **Example response:** .. sourcecode:: http HTTP/1.1 202 Accepted Content-Type: application/json { "status": "PENDING", "zone_id": "074e805e-fe87-4cbb-b10b-21a06e215d41", "links": { "self": "http://127.0.0.1:9001/v2/zones/tasks/exports/8ec17fe1-d1f9-41b4-aa98-4eeb4c27b720" }, "created_at": "2015-08-27T20:57:03.000000", "updated_at": null, "version": 1, "location": null, "message": null, "project_id": "1", "id": "8ec17fe1-d1f9-41b4-aa98-4eeb4c27b720" } :statuscode 202: Accepted View a Zone Export Record ^^^^^^^^^^^^^^^^^^^^^^^^^ .. http:get:: /zones/tasks/exports/(uuid:id) The status of a zone export can be viewed by querying the id given when the request was created. **Example request:** .. sourcecode:: http GET /v2/zones/tasks/exports/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3 HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json **Example response:** .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json { "status": "COMPLETE", "zone_id": "6625198b-d67d-47dc-8d29-f90bd60f3ac4", "links": { "self": "http://127.0.0.1:9001/v2/zones/tasks/exports/8ec17fe1-d1f9-41b4-aa98-4eeb4c27b720", "export": "http://127.0.0.1:9001/v2/zones/tasks/exports/8ec17fe1-d1f9-41b4-aa98-4eeb4c27b720/export" }, "created_at": "2015-08-27T20:57:03.000000", "updated_at": "2015-08-27T20:57:03.000000", "version": 2, "location": "designate://v2/zones/tasks/exports/8ec17fe1-d1f9-41b4-aa98-4eeb4c27b720/export", "message": null, "project_id": "noauth-project", "id": "8ec17fe1-d1f9-41b4-aa98-4eeb4c27b720" } :statuscode 200: Success :statuscode 401: Access Denied :statuscode 404: Not Found Notice the status has been updated and there is now an 'export' in the 'links' field that points to a link where the export (zonefile) can be accessed. View the Exported Zone ^^^^^^^^^^^^^^^^^^^^^^ The link that is generated in the export field in an export resource can be followed to a Designate resource, or an external resource. If the link is to a Designate endpoint, the zonefile can be retrieved directly through the API by following that link. .. http:get:: /zones/tasks/exports/(uuid:id) **Example request:** .. sourcecode:: http GET /zones/tasks/exports/8ec17fe1-d1f9-41b4-aa98-4eeb4c27b720/export HTTP/1.1 Host: 127.0.0.1:9001 Accept: text/dns **Example response:** .. sourcecode:: http HTTP/1.1 200 OK Content-Type: text/dns $ORIGIN example.com. $TTL 42 example.com. IN SOA ns.designate.com. nsadmin.example.com. ( 1394213803 ; serial 3600 ; refresh 600 ; retry 86400 ; expire 3600 ; minimum ) example.com. IN NS ns.designate.com. example.com. IN MX 10 mail.example.com. ns.example.com. IN A 10.0.0.1 mail.example.com. IN A 10.0.0.2 :statuscode 200: Success :statuscode 401: Access Denied :statuscode 404: Not Found Notice how the SOA and NS records are replaced with the Designate server(s). List Zone Exports ^^^^^^^^^^^^^^^^^ .. http:get:: /zones/tasks/exports/ List all of the zone exports created by this project. **Example request:** .. sourcecode:: http GET /v2/zones/tasks/exports/ HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json **Example response:** .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json { "exports": [ { "status": "COMPLETE", "zone_id": "30ea7692-7f9e-4195-889e-0ba11620b491", "links": { "self": "http://127.0.0.1:9001/v2/zones/tasks/exports/d2f36aa6-2da4-4b22-a2a9-9cdf19a2f248", "export": "http://127.0.0.1:9001/v2/zones/30ea7692-7f9e-4195-889e-0ba11620b491/tasks/exports/d2f36aa6-2da4-4b22-a2a9-9cdf19a2f248/export" }, "created_at": "2015-08-24T19:46:50.000000", "updated_at": "2015-08-24T19:46:50.000000", "version": 2, "location": "designate://v2/zones/30ea7692-7f9e-4195-889e-0ba11620b491/tasks/exports/d2f36aa6-2da4-4b22-a2a9-9cdf19a2f248/export", "message": null, "project_id": "noauth-project", "id": "d2f36aa6-2da4-4b22-a2a9-9cdf19a2f248" }, { "status": "COMPLETE", "zone_id": "0503f9fd-3938-47a4-bbf3-df99b088abfc", "links": { "self": "http://127.0.0.1:9001/v2/zones/tasks/exports/3d7d07a5-2ce3-458e-b3dd-6a29906234d8", "export": "http://127.0.0.1:9001/v2/zones/tasks/exports/3d7d07a5-2ce3-458e-b3dd-6a29906234d8/export" }, "created_at": "2015-08-25T15:16:10.000000", "updated_at": "2015-08-25T15:16:10.000000", "version": 2, "location": "designate://v2/zones/tasks/exports/3d7d07a5-2ce3-458e-b3dd-6a29906234d8/export", "message": null, "project_id": "noauth-project", "id": "3d7d07a5-2ce3-458e-b3dd-6a29906234d8" }, ], "links": { "self": "http://127.0.0.1:9001/v2/zones/tasks/exports" } } :statuscode 200: Success :statuscode 401: Access Denied :statuscode 404: Not Found Delete Zone Export ^^^^^^^^^^^^^^^^^^ .. http:delete:: /zones/tasks/exports/(uuid:id) Deletes a zone export with the specified ID. This does not affect the zone that was exported, it simply removes the record of the export. If the link to view the export was pointing to a Designate API endpoint, the endpoint will no longer be available. **Example Request:** .. sourcecode:: http DELETE /v2/zones/tasks/exports/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3 HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json **Example Response:** .. sourcecode:: http HTTP/1.1 204 No Content :statuscode 204: No Content designate-2.0.0/doc/source/rest/v2/pools.rst0000664000567000056710000001631612701406241022060 0ustar jenkinsjenkins00000000000000.. Copyright (C) 2015 Rackspace Author: Eric Larson Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ======= Pools ======= Pools are collection of backend DNS servers such as bind9. The backend servers in a pool are responsible for answering DNS queries. .. note:: Currently there is a default pool that is created. Please be aware, this will change in the future. Create Pool =========== .. http:post:: /pools Create a new Pool. **Example request**: .. code-block:: http POST /pools HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json { "name": "Example Pool", "ns_records": [ { "hostname": "ns1.example.org.", "priority": 1 } ] } **Example response**: .. code-block:: http HTTP/1.1 201 Created Location: http://127.0.0.1:9001/v2/pools/d1716333-8c16-490f-85ee-29af36907605 Content-Type: application/json; charset=UTF-8 { "description": null, "id": "d1716333-8c16-490f-85ee-29af36907605", "project_id": "noauth-project", "created_at": "2015-02-23T21:56:33.000000", "attributes": null, "ns_records": [ { "hostname": "ns1.example.org.", "priority": 1 } ], "links": { "self": "http://127.0.0.1:9001/v2/pools/d1716333-8c16-490f-85ee-29af36907605" }, "name": "example_pool", "updated_at": null } :form name: UTF-8 text field :form description: a description of the pool :form tenant_id: the UUID of the tenant :form provisioner: the type backend that should be used :form attributes: meta data for the pool :form ns_records: a list of ns_records as fully qualified domains :statuscode 201: Created :statuscode 400: Bad Request :statuscode 401: Access Denied Get Pools ========= .. http:get:: /pools Get the list of Pools. This resource supports the :doc:`collections` API. **Example request**: .. code-block:: http GET /pools HTTP/1.1 Host: example.com Accept: application/json **Example response**: .. code-block:: http HTTP/1.1 200 OK Content-Length: 755 Content-Type: application/json; charset=UTF-8 { "metadata": null, "links": { "self": "http://127.0.0.1:9001/v2/pools" }, "pools": [ { "description": null, "id": "794ccc2c-d751-44fe-b57f-8894c9f5c842", "project_id": null, "created_at": "2015-02-18T22:18:58.000000", "attributes": null, "ns_records": [ { "hostname": "ns1.example.org.", "priority": 1 } ], "links": { "self": "http://127.0.0.1:9001/v2/pools/794ccc2c-d751-44fe-b57f-8894c9f5c842" }, "name": "default", "updated_at": "2015-02-19T15:59:44.000000" }, { "description": null, "id": "d1716333-8c16-490f-85ee-29af36907605", "project_id": "noauth-project", "created_at": "2015-02-23T21:56:33.000000", "attributes": null, "ns_records": [ { "hostname": "ns2.example.org.", "priority": 1 } ], "links": { "self": "http://127.0.0.1:9001/v2/pools/d1716333-8c16-490f-85ee-29af36907605" }, "name": "example_pool", "updated_at": null } ] } :statuscode 200: OK :statuscode 400: Bad Request Get Pool ======== .. http:get:: /pools/(uuid:id) Get a specific Pool using the Pool's uuid id. **Example request**: .. code-block:: http GET /pools/d1716333-8c16-490f-85ee-29af36907605 HTTP/1.1 Host: example.com Accept: application/json **Example response**: .. code-block:: http HTTP/1.1 200 OK Content-Length: 349 Content-Type: application/json; charset=UTF-8 { "description": null, "id": "794ccc2c-d751-44fe-b57f-8894c9f5c842", "project_id": null, "created_at": "2015-02-18T22:18:58.000000", "attributes": null, "ns_records": [ { "hostname": "ns1.example.org.", "priority": 1 } ], "links": { "self": "http://127.0.0.1:9001/v2/pools/794ccc2c-d751-44fe-b57f-8894c9f5c842" }, "name": "default", "updated_at": "2015-02-19T15:59:44.000000" } :statuscode 200: OK :statuscode 400: Bad Request Update Pool =========== .. http:patch:: /pools/(uuid:id) Update a Pool. **Example request**: .. code-block:: http PATCH /pools/794ccc2c-d751-44fe-b57f-8894c9f5c842 HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json { "ns_records": [ { "hostname": "ns1.example.org.", "priority": 1 }, { "hostname": "ns3.example.org.", "priority": 2 } ], } **Example response**: .. code-block:: http HTTP/1.1 200 OK Content-Length: 369 Content-Type: application/json; charset=UTF-8 { "description": null, "id": "794ccc2c-d751-44fe-b57f-8894c9f5c842", "project_id": null, "created_at": "2015-02-18T22:18:58.000000", "attributes": null, "ns_records": [ { "hostname": "ns1.example.org.", "priority": 1 } { "hostname": "ns3.example.org.", "priority": 2 } ], "links": { "self": "http://127.0.0.1:9001/v2/pools/794ccc2c-d751-44fe-b57f-8894c9f5c842" }, "name": "default", "updated_at": "2015-02-24T17:39:07.000000" } .. note:: When updating the Pool definition document, take care to ensure that any existing values are included when updating a field. For example, if we used .. code-block:: json { "ns_records": [ { "hostname": "ns3.example.org.", "priority": 2 } ] } This would **replace** the value of the `ns_records` key. It is a good practice to perform a GET and mutate the result accordingly. :statuscode 202: Accepted :statuscode 400: Bad Request :statuscode 409: Conflict Remove Pool =========== .. http:delete:: /pools/(uuid:id) Remove a Pool. When deleting a Pool, the Pool cannot contain any zones. **Example request**: .. code-block:: http DELETE /pools HTTP/1.1 Accept: application/json **Example response**: .. code-block:: http HTTP/1.1 204 No Content Content-Length: 0 :statuscode 400: Bad Request :statuscode 204: Successfully Deleted designate-2.0.0/doc/source/rest/v2/recordsets.rst0000664000567000056710000004202112701406243023073 0ustar jenkinsjenkins00000000000000.. Copyright (C) 2014 Rackspace Author: Joe McBride Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Record Sets and Records ======================= A record set groups together a list of related records. It is the essential content of your zone file and is used to define the various domain to server routes for your application. Record sets are also referred to as "Resource Record Sets" or "RRSet". The following illustrates a record set in the BIND file format: .. sourcecode:: none example.org. 86400 MX 10 mail1.example.org. 20 mail2.example.org. 30 mail3.example.org. .. note:: The "description" field on Records cannot be accessed from the V2 API. Likewise, the "description" field on Record Sets cannot be accessed from the V1 API. Create Record Set (A, AAAA, CNAME, NS, and TXT) ----------------------------------------------- The following format can be used for common record set types including A, AAAA, CNAME, NS and TXT. Simply replace the type and records with the respective values. NS record sets can only be created and deleted. Examples for MX, SSHFP, SPF and SRV will follow. .. http:post:: /zones/(uuid:id)/recordsets Creates a new record set. **Example request:** .. sourcecode:: http POST /v2/zones/2150b1bf-dee2-4221-9d85-11f7886fb15f/recordsets HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json { "name" : "example.org.", "description" : "This is an example record set.", "type" : "A", "ttl" : 3600, "records" : [ "10.1.0.2" ] } **Example response:** .. sourcecode:: http HTTP/1.1 201 Created Content-Type: application/json { "description": "This is an example record set.", "links": { "self": "https://127.0.0.1:9001/v2/zones/2150b1bf-dee2-4221-9d85-11f7886fb15f/recordsets/f7b10e9b-0cae-4a91-b162-562bc6096648" }, "updated_at": null, "records": [ "10.1.0.2" ], "ttl": 3600, "id": "f7b10e9b-0cae-4a91-b162-562bc6096648", "name": "example.org.", "zone_id": "2150b1bf-dee2-4221-9d85-11f7886fb15f", "created_at": "2014-10-24T19:59:44.000000", "version": 1, "type": "A" } :form description: UTF-8 text field :form name: domain name :form ttl: time-to-live numeric value in seconds :form type: type of record set :form records: a list of record values :statuscode 201: Created :statuscode 401: Access Denied Get Record Set -------------- .. http:get:: /zones/(uuid:id)/recordsets/(uuid:id) Retrieves a record set with the specified record set ID. **Example request:** .. sourcecode:: http GET /v2/zones/2150b1bf-dee2-4221-9d85-11f7886fb15f/recordsets/f7b10e9b-0cae-4a91-b162-562bc6096648 HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json **Example response:** .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "description": "This is an example recordset.", "links": { "self": "https://127.0.0.1:9001/v2/zones/2150b1bf-dee2-4221-9d85-11f7886fb15f/recordsets/f7b10e9b-0cae-4a91-b162-562bc6096648" }, "updated_at": null, "records": [ "10.1.0.2" ], "ttl": 3600, "id": "f7b10e9b-0cae-4a91-b162-562bc6096648", "name": "example.org.", "zone_id": "2150b1bf-dee2-4221-9d85-11f7886fb15f", "created_at": "2014-10-24T19:59:44.000000", "version": 1, "type": "A" } :statuscode 200: Success :statuscode 401: Access Denied List Record Sets ---------------- .. http:get:: /zones/(uuid:id)/recordsets Lists all record sets for a given zone id. **Example Request:** .. sourcecode:: http GET /v2/zones/2150b1bf-dee2-4221-9d85-11f7886fb15f/recordsets HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json **Example Response:** .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "recordsets": [ { "description": null, "links": { "self": "https://127.0.0.1:9001/v2/zones/2150b1bf-dee2-4221-9d85-11f7886fb15f/recordsets/65ee6b49-bb4c-4e52-9799-31330c94161f" }, "updated_at": null, "records": [ "ns2.example.com." ], "ttl": null, "id": "65ee6b49-bb4c-4e52-9799-31330c94161f", "name": "example.org.", "zone_id": "2150b1bf-dee2-4221-9d85-11f7886fb15f", "created_at": "2014-10-24T19:59:11.000000", "version": 1, "type": "NS" }, { "description": null, "links": { "self": "https://127.0.0.1:9001/v2/zones/2150b1bf-dee2-4221-9d85-11f7886fb15f/recordsets/14500cf9-bdff-48f6-b06b-5fc7491ffd9e" }, "updated_at": "2014-10-24T19:59:46.000000", "records": [ "ns2.example.com. joe.example.org. 1414180785 3600 600 86400 3600" ], "ttl": null, "id": "14500cf9-bdff-48f6-b06b-5fc7491ffd9e", "name": "example.org.", "zone_id": "2150b1bf-dee2-4221-9d85-11f7886fb15f", "created_at": "2014-10-24T19:59:12.000000", "version": 1, "type": "SOA" }, { "description": "This is an example recordset.", "links": { "self": "https://127.0.0.1:9001/v2/zones/2150b1bf-dee2-4221-9d85-11f7886fb15f/recordsets/f7b10e9b-0cae-4a91-b162-562bc6096648" }, "updated_at": null, "records": [ "10.1.0.2" ], "ttl": 3600, "id": "f7b10e9b-0cae-4a91-b162-562bc6096648", "name": "example.org.", "zone_id": "2150b1bf-dee2-4221-9d85-11f7886fb15f", "created_at": "2014-10-24T19:59:44.000000", "version": 1, "type": "A" } ], "links": { "self": "https://127.0.0.1:9001/v2/zones/2150b1bf-dee2-4221-9d85-11f7886fb15f/recordsets" } } :statuscode 200: Success :statuscode 401: Access Denied Update Record Set ----------------- .. http:put:: /zones/(uuid:id)/recordsets/(uuid:id) Replaces the record set with the specified details. In the example below, we update the TTL to 3600. **Request:** .. sourcecode:: http PUT /v2/zones/2150b1bf-dee2-4221-9d85-11f7886fb15f/recordsets/f7b10e9b-0cae-4a91-b162-562bc6096648 HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json { "description" : "I updated this example.", "ttl" : 60, "records" : [ "10.1.0.2" ] } **Response:** .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json { "description": "I updated this example.", "ttl": 60, "records": [ "10.1.0.2" ], "links": { "self": "https://127.0.0.1:9001/v2/zones/2150b1bf-dee2-4221-9d85-11f7886fb15f/recordsets/f7b10e9b-0cae-4a91-b162-562bc6096648" }, "updated_at": "2014-10-24T20:15:27.000000", "id": "f7b10e9b-0cae-4a91-b162-562bc6096648", "name": "example.org.", "zone_id": "2150b1bf-dee2-4221-9d85-11f7886fb15f", "created_at": "2014-10-24T19:59:44.000000", "version": 2, "type": "A" } :form description: UTF-8 text field :form name: domain name :form ttl: time-to-live numeric value in seconds :form type: type of record set (can not be changed on update) :form records: a list of data records :statuscode 200: Success :statuscode 401: Access Denied Delete Record Set ----------------- .. http:delete:: zones/(uuid:id)/recordsets/(uuid:id) Deletes a record set with the specified record set ID. **Example Request:** .. sourcecode:: http DELETE /v2/zones/2150b1bf-dee2-4221-9d85-11f7886fb15f/recordsets/f7b10e9b-0cae-4a91-b162-562bc6096648 HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json **Example Response:** .. sourcecode:: http HTTP/1.1 204 No Content :statuscode 204: No content Create MX Record Set -------------------- .. http:post:: /zones/(uuid:id)/recordsets Creates a new MX record set. MX record set data format is " " (e.g. "10 10.1.0.1"). **Example request:** .. sourcecode:: http POST /v2/zones/2150b1bf-dee2-4221-9d85-11f7886fb15f/recordsets HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json { "name" : "mail.example.org.", "description" : "An MX recordset.", "type" : "MX", "ttl" : 3600, "records" : [ "10 mail1.example.org.", "20 mail2.example.org.", "30 mail3.example.org.", "40 mail4.example.org." ] } **Example response:** .. sourcecode:: http HTTP/1.1 201 Created Content-Type: application/json { "description": "An MX recordset.", "links": { "self": "https://127.0.0.1:9001/v2/zones/2150b1bf-dee2-4221-9d85-11f7886fb15f/recordsets/f7b10e9b-0cae-4a91-b162-562bc6096649" }, "updated_at": null, "records" : [ "10 mail1.example.org.", "20 mail2.example.org.", "30 mail3.example.org.", "40 mail4.example.org." ], "ttl": 3600, "id": "f7b10e9b-0cae-4a91-b162-562bc6096649", "name": "mail.example.org.", "zone_id": "2150b1bf-dee2-4221-9d85-11f7886fb15f", "created_at": "2014-10-25T19:59:44.000000", "version": 1, "type": "MX" } :form description: UTF-8 text field :form name: domain name :form ttl: time-to-live numeric value in seconds :form type: type of record set :form records: a list of record values :statuscode 201: Created :statuscode 401: Access Denied Create SSHFP Record Set ----------------------- .. http:post:: /zones/(uuid:id)/recordsets Creates a new SSHFP record set. SSHFP record set data format is " " (e.g. "1 2 aa2df857dc65c5359f02ca75ec5c4308c0100594d931e8d243a42f586257b5e8"). **Example request:** .. sourcecode:: http POST /v2/zones/2150b1bf-dee2-4221-9d85-11f7886fb15f/recordsets HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json { "name" : "foo.example.org.", "description" : "An SSHFP recordset.", "type" : "SSHFP", "ttl" : 3600, "records" : [ "1 2 aa2df857dc65c5359f02ca75ec5c4308c0100594d931e8d243a42f586257b5e8" ] } **Example response:** .. sourcecode:: http HTTP/1.1 201 Created Content-Type: application/json { "description": "An SSHFP recordset.", "links": { "self": "https://127.0.0.1:9001/v2/zones/2150b1bf-dee2-4221-9d85-11f7886fb15f/recordsets/f7b10e9b-0cae-4a91-b162-562bc6096650" }, "updated_at": null, "records" : [ "1 2 aa2df857dc65c5359f02ca75ec5c4308c0100594d931e8d243a42f586257b5e8" ], "ttl": 3600, "id": "f7b10e9b-0cae-4a91-b162-562bc6096650", "name": "foo.example.org.", "zone_id": "2150b1bf-dee2-4221-9d85-11f7886fb15f", "created_at": "2014-11-10T19:59:44.000000", "version": 1, "type": "SSHFP" } :form description: UTF-8 text field :form name: domain name :form ttl: time-to-live numeric value in seconds :form type: type of record set :form records: a list of record values :statuscode 201: Created :statuscode 401: Access Denied Create SPF Record Set --------------------- .. http:post:: /zones/(uuid:id)/recordsets Creates a new SPF record set. SPF record set data formatting follows standard SPF record syntax. **Example request:** .. sourcecode:: http POST /v2/zones/2150b1bf-dee2-4221-9d85-11f7886fb15f/recordsets HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json { "name" : "foospf.example.org.", "description" : "An SPF recordset.", "type" : "SPF", "ttl" : 3600, "records" : [ "v=spf1 +all" ] } **Example response:** .. sourcecode:: http HTTP/1.1 201 Created Content-Type: application/json { "description": "An SPF recordset.", "links": { "self": "https://127.0.0.1:9001/v2/zones/2150b1bf-dee2-4221-9d85-11f7886fb15f/recordsets/f7b10e9b-0cae-4a91-b162-562bc6096651" }, "updated_at": null, "records" : [ "v=spf1 +all" ], "ttl": 3600, "id": "f7b10e9b-0cae-4a91-b162-562bc6096651", "name": "foospf.example.org.", "zone_id": "2150b1bf-dee2-4221-9d85-11f7886fb15f", "created_at": "2014-11-10T19:59:44.000000", "version": 1, "type": "SPF" } :form description: UTF-8 text field :form name: domain name :form ttl: time-to-live numeric value in seconds :form type: type of record set :form records: a list of record values :statuscode 201: Created :statuscode 401: Access Denied Create SRV Record Set --------------------- .. http:post:: /zones/(uuid:id)/recordsets Creates a new SRV record set. SRV record set data format is " " (e.g. "10 0 5060 server1.example.org."). The "name" attribute should contain the service name, protocol and domain name (e.g. "_sip.tcp.example.org."). **Example request:** .. sourcecode:: http POST /v2/zones/2150b1bf-dee2-4221-9d85-11f7886fb15f/recordsets HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json { "name" : "_sip.tcp.example.org.", "description" : "An SRV recordset.", "type" : "SRV", "ttl" : 3600, "records" : [ "10 0 5060 server1.example.org." ] } **Example response:** .. sourcecode:: http HTTP/1.1 201 Created Content-Type: application/json { "description": "An SRV recordset.", "links": { "self": "https://127.0.0.1:9001/v2/zones/2150b1bf-dee2-4221-9d85-11f7886fb15f/recordsets/f7b10e9b-0cae-4a91-b162-562bc6096652" }, "updated_at": null, "records" : [ "10 0 5060 server1.example.org." ], "ttl": 3600, "id": "f7b10e9b-0cae-4a91-b162-562bc6096652", "name": "_sip.tcp.example.org.", "zone_id": "2150b1bf-dee2-4221-9d85-11f7886fb15f", "created_at": "2014-11-10T19:59:44.000000", "version": 1, "type": "SRV" } :form description: UTF-8 text field :form name: domain name :form ttl: time-to-live numeric value in seconds :form type: type of record set :form records: a list of record values :statuscode 201: Created :statuscode 401: Access Denied designate-2.0.0/doc/source/rest/v2/tlds.rst0000664000567000056710000001632412701406241021671 0ustar jenkinsjenkins00000000000000.. Copyright (c) 2014 Rackspace Hosting All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Tlds ======= Overview ----------------------- Tld (Top level domain) entries are used to manage the Tlds that Designate recognizes. By default, only an admin can manage these entries. The Tlds are stored in the :ref:`database` in the table *tlds* and are not propagated to the :ref:`dns-backend`. By default when Designate starts up there are no Tlds in the database. Tld Checks ----------------------- When there are no Tld entries in the database, Tld checks are not enforced and any domain/zone name can be created, as long as it adheres to the domain name schema. When there are Tlds present in the database, then when a domain/zone is created the name has to pass the following checks. #. The last label in the domain/zone name must be present as a Tld entry in the database. e.g. If a domain/zone with the name *example.com.* is being created then the entry *com* must be present in the database. #. The domain/zone name must not be present as a Tld entry in the database. e.g. If there is a Tld entry *co.uk* in the database, then a domain/zone with the name *co.uk.* cannot be created. Create Tld ------------- .. http:post:: /tlds Create a tld. *name* is the only entry that is required. The *name* should not end in a period (.). **Example request**: .. sourcecode:: http POST /tlds HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json { "name" : "com", "description" : "Tld source http://data.iana.org/TLD/tlds-alpha-by-domain.txt" } **Example response**: .. sourcecode:: http HTTP/1.1 201 Created Content-Type: application/json; charset=UTF-8 Location: http://127.0.0.1:9001/v2/tlds/5abe514c-9fb5-41e8-ab73-5ed25f8a73e9 { "description":"Tld source http://data.iana.org/TLD/tlds-alpha-by-domain.txt", "links":{ "self":"http://127.0.0.1:9001/v2/tlds/5abe514c-9fb5-41e8-ab73-5ed25f8a73e9" }, "created_at":"2014-01-23T18:39:26.710827", "updated_at":null, "id":"5abe514c-9fb5-41e8-ab73-5ed25f8a73e9", "name":"com" } :form created_at: timestamp :form updated_at: timestamp :form name: tld name :form id: uuid :form description: UTF-8 text field :form links: links to traverse the list :statuscode 201: Created :statuscode 401: Access Denied :statuscode 400: Invalid Object :statuscode 409: Duplicate Tld Get a Tld ------------- .. http:get:: /tlds/(uuid:id) Lists a particular Tld **Example request**: .. sourcecode:: http GET /tlds/5abe514c-9fb5-41e8-ab73-5ed25f8a73e9 HTTP/1.1 Host: example.com Accept: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json; charset=UTF-8 { "description":"Tld source http://data.iana.org/TLD/tlds-alpha-by-domain.txt", "links":{ "self":"http://127.0.0.1:9001/v2/tlds/5abe514c-9fb5-41e8-ab73-5ed25f8a73e9" }, "created_at":"2014-01-23T18:39:26.710827", "updated_at":null, "id":"5abe514c-9fb5-41e8-ab73-5ed25f8a73e9", "name":"com" } :form created_at: timestamp :form updated_at: timestamp :form name: tld name :form id: uuid :form description: UTF-8 text field :form links: links to traverse the list :statuscode 200: OK :statuscode 401: Access Denied :statuscode 404: Tld not found List Tlds ------------ .. http:get:: /tlds Lists all tlds **Example request**: .. sourcecode:: http GET /tlds HTTP/1.1 Host: example.com Accept: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json; charset=UTF-8 { "tlds":[ { "description":"Tld source http://data.iana.org/TLD/tlds-alpha-by-domain.txt", "links":{ "self":"http://127.0.0.1:9001/v2/tlds/5abe514c-9fb5-41e8-ab73-5ed25f8a73e9" }, "created_at":"2014-01-23T18:39:26.710827", "updated_at":null, "id":"5abe514c-9fb5-41e8-ab73-5ed25f8a73e9", "name":"com" }, { "description":"Tld source http://data.iana.org/TLD/tlds-alpha-by-domain.txt", "links":{ "self":"http://127.0.0.1:9001/v2/tlds/46e50ebc-1b51-41ee-bc1f-8e75a470c5be" }, "created_at":"2014-01-23T19:59:53.985455", "updated_at":null, "id":"46e50ebc-1b51-41ee-bc1f-8e75a470c5be", "name":"net" } ], "links":{ "self":"http://127.0.0.1:9001/v2/tlds" } } :form created_at: timestamp :form updated_at: timestamp :form name: tld name :form id: uuid :form description: UTF-8 text field :form links: links to traverse the list :statuscode 200: OK :statuscode 401: Access Denied Update a Tld --------------- .. http:patch:: /tlds/(uuid:id) updates a tld **Example request**: .. sourcecode:: http PATCH /tlds/5abe514c-9fb5-41e8-ab73-5ed25f8a73e9 HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json { "name" : "org", "description" : "Updated the name from com to org" } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json; charset=UTF-8 { "description":"Updated the name from com to org", "links":{ "self":"http://127.0.0.1:9001/v2/tlds/5abe514c-9fb5-41e8-ab73-5ed25f8a73e9" }, "created_at":"2014-01-23T18:39:26.710827", "updated_at":"2014-01-23T20:35:12.449599", "id":"5abe514c-9fb5-41e8-ab73-5ed25f8a73e9", "name":"org" } :form created_at: timestamp :form updated_at: timestamp :form name: tld name :form id: uuid :form description: UTF-8 text field :form links: links to traverse the list :statuscode 200: OK :statuscode 401: Access Denied :statuscode 404: Tld not found :statuscode 409: Duplicate Tld Delete a Tld --------------- .. http:delete:: /tlds/(uuid:id) delete a tld **Example request**: .. sourcecode:: http DELETE /tlds/5abe514c-9fb5-41e8-ab73-5ed25f8a73e9 HTTP/1.1 Host: example.com **Example response**: .. sourcecode:: http HTTP/1.1 204 No Content Content-Type: application/json; charset=UTF-8 Content-Length: 0 :statuscode 204: No Content :statuscode 401: Access Denied :statuscode 404: Tld not found designate-2.0.0/doc/source/rest/v2/reverse.rst0000664000567000056710000001556512701406241022404 0ustar jenkinsjenkins00000000000000.. Copyright 2015 Hewlett-Packard Development Company, L.P. All Rights Reserved. Author: Endre Karlson Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. .. note: Currently the /reverse endpoint is used to tie reverse DNS records to IPs. FloatingIPs =========== In order to use the FloatingIPs functionality you will need to have a FloatingIP associated to your project in Neutron. Set FloatingIP's PTR record ---------------------------- .. http:patch:: /reverse/floatingips/(string:region):(uuid:floatingip_id) Set a PTR record for the given FloatingIP. The domain if it does not exist will be provisioned automatically. **Example request**: .. sourcecode:: http POST /reverse/floatingips/RegionOne:c47229fb-0831-4b55-a5b5-380d361be4bd HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json { "ptrdname" : "smtp.example.com.", "description" : "This is a floating ip for 10.0.0.1", "ttl": 600 } **Example response**: .. sourcecode:: http HTTP/1.1 202 Created Content-Type: application/json; charset=UTF-8 Location: http://example.com:9001/v2/reverse/floatingips/RegionOne:c47229fb-0831-4b55-a5b5-380d361be4bd { "ptrdname": "smtp.example.com.", "ttl": 600, "description":"This is a floating ip for 172.24.4.3", "address": "172.24.4.3", "action": "CREATE", "status": "PENDING", "links":{ "self":"http://example.com:9001/v2/reverse/floatingips/RegionOne:c47229fb-0831-4b55-a5b5-380d361be4bd" }, "pattern":"smtp.example.com.", "created_at":"2014-03-11T21:54:57.000000", "updated_at":null, "id":"RegionOne:c47229fb-0831-4b55-a5b5-380d361be4bd", } :form created_at: timestamp :form updated_at: timestamp :form ptrdname: Hostname :form ttl: Time to live :form address: The FloatingIP address :form id: A combination of the Region and FloatingIP ID :form description: UTF-8 text field :form links: links to traverse the list :form action: Provisioning Action :form status: Provisioning Status :statuscode 202: Created :statuscode 401: Access Denied :statuscode 400: Invalid Object :statuscode 404: FloatingIP / PTR Not found Get a FloatingIP's PTR record ----------------------------- .. http:get:: /reverse/floatingips/(string:region):(uuid:floatingip_id) Shows a particular FloatingIP PTR **Example request**: .. sourcecode:: http GET /reverse/floatingips/RegionOne:c47229fb-0831-4b55-a5b5-380d361be4bd HTTP/1.1 Host: example.com Accept: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json; charset=UTF-8 { "ptrdname": "smtp.example.com.", "ttl": 600, "description":"This is a floating ip for 172.24.4.3", "address": "172.24.4.3", "action": "NONE", "status": "ACTIVE", "links":{ "self":"http://example.com:9001/v2/reverse/floatingips/RegionOne:c47229fb-0831-4b55-a5b5-380d361be4bd" }, "pattern":"smtp.example.com.", "created_at":"2014-03-11T21:54:57.000000", "updated_at":null, "id":"RegionOne:c47229fb-0831-4b55-a5b5-380d361be4bd", } :form created_at: timestamp :form updated_at: timestamp :form ptrdname: Hostname :form ttl: Time to live :form address: The FloatingIP address :form id: A combination of the Region and FloatingIP ID :form description: UTF-8 text field :form links: links to traverse the list :form action: Provisioning Action :form status: Provisioning Status :statuscode 200: OK :statuscode 404: FloatingIP or PTR not found not found List FloatingIP PTR records --------------------------- .. http:get:: /reverse/floatingips/ Lists all FloatingIPs PTR records **Example request**: .. sourcecode:: http GET /reverse/floatingips/ HTTP/1.1 Host: example.com Accept: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json; charset=UTF-8 { "floatingips":[ { "ttl": 600, "ptrdname": "smtp.example.com.", "description":"This is a floating ip for 172.24.4.3", "address": "172.24.4.3", "action": "NONE", "status": "ACTIVE", "links":{ "self":"http://example.com:9001/v2/reverse/floatingips/RegionOne:c47229fb-0831-4b55-a5b5-380d361be4bd" }, "pattern":"smtp.example.com.", "created_at":"2014-03-11T21:54:57.000000", "updated_at":null, "id":"RegionOne:c47229fb-0831-4b55-a5b5-380d361be4bd", }, { "ptrdname": "www.example.com.", "ttl": 600, "description":"This is a floating ip for 172.24.4.4", "address": "172.24.4.4", "action": "NONE", "status": "ACTIVE", "links":{ "self":"http://example.com:9001/v2/reverse/floatingips/RegionOne:c47229fb-0831-4b55-a5b5-380d361be4be" }, "pattern":"smtp.example.com.", "created_at":"2014-03-11T21:54:57.000000", "updated_at":null, "id":"RegionOne:c47229fb-0831-4b55-a5b5-380d361be4be", } ], "links":{ "self":"http://127.0.0.1:9001/v2/tlds" } } :form created_at: timestamp :form updated_at: timestamp :form name: tld name :form id: uuid :form description: UTF-8 text field :form links: links to traverse the list :statuscode 200: OK :statuscode 401: Access Denied Unset the PTR record for a FloatingIP ------------------------------------- .. http:patch:: /reverse/floatingips/(string:region):(uuid:floatingip_id) Unset a PTR record for the given FloatingIP. **Example request**: .. sourcecode:: http PATCH /reverse/floatingips/RegionOne:c47229fb-0831-4b55-a5b5-380d361be4bd HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json { "ptrdname" : null, } :statuscode 202: Pending :statuscode 401: Access Denied :statuscode 400: Invalid Object :statuscode 404: FloatingIP / PTR Not found designate-2.0.0/doc/source/rest/v2/blacklists.rst0000664000567000056710000002004312701406241023047 0ustar jenkinsjenkins00000000000000.. Copyright (c) 2014 Rackspace Hosting All Rights Reserved. Author: Betsy Luzader Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Blacklists ========== Overview ------------------- The blacklist entries are used to manage blacklisted zones. If a zone is blacklisted, then it cannot be used to create a zone. By default, only an admin can manage these entries. Blacklisted zones are stored as a regular expression (regex) pattern in the :ref:`database` in the *blacklists* table. Blacklist Checks ------------------- Every time a new zone is created, that domain name is checked against the blacklisted zones in the database. If it matches the regex pattern, then a 400 is returned with the message "Blacklisted domain name". If there is no match, then the zone is created. When a new blacklisted pattern is added, it will catch any matching new zones, but it does not check for existing zones that match the blacklisted pattern. Regular Expressions ------------------- Any valid regular expression may be added to the blacklists table. Here are some examples: #. ``^example\\.com\\.$`` This will block the "example.com." domain, but will not block any sub-domains, e.g. "my.example.com." or anything else containing example.com, such as, "myexample.com." #. ``^([A-Za-z0-9_\\-]+\\.)*example\\.com\\.$`` This will block "example.com." and all sub-domains, e.g. "my.example.com.", but anything else containing example.com, will not be blocked, such as, "myexample.com." *NOTE:* When using regular expressions in json, the '\\' character needs to be escaped with an additional '\\', so it needs to be written as "^example\\\\.com\\\\.$" Create a Blacklist ------------------ .. http:post:: /blacklists Create a blacklist. *pattern* is the only entry that is required. The domain name part of the pattern should end in a period (.).' **Example request**: .. sourcecode:: http POST /blacklists HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json { "pattern" : "^([A-Za-z0-9_\\-]+\\.)*example\\.com\\.$", "description" : "This is a blacklisted domain." } **Example response**: .. sourcecode:: http HTTP/1.1 201 Created Content-Type: application/json; charset=UTF-8 Location: 127.0.0.1:9001/v2/blacklists/c47229fb-0831-4b55-a5b5-380d361be4bd { "description":"This is a blacklisted domain.", "links":{ "self":"http://127.0.0.1:9001/v2/blacklists/c47229fb-0831-4b55-a5b5-380d361be4bd" }, "pattern":"^([A-Za-z0-9_\\-]+\\.)*example\\.com\\.$", "created_at":"2014-03-11T21:54:57.000000", "updated_at":null, "id":"c47229fb-0831-4b55-a5b5-380d361be4bd" } :form created_at: timestamp :form updated_at: timestamp :form pattern: blacklist regular expression :form id: uuid :form description: UTF-8 text field :form links: links to traverse the list :statuscode 201: Created :statuscode 401: Access Denied :statuscode 400: Invalid Object :statuscode 409: Duplicate Blacklist Get a Blacklist --------------- .. http:get:: /blacklists/(uuid:id) Lists a particular Blacklisted domain **Example request**: .. sourcecode:: http GET /blacklists/c47229fb-0831-4b55-a5b5-380d361be4bd HTTP/1.1 Host: example.com Accept: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json; charset=UTF-8 { "description":"This is a blacklisted domain.", "links":{ "self":"http://127.0.0.1:9001/v2/blacklists/c47229fb-0831-4b55-a5b5-380d361be4bd" }, "pattern":"^([A-Za-z0-9_\\-]+\\.)*example\\.com\\.$", "created_at":"2014-03-11T21:54:57.000000", "updated_at":null, "id":"c47229fb-0831-4b55-a5b5-380d361be4bd" } :form created_at: timestamp :form updated_at: timestamp :form pattern: blacklist regular expression :form id: uuid :form description: UTF-8 text field :form links: links to traverse the list :statuscode 200: OK :statuscode 401: Access Denied :statuscode 404: Blacklist not found List Blacklists --------------- .. http:get:: /blacklists Lists all blacklists **Example request**: .. sourcecode:: http GET /blacklists HTTP/1.1 Host: example.com Accept: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json; charset=UTF-8 { "blacklists":[ { "description": "This is a blacklisted domain.", "links":{ "self":"http://127.0.0.1:9001/v2/blacklists/c47229fb-0831-4b55-a5b5-380d361be4bd" }, "pattern":"^([A-Za-z0-9_\\-]+\\.)*example\\.com\\.$", "created_at":"2014-03-11T21:54:57.000000", "updated_at":null, "id":"c47229fb-0831-4b55-a5b5-380d361be4bd" }, { "description": null, "links":{ "self":"http://127.0.0.1:9001/v2/blacklists/61140aff-e2c8-488b-9bf4-da710ec8732b" }, "pattern" : "^examples\\.com\\.$", "created_at":"2014-03-07T21:05:59.000000", "updated_at":null, "id":"61140aff-e2c8-488b-9bf4-da710ec8732b" } ], "links":{ "self":"http://127.0.0.1:9001/v2/blacklists" } } :form created_at: timestamp :form updated_at: timestamp :form pattern: blacklist regular expression :form id: uuid :form description: UTF-8 text field :form links: links to traverse the list :statuscode 200: OK :statuscode 401: Access Denied Update a Blacklist ------------------ .. http:patch:: /blacklists/(uuid:id) updates a blacklist **Example request**: .. sourcecode:: http PATCH blacklists/c47229fb-0831-4b55-a5b5-380d361be4bd HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json { "pattern" : "^([A-Za-z0-9_\\-]+\\.)*example\\.com\\.$", "description" : "Updated the description" } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json; charset=UTF-8 { "description":"Updated the pattern to catch subdomains", "links":{ "self":"http://127.0.0.1:9001/v2/blacklists/c47229fb-0831-4b55-a5b5-380d361be4bd" }, "created_at":"2014-03-11T21:54:57.000000", "updated_at":"2014-03-13T16:49:32.117187", "id":"c47229fb-0831-4b55-a5b5-380d361be4bd", "pattern":"^([A-Za-z0-9_\\-]+\\.)*example\\.com\\.$" } :form created_at: timestamp :form updated_at: timestamp :form pattern: blacklist regular expression pattern :form id: uuid :form description: UTF-8 text field :form links: links to traverse the list :statuscode 200: OK :statuscode 401: Access Denied :statuscode 404: Blacklist not found :statuscode 409: Duplicate Blacklist Delete a Blacklist ------------------ .. http:delete:: /blacklists/(uuid:id) delete a blacklist **Example request**: .. sourcecode:: http DELETE /blacklists/c47229fb-0831-4b55-a5b5-380d361be4bd HTTP/1.1 Host: example.com **Example response**: .. sourcecode:: http HTTP/1.1 204 No Content Content-Type: application/json; charset=UTF-8 Content-Length: 0 :statuscode 204: No Content :statuscode 401: Access Denied :statuscode 404: Blacklist not found designate-2.0.0/doc/source/rest/v2/limits.rst0000664000567000056710000000345612701406241022226 0ustar jenkinsjenkins00000000000000.. Copyright 2015 Hewlett-Packard Development Company, L.P. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Limits ====== Overview ------------------- This endpoint is used to retrieve current limits. Get Limits ---------- .. http:get:: /limits Lists current limits **Example request**: .. sourcecode:: http GET /limits HTTP/1.1 Host: example.com Accept: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json; charset=UTF-8 { "max_page_limit": 1000, "max_recordset_name_length": 255, "max_recordset_records": 20, "max_zone_name_length": 255, "max_zone_records": 500, "max_zone_recordsets": 500, "max_zones": 10, "min_ttl": null } :form max_page_limit: Max limit for paging :form max_recordset_name_length: Max length for a RecordSet name :form max_recordset_records: Max number RecordSet of Records :form max_zone_name_length: Max length for a Zone name :form max_zone_records: Max number of Records in a Zone :form max_zone_recordsets: Max number of RecordSets in a Zone :form max_zones: Max number of Zones :form max_ttl: Max TTL :statuscode 200: OK designate-2.0.0/doc/source/rest/v1/0000775000567000056710000000000012701406373020170 5ustar jenkinsjenkins00000000000000designate-2.0.0/doc/source/rest/v1/records.rst0000664000567000056710000005371412701406241022367 0ustar jenkinsjenkins00000000000000Records ======= Resource record entries are used to generate records within a zone TODO: More detail. .. note:: V1 API has been deprecated since the Kilo release. .. note:: The "description" field on Records cannot be accessed from the V2 API. Likewise, the "description" field on Record Sets cannot be accessed from the V1 API. Create Record ------------- .. http:post:: /domains/(uuid:domain_id)/records Create an A record for a domain **Example request**: .. sourcecode:: http POST /domains/89acac79-38e7-497d-807c-a011e1310438/records HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json { "name": "www.example.com.", "type": "A", "data": "192.0.2.3" } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json Content-Length: 399 Location: http://localhost:9001/v1/domains/89acac79-38e7-497d-807c-a011e1310438/records/2e32e609-3a4f-45ba-bdef-e50eacd345ad Date: Fri, 02 Nov 2012 19:56:26 GMT { "id": "2e32e609-3a4f-45ba-bdef-e50eacd345ad", "name": "www.example.com.", "type": "A", "created_at": "2012-11-02T19:56:26.366792", "updated_at": null, "domain_id": "89acac79-38e7-497d-807c-a011e1310438", "ttl": null, "priority": null, "data": "192.0.2.3", "description": null } :param domain_id: domain ID :form id: record ID :form name: name of record FQDN :form type: type of record :form created_at: timestamp :form updated_at: timestamp :form ttl: time-to-live numeric value in seconds :form data: IPv4 address :form domain_id: domain ID :form priority: must be null for 'A' record :form description: UTF-8 text field :statuscode 200: Success :statuscode 401: Access Denied :statuscode 400: Invalid Object :statuscode 404: Not Found :statuscode 409: Duplicate Record Create a AAAA record for a domain **Example request**: .. sourcecode:: http POST /domains/89acac79-38e7-497d-807c-a011e1310438/records HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json { "name": "www.example.com.", "type": "AAAA", "data": "2001:db8:0:1234:0:5678:9:12" } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json Content-Length: 303 Location: http://localhost:9001/v1/domains/89acac79-38e7-497d-807c-a011e1310438/records/11112222-3333-4444-5555-666677778888 Date: Fri, 02 Nov 2012 19:56:26 GMT { "id": "11112222-3333-4444-5555-666677778888", "name": "www.example.com.", "type": "AAAA", "created_at": "2013-01-07T00:00:00.000000", "updated_at": null, "domain_id": "89acac79-38e7-497d-807c-a011e1310438", "priority": null, "ttl": null, "data": "2001:db8:0:1234:0:5678:9:12", "description": null } :param domain_id: domain ID :form id: record ID :form name: name of record FQDN :form type: type of record :form created_at: timestamp :form updated_at: timestamp :form ttl: time-to-live numeric value in seconds :form data: IPv6 address :form domain_id: domain ID :form priority: must be null for 'AAAA' records :form description: UTF-8 text field :statuscode 200: Success :statuscode 401: Access Denied :statuscode 400: Invalid Object :statuscode 404: Not Found :statuscode 409: Duplicate Record Create an MX record for a domain **Example request**: .. sourcecode:: http POST /domains/89acac79-38e7-497d-807c-a011e1310438/records HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json { "name": "example.com.", "type": "MX", "data": "mail.example.com.", "priority": 10 } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json Content-Length: 420 Location: http://localhost:9001/v1/domains/89acac79-38e7-497d-807c-a011e1310438/records/11112222-3333-4444-5555-666677778888 Date: Fri, 02 Nov 2012 19:56:26 GMT { "id": "11112222-3333-4444-5555-666677778888", "name": "www.example.com.", "type": "MX", "created_at": "2013-01-07T00:00:00.000000", "updated_at": null, "domain_id": "89acac79-38e7-497d-807c-a011e1310438", "priority": 10, "ttl": null, "data": "mail.example.com.", "description": null } :param domain_id: domain ID :form id: record ID :form name: name of record FQDN :form type: type of record :form created_at: timestamp :form ttl: time-to-live numeric value in seconds :form data: value of record :form domain_id: domain ID :form priority: priority of MX record :form description: UTF-8 text field :statuscode 200: Success :statuscode 401: Access Denied :statuscode 400: Invalid Object :statuscode 404: Not Found :statuscode 409: Duplicate Record Create a CNAME record for a domain **Example request**: .. sourcecode:: http POST /domains/89acac79-38e7-497d-807c-a011e1310438/records HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json { "name": "www.example.com.", "type": "CNAME", "data": "example.com." } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json Content-Length: 303 Location: http://localhost:9001/v1/domains/89acac79-38e7-497d-807c-a011e1310438/records/11112222-3333-4444-5555-666677778889 Date: Fri, 02 Nov 2012 19:56:26 GMT { "id": "11112222-3333-4444-5555-666677778889", "name": "www.example.com.", "type": "CNAME", "created_at": "2013-01-07T00:00:00.000000", "updated_at": null, "domain_id": "89acac79-38e7-497d-807c-a011e1310438", "priority": null, "ttl": null, "data": "example.com.", "description": null } :param domain_id: domain ID :form id: record ID :form name: alias for the CNAME :form type: type of record :form created_at: timestamp :form updated_at: timestamp :form ttl: time-to-live numeric value in seconds :form data: CNAME :form domain_id: domain ID :form priority: must be null for 'CNAME' records :form description: UTF-8 text field :statuscode 200: Success :statuscode 401: Access Denied :statuscode 400: Invalid Object :statuscode 404: Not Found :statuscode 409: Duplicate Record Create a TXT record for a domain **Example request**: .. sourcecode:: http POST /domains/89acac79-38e7-497d-807c-a011e1310438/records HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json { "name": "www.example.com.", "type": "TXT", "data": "This is a TXT record" } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json Content-Length: 303 Location: http://localhost:9001/v1/domains/89acac79-38e7-497d-807c-a011e1310438/records/11112222-3333-4444-5555-666677778899 Date: Fri, 02 Nov 2012 19:56:26 GMT { "id": "11112222-3333-4444-5555-666677778899", "name": "www.example.com.", "type": "TXT", "created_at": "2013-01-07T00:00:00.000000", "updated_at": null, "domain_id": "89acac79-38e7-497d-807c-a011e1310438", "priority": null, "ttl": null, "data": "This is a TXT record", "description": null } :param domain_id: domain ID :form id: record ID :form name: name of record FQDN :form type: type of record :form created_at: timestamp :form updated_at: timestamp :form ttl: time-to-live numeric value in seconds :form data: Text associated with record. :form domain_id: domain ID :form priority: must be null for 'TXT' records :form description: UTF-8 text field :statuscode 200: Success :statuscode 401: Access Denied :statuscode 400: Invalid Object :statuscode 404: Not Found :statuscode 409: Duplicate Record Create an SRV record for a domain **Example request**: .. sourcecode:: http POST /domains/89acac79-38e7-497d-807c-a011e1310438/records HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json { "name": "_sip._tcp.example.com.", "type": "SRV", "data": "0 5060 sip.example.com.", "priority": 30 } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json Content-Length: 399 Location: http://localhost:9001/v1/domains/89acac79-38e7-497d-807c-a011e1310438/records/11112222-3333-4444-5555-666677778999 Date: Fri, 02 Nov 2012 19:56:26 GMT { "id": "11112222-3333-4444-5555-66667777899", "name": "_sip._tcp.example.com.", "type": "SRV", "created_at": "2012-11-02T19:56:26.366792", "updated_at": null, "domain_id": "89acac79-38e7-497d-807c-a011e1310438", "ttl": null, "priority" : 30, "data": "0 5060 sip.example.com.", "description": null } :param domain_id: domain ID :form id: record ID :form name: name of service :form type: type of record :form created_at: timestamp :form updated_at: timestamp :form ttl: time-to-live numeric value in seconds :form data: weight port target :form domain_id: domain ID :form priority: priority of SRV record :form description: UTF-8 text field :statuscode 200: Success :statuscode 401: Access Denied :statuscode 400: Invalid Object :statuscode 404: Not Found :statuscode 409: Duplicate Record Create an NS record for a domain **Example request**: .. sourcecode:: http POST /domains/89acac79-38e7-497d-807c-a011e1310438/records HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json { "name": ".example.com.", "type": "NS", "data": "ns1.example.com." } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json Content-Length: 399 Location: http://localhost:9001/v1/domains/89acac79-38e7-497d-807c-a011e1310438/records/11112222-3333-4444-5555-666677789999 Date: Fri, 02 Nov 2012 19:56:26 GMT { "id": "11112222-3333-4444-5555-666677789999", "name": ".example.com.", "type": "NS", "created_at": "2012-11-02T19:56:26.366792", "updated_at": null, "domain_id": "89acac79-38e7-497d-807c-a011e1310438", "ttl": null, "priority" : null, "data": "ns1.example.com", "description": null } :param domain_id: domain ID :form id: record ID :form name: record name :form type: type of record :form created_at: timestamp :form updated_at: timestamps :form ttl: time-to-live numeric value in seconds :form data: record value :form domain_id: domain ID :form priority: must be null for 'NS' record :form description: UTF-8 text field :statuscode 200: Success :statuscode 401: Access Denied :statuscode 400: Invalid Object :statuscode 404: Not Found :statuscode 409: Duplicate Record Create a PTR record for a domain **Example request**: .. sourcecode:: http POST /domains/89acac79-38e7-497d-807c-a011e1310438/records HTTP/1.1 Host: 2.3.192.in-addr.arpa. Accept: application/json Content-Type: application/json { "name": "1.2.3.192.in-addr.arpa.", "type": "PTR", "data": "www.example.com." } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json Content-Length: 399 Location: http://localhost:9001/v1/domains/89acac79-38e7-497d-807c-a011e1310438/records/11112222-3333-4444-5555-666677889999 Date: Fri, 02 Nov 2012 19:56:26 GMT { "id": "11112222-3333-4444-5555-666677889999", "name": "1.2.3.192.in-addr.arpa.", "type": "PTR", "created_at": "2012-11-02T19:56:26.366792", "updated_at": null, "domain_id": "89acac79-38e7-497d-807c-a011e1310438", "ttl": null, "priority" : null, "data": "www.example.com", "description": null } :param domain_id: domain ID :form id: record ID :form name: PTR record name :form type: type of record :form created_at: timestamp :form updated_at: timestamp :form ttl: time-to-live numeric value in seconds :form data: DNS record value :form domain_id: domain ID :form priority: must be null for 'PTR' record :form description: UTF-8 text field :statuscode 200: Success :statuscode 401: Access Denied :statuscode 400: Invalid Object :statuscode 404: Not Found :statuscode 409: Duplicate Record Create an SPF record for a domain **Example request**: .. sourcecode:: http POST /domains/89acac79-38e7-497d-807c-a011e1310438/records HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json { "name": ".example.com.", "type": "SPF", "data": "v=spf1 +mx a:colo.example.com/28 -all" } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json Content-Length: 399 Location: http://localhost:9001/v1/domains/89acac79-38e7-497d-807c-a011e1310438/records/11112222-3333-4444-5555-666678889999 Date: Fri, 02 Nov 2012 19:56:26 GMT { "id": "11112222-3333-4444-5555-666678889999", "name": ".example.com.", "type": "SPF", "created_at": "2012-11-02T19:56:26.366792", "updated_at": null, "domain_id": "89acac79-38e7-497d-807c-a011e1310438", "ttl": null, "priority" : null, "data": "v=spf1 +mx a:colo.example.com/28 -all", "description": null } :param domain_id: domain ID :form id: record ID :form name: name of record :form type: type of record :form created_at: timestamp :form updated_at: timestamp :form ttl: time-to-live numeric value in seconds :form data: record value :form domain_id: domain ID :form priority: must be null for 'SPF' record :form description: UTF-8 text field :statuscode 200: Success :statuscode 401: Access Denied :statuscode 400: Invalid Object :statuscode 404: Not Found :statuscode 409: Duplicate Record Create an SSHFP record for a domain **Example request**: .. sourcecode:: http POST /domains/89acac79-38e7-497d-807c-a011e1310438/records HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json { "name": "www.example.com.", "type": "SSHFP", "data": "2 1 6c3c958af43d953f91f40e0d84157f4fe7b4a898" } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json Content-Length: 399 Location: http://localhost:9001/v1/domains/89acac79-38e7-497d-807c-a011e1310438/records/11112222-3333-4444-5555-666778889999 Date: Fri, 02 Nov 2012 19:56:26 GMT { "id": "11112222-3333-4444-5555-666778889999", "name": "www.example.com.", "type": "SSHFP", "created_at": "2012-11-02T19:56:26.366792", "updated_at": null, "domain_id": "89acac79-38e7-497d-807c-a011e1310438", "ttl": null, "priority" : null, "data": "2 1 6c3c958af43d953f91f40e0d84157f4fe7b4a898", "description": null } :param domain_id: domain ID :form id: record ID :form name: name of record :form type: type of record :form created_at: timestamp :form updated_at: timestamp :form ttl: time-to-live numeric value in seconds :form data: algorithm number, fingerprint type, fingerprint :form domain_id: domain ID :form priority: must be null for 'SSHFP' record :form description: UTF-8 text field :statuscode 200: Success :statuscode 401: Access Denied :statuscode 400: Invalid Object :statuscode 404: Not Found :statuscode 409: Duplicate Record Get a Record ------------- .. http:get:: /domains/(uuid:domain_id)/records/(uuid:id) Get a particular record **Example request**: .. sourcecode:: http GET /domains/09494b72b65b42979efb187f65a0553e/records/2e32e609-3a4f-45ba-bdef-e50eacd345ad HTTP/1.1 Host: example.com Accept: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "id": "2e32e609-3a4f-45ba-bdef-e50eacd345ad", "name": "www.example.com.", "type": "A", "created_at": "2012-11-02T19:56:26.366792", "updated_at": "2012-11-04T13:22:36.859786", "priority": null, "ttl": 3600, "data": "15.185.172.153", "domain_id": "89acac79-38e7-497d-807c-a011e1310438", "description": null } :param domain_id: Domain ID :param id: Record ID :form id: record ID :form name: name of record FQDN :form type: type of record :form created_at: timestamp :form updated_at: timestamp :form priority: priority of record :form ttl: time-to-live numeric value in seconds :form data: value of record :form description: UTF-8 text field :form domain_id: domain ID :statuscode 200: Success :statuscode 401: Access Denied :statuscode 404: Record Not Found Update a record --------------- .. http:put:: /domains/(uuid:domain_id)/records/(uuid:id) Updates a record **Example request**: .. sourcecode:: http PUT /domains/89acac79-38e7-497d-807c-a011e1310438/records/2e32e609-3a4f-45ba-bdef-e50eacd345ad Host: example.com Accept: application/json Content-Type: application/json { "name": "www.example.com.", "type": "A", "data": "192.0.2.5" } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json Content-Length: 446 Date: Sun, 04 Nov 2012 13:22:36 GMT { "id": "2e32e609-3a4f-45ba-bdef-e50eacd345ad", "name": "www.example.com.", "type": "A", "created_at": "2012-11-02T19:56:26.366792", "updated_at": "2012-11-04T13:22:36.859786", "priority": null, "ttl": 3600, "data": "192.0.2.5", "domain_id": "89acac79-38e7-497d-807c-a011e1310438", "description": null } :param domain_id: domain ID :param id: record ID :form id: record ID :form name: name of record FQDN :form type: type of record :form created_at: timestamp :form updated_at: timestamp :form priority: priority of record :form ttl: time-to-live numeric value in seconds :form data: value of record :form description: UTF-8 text field :form domain_id: domain ID :statuscode 200: Success :statuscode 401: Access Denied :statuscode 400: Invalid Object :statuscode 409: Duplicate Record Delete a record --------------- .. http:delete:: /domains/(uuid:domain_id)/records/(uuid:id) Delete a DNS resource record **Example request**: .. sourcecode:: http DELETE /domains/89acac79-38e7-497d-807c-a011e1310438/records/4ad19089-3e62-40f8-9482-17cc8ccb92cb HTTP/1.1 :param domain_id: domain ID :param id: record ID **Example response**: Content-Type: text/html; charset=utf-8 Content-Length: 0 Date: Sun, 04 Nov 2012 14:35:57 GMT List Records in a Domain ------------------------ .. http:get:: /domains/(uuid:domain_id)/records Lists records of a domain **Example request**: .. sourcecode:: http GET /domains/89acac79-38e7-497d-807c-a011e1310438/records HTTP/1.1 Host: example.com Accept: application/json **Example response**: .. sourcecode:: http Content-Type: application/json Content-Length: 1209 Date: Sun, 04 Nov 2012 13:58:21 GMT { "records": [ { "id": "2e32e609-3a4f-45ba-bdef-e50eacd345ad", "name": "www.example.com.", "type": "A", "ttl": 3600, "created_at": "2012-11-02T19:56:26.000000", "updated_at": "2012-11-04T13:22:36.000000", "data": "15.185.172.153", "domain_id": "89acac79-38e7-497d-807c-a011e1310438", "tenant_id": null, "priority": null, "description": null, "version": 1 }, { "id": "8e9ecf3e-fb92-4a3a-a8ae-7596f167bea3", "name": "host1.example.com.", "type": "A", "ttl": 3600, "created_at": "2012-11-04T13:57:50.000000", "updated_at": null, "data": "15.185.172.154", "domain_id": "89acac79-38e7-497d-807c-a011e1310438", "tenant_id": null, "priority": null, "description": null, "version": 1 }, { "id": "4ad19089-3e62-40f8-9482-17cc8ccb92cb", "name": "web.example.com.", "type": "CNAME", "ttl": 3600, "created_at": "2012-11-04T13:58:16.393735", "updated_at": null, "data": "www.example.com.", "domain_id": "89acac79-38e7-497d-807c-a011e1310438", "tenant_id": null, "priority": null, "description": null, "version": 1 } ] } :param domain_id: domain ID :form id: record id :form name: name of record FQDN :form type: type of record :form created_at: timestamp :form updated_at: timestamp :form priority: priority of record :form ttl: time-to-live numeric value in seconds :form data: value of record :form description: UTF-8 text field :form domain_id: domain ID :statuscode 200: Success :statuscode 401: Access Denied designate-2.0.0/doc/source/rest/v1/servers.rst0000664000567000056710000001005112701406241022402 0ustar jenkinsjenkins00000000000000Servers ======= Server entries are used to generate NS records for zones.. TODO: More detail. TODO: Server Groups Concept. Create Server ------------- .. http:post:: /servers Create a DNS server **Example request**: .. sourcecode:: http POST /servers HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json { "name": "ns1.example.org." } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "id": "384a9b20-239c-11e2-81c1-0800200c9a66", "name": "ns1.example.org.", "created_at": "2011-01-21T11:33:21Z", "updated_at": null } :form name: Server hostname :statuscode 200: Success :statuscode 401: Access Denied :statuscode 409: Conflict Get Server ---------- .. http:get:: /servers/(uuid:server_id) Lists all configured DNS servers **Example request**: .. sourcecode:: http GET /servers/384a9b20-239c-11e2-81c1-0800200c9a66 HTTP/1.1 Host: example.com Accept: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "id": "384a9b20-239c-11e2-81c1-0800200c9a66", "name": "ns1.example.org.", "created_at": "2011-01-21T11:33:21Z", "updated_at": null } :param server_id: The server's unique id :type server_id: uuid :form name: Server hostname :form created_at: timestamp :form updated_at: timestamp :statuscode 200: Success :statuscode 401: Access Denied :statuscode 404: Not Found Update Server ------------- .. http:put:: /servers/(uuid:server_id) Create a DNS server **Example request**: .. sourcecode:: http PUT /servers/879c1100-9c92-4244-bc83-9535ee6534d0 HTTP/1.1 Content-Type: application/json Accept: application/json Content-Type: application/json { "name": "ns1.example.org." } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "id": "879c1100-9c92-4244-bc83-9535ee6534d0", "name": "ns1.example.org.", "created_at": "2012-11-02T02:55:44.000000", "updated_at": "2012-11-02T02:58:41.993556" } :form id: UUID server_id :form name: Server hostname :form created_at: timestamp :form updated_at: timestamp :statuscode 200: Success :statuscode 401: Access Denied :statuscode 404: Server Not Found :statuscode 409: Duplicate Server List Servers ------------ .. http:get:: /servers Lists all configured DNS servers **Example request**: .. sourcecode:: http GET /servers HTTP/1.1 Host: example.com Accept: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json [ { "id": "384a9b20-239c-11e2-81c1-0800200c9a66", "name": "ns1.example.org.", "created_at": "2011-01-21T11:33:21Z", "updated_at": null }, { "id": "cf661142-e577-40b5-b3eb-75795cdc0cd7", "name": "ns2.example.org.", "created_at": "2011-01-21T11:33:21Z", "updated_at": "2011-01-21T11:33:21Z" } ] :form id: UUID server_id :form name: Server hostname :form created_at: timestamp :form updated_at: timestamp :statuscode 200: Success :statuscode 401: Access Denied Delete Server ------------- .. http:delete:: /servers/(uuid:server_id) Deletes a specified server **Example request**: .. sourcecode:: http DELETE /servers/5d1d7879-b778-4f77-bb95-02f4a5a224d8 HTTP/1.1 Host: example.com **Example response** .. sourcecode:: http HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8 Content-Length: 0 Date: Thu, 01 Nov 2012 10:00:00 GMT :statuscode 200: Success :statuscode 401: Access Denied :statuscode 404: Not Found designate-2.0.0/doc/source/rest/v1/domains.rst0000664000567000056710000001461112701406241022351 0ustar jenkinsjenkins00000000000000Domains ======= Domain entries are used to generate zones containing RR TODO: More detail. Create Domain ------------- .. http:post:: /domains Create a domain **Example request**: .. sourcecode:: http POST /domains HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json { "name": "domain1.com.", "ttl": 3600, "email": "nsadmin@example.org" } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "id": "89acac79-38e7-497d-807c-a011e1310438", "name": "domain1.com.", "ttl": 3600, "serial": 1351800588, "email": "nsadmin@example.org", "created_at": "2012-11-01T20:09:48.094457", "updated_at": null, "description": null } :form created_at: timestamp :form updated_at: timestamp :form name: domain name :form id: uuid :form ttl: time-to-live numeric value in seconds :form serial: numeric seconds :form email: email address :form description: UTF-8 text field :statuscode 200: Success :statuscode 401: Access Denied :statuscode 400: Invalid Object :statuscode 409: Duplicate Domain Get a Domain ------------- .. http:get:: /domains/(uuid:id) Lists a particular domain **Example request**: .. sourcecode:: http GET /domains/09494b72-b65b-4297-9efb-187f65a0553e HTTP/1.1 Host: example.com Accept: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "id": "09494b72-b65b-4297-9efb-187f65a0553e", "name": "domain1.com.", "ttl": 3600, "serial": 1351800668, "email": "nsadmin@example.org", "created_at": "2012-11-01T20:11:08.000000", "updated_at": null, "description": null } :form created_at: timestamp :form updated_at: timestamp :form name: domain name :form id: uuid :form ttl: time-to-live numeric value in seconds :form serial: numeric seconds :form email: email address :form description: UTF-8 text field :statuscode 200: Success :statuscode 401: Access Denied Update a Domain --------------- .. http:put:: /domains/(uuid:id) updates a domain **Example request**: .. sourcecode:: http PUT /domains/09494b72-b65b-4297-9efb-187f65a0553e HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json { "name": "domainnamex.com", "ttl": 7200, "email": "nsadmin@example.org" } **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json Content-Length: 422 Date: Fri, 02 Nov 2012 01:06:19 GMT { "id": "09494b72-b65b-4297-9efb-187f65a0553e", "name": "domain1.com.", "email": "nsadmin@example.org", "ttl": 7200, "serial": 1351818367, "created_at": "2012-11-02T00:58:42.000000", "updated_at": "2012-11-02T01:06:07.000000", "description": null } :form created_at: timestamp :form updated_at: timestamp :form name: domain name :form id: uuid :form ttl: time-to-live numeric value in seconds :form serial: numeric seconds :form email: email address :form description: UTF-8 text field :statuscode 200: Success :statuscode 401: Access Denied :statuscode 400: Invalid Object :statuscode 400: Domain not found :statuscode 409: Duplicate Domain Delete a Domain --------------- .. http:delete:: /domains/(uuid:id) delete a domain **Example request**: .. sourcecode:: http DELETE /domains/09494b72-b65b-4297-9efb-187f65a0553e HTTP/1.1 Host: example.com **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: text/html; charset=utf-8 Content-Length: 0 Date: Fri, 02 Nov 2012 01:26:06 GMT :statuscode 200: Success :statuscode 401: Access Denied :statuscode 400: Invalid Object :statuscode 404: Domain not found Get Servers Hosting a Domain ---------------------------- .. http:get:: /domains/(uuid:id)/servers Lists the nameservers hosting a particular domain **Example request**: .. sourcecode:: http GET /domains/09494b72-b65b-4297-9efb-187f65a0553e/servers HTTP/1.1 Host: example.com Accept: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json [ { "id": "384a9b20-239c-11e2-81c1-0800200c9a66", "name": "ns1.provider.com.", "created_at": "2011-01-21T11:33:21Z", "updated_at": null }, { "id": "cf661142-e577-40b5-b3eb-75795cdc0cd7", "name": "ns2.provider.com.", "created_at": "2011-01-21T11:33:21Z", "updated_at": "2011-01-21T11:33:21Z" } ] :form id: UUID server_id :form name: Server hostname :form created_at: timestamp :form updated_at: timestamp :statuscode 200: Success :statuscode 401: Access Denied :statuscode 404: Domain Not Found List Domains ------------ .. http:get:: /domains Lists all domains **Example request**: .. sourcecode:: http GET /domains HTTP/1.1 Host: example.com Accept: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "domains": [ { "name": "domain1.com.", "created_at": "2012-11-01T20:11:08.000000", "email": "nsadmin@example.org", "ttl": 3600, "serial": 1351800668, "id": "09494b72-b65b-4297-9efb-187f65a0553e" }, { "name": "domain2.com.", "created_at": "2012-11-01T20:09:48.000000", "email": "nsadmin@example.org", "ttl": 3600, "serial": 1351800588, "id": "89acac79-38e7-497d-807c-a011e1310438" } ] } :form name: domain name :form created_at: timestamp :form email: email address :form ttl: time-to-live numeric value in seconds :form serial: numeric seconds :param id: Domain ID :type id: uuid :statuscode 200: Success :statuscode 401: Access Denied designate-2.0.0/doc/source/rest/v1/reports.rst0000664000567000056710000001074412701406241022420 0ustar jenkinsjenkins00000000000000.. Copyright 2014 Hewlett-Packard Development Company, L.P. Author: Endre Karlson Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Reports ======= Overview -------- *Note*: Reports is an extension and needs to be enabled before it can be used. If Designate returns a 404 error, ensure that the following line has been added to the designate.conf file:: enabled_extensions_v1 = reports, ... Reports about things in the system Get all tenants --------------- .. http:get:: /reports/tenants Fetch all tenants **Example request**: .. sourcecode:: http GET /reports/tenants HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "tenants": [{ "domain_count": 2, "id": "71ee6d049a49435c8f7dd002cfe08d96" }] } :form tenants: List of tenants :statuscode 200: Success :statuscode 401: Access Denied Report tenant resources ----------------------- .. http:get:: /reports/tenants/(tenant_id) Report tenant resources **Example request**: .. sourcecode:: http GET /reports/tenants/3d8391080d4a4ec4b3eadf18e6b1539a HTTP/1.1 Host: example.com Accept: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "domain_count": 0, "domains": [], "id": "3d8391080d4a4ec4b3eadf18e6b1539a" } :param tenant_id: Tenant Id to get reports for :type tenant_id: string :form domain_count: integer :form domains: Server hostname :form id: Tenant Id :statuscode 200: Success :statuscode 401: Access Denied Report resource counts ---------------------- .. http:get:: /reports/counts Report resource counts **Example request**: .. sourcecode:: http GET /reports/counts HTTP/1.1 Host: example.com Accept: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "domains": 0, "records": 0, "tenants": 0 } :form domains: Domains count :form records: Records count :form tenants: Tenants count :statuscode 200: Success :statuscode 401: Access Denied Report tenant counts ---------------------- .. http:get:: /reports/counts/tenants Report tenant counts **Example request**: .. sourcecode:: http GET /reports/counts/tenants HTTP/1.1 Host: example.com Accept: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "tenants": 0 } :form tenants: Tenants count :statuscode 200: Success :statuscode 401: Access Denied Report domain counts ---------------------- .. http:get:: /reports/counts/domains Report domain counts **Example request**: .. sourcecode:: http GET /reports/counts/domains HTTP/1.1 Host: example.com Accept: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "domains": 0 } :form domains: Domains count :statuscode 200: Success :statuscode 401: Access Denied Report record counts ---------------------- .. http:get:: /reports/counts/records Report record counts **Example request**: .. sourcecode:: http GET /reports/counts/records HTTP/1.1 Host: example.com Accept: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "records": 0 } :form records: Records count :statuscode 200: Success :statuscode 401: Access Denieddesignate-2.0.0/doc/source/rest/v1/sync.rst0000664000567000056710000000474512701406241021702 0ustar jenkinsjenkins00000000000000.. Copyright 2014 Hewlett-Packard Development Company, L.P. Author: Endre Karlson Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Synchronize =========== Overview -------- *Note*: Synchronize is an extension and needs to be enabled before it can be used. If Designate returns a 404 error, ensure that the following line has been added to the designate.conf file:: enabled_extensions_v1 = sync, ... Trigger a synchronization of one or more resource(s) in the system. Synchronize all domains ----------------------- .. http:post:: /domains/sync Synchronize all domains **Example request**: .. sourcecode:: http POST /domains/sync HTTP/1.1 Host: example.com Content-Type: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json :statuscode 200: Success :statuscode 401: Access Denied Synchronize one domain ---------------------- .. http:post:: /domains/(uuid:domain_id)/sync Synchronize one domain **Example request**: .. sourcecode:: http POST /domains/1dd7851a-74e7-4ddb-b6e8-38a610956bd5/sync HTTP/1.1 Host: example.com Content-Type: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json :statuscode 200: Success :statuscode 401: Access Denied Synchronize one record ---------------------- .. http:post:: /domains/(uuid:domain_id)/records/(uuid:record_id)/sync Synchronize one record **Example request**: .. sourcecode:: http POST /domains/1dd7851a-74e7-4ddb-b6e8-38a610956bd5/records/1dd7851a-74e7-4ddb-b6e8-38a610956bd5/sync HTTP/1.1 Host: example.com Content-Type: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json :statuscode 200: Success :statuscode 401: Access Denieddesignate-2.0.0/doc/source/rest/v1/quotas.rst0000664000567000056710000000656312701406241022242 0ustar jenkinsjenkins00000000000000.. Copyright 2014 Hewlett-Packard Development Company, L.P. Author: Endre Karlson Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Quotas ====== Overview -------- The quotas extension can be used to retrieve a tenant's absolute limits. *Note*: Quotas is an extension and needs to be enabled before it can be used. If Designate returns a 404 error, ensure that the following line has been added to the designate.conf file:: enabled_extensions_v1 = quotas, ... Once this line has been added, restart the designate-central and designate-api services. Get Quotas ---------- .. http:get:: /quotas/TENANT_ID Retrieves quotas for tenant with the specified TENANT_ID. The following example retrieves the quotas for tenant 12345. **Example request:** .. sourcecode:: http GET /v1/quotas/12345 HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json **Example response:** .. sourcecode:: http HTTP/1.1 201 Created Content-Type: application/json { "api_export_size": 1000, "domains": 10, "recordset_records": 20, "domain_records": 500, "domain_recordsets": 500 } :from api_export_size: Number of recordsets allowed in a zone export :form domains: Number of domains the tenant is allowed to own :form recordset_records: Number of records allowed per recordset :form domain_records: Number of records allowed per domain :form domain_recordsets: Number of recordsets allowed per domain :statuscode 200: Success :statuscode 401: Access Denied Update Quotas ------------- .. http:put:: /quotas/TENANT_ID Updates the specified quota(s) to their new values. **Example request:** .. sourcecode:: http PUT /v1/quotas/12345 HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json { "domains": 1000, "domain_records": 50 } **Example response:** .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json { "api_export_size": 1000, "domains": 1000, "recordset_records": 20, "domain_records": 50, "domain_recordsets": 500 } :statuscode 200: Success :statuscode 401: Access Denied Reset Quotas to Default ----------------------- .. http:delete:: /quotas/TENANT_ID Restores the tenant's quotas back to their default values. **Example request:** .. sourcecode:: http DELETE /v1/quotas/12345 HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json **Example response:** .. sourcecode:: http HTTP/1.1 200 Success :statuscode 200: Success :statuscode 401: Access Denied designate-2.0.0/doc/source/rest/v1/diagnostics.rst0000664000567000056710000000322412701406241023224 0ustar jenkinsjenkins00000000000000.. Copyright 2014 Hewlett-Packard Development Company, L.P. Author: Endre Karlson Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Diagnostics =========== Overview -------- *Note*: Diagnostics is an extension and needs to be enabled before it can be used. If Designate returns a 404 error, ensure that the following line has been added to the designate.conf file:: enabled_extensions_v1 = diagnostic, ... Diagnose parts of the system. Ping a host on a RPC topic -------------------------- .. http:get:: /diagnostics/ping/(topic)/(host) Ping a host on a RPC topic **Example request**: .. sourcecode:: http GET /diagnostics/ping/agents/msdns-1 HTTP/1.1 Host: example.com Accept: application/json Content-Type: application/json **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "host": "rpc-hostname", "status": true, "backend": "msdns", "storage": {"status": true, "message": "..."} } :statuscode 200: Success :statuscode 401: Access Denieddesignate-2.0.0/doc/source/api.rst0000664000567000056710000000047212701406241020165 0ustar jenkinsjenkins00000000000000.. _api: *** API *** .. _api-middleware: API Middleware =============== .. automodule:: designate.api.middleware :members: :undoc-members: :show-inheritance: .. _api-service: API Service =========== .. automodule:: designate.api.service :members: :undoc-members: :show-inheritance: designate-2.0.0/doc/source/developer-guidelines.rst0000664000567000056710000000315012701406241023523 0ustar jenkinsjenkins00000000000000******************** Developer Guidelines ******************** Example DNS Names and IP Space ============================== The IANA has allocated several special purpose domains and IP blocks for use as examples in code and documentation. Where possible, these domains and IP blocks should be preferred. There are some cases where it will not be possible to follow this guidance, for example, there is currently no reserved IDN domain name. We prefer to use these names and IP blocks to avoid causing any unexpected collateral damage to the rightful owners of the non-reserved names and IP space. For example, publishing an email address in our codebase will more than likely be picked up by spammers, while published URLs etc using non-reserved names or IP space will likely trigger search indexers etc to begin crawling. Reserved Domains ---------------- Reserved DNS domains are documented here: `IANA Special Use Domain Names`_. Several common reserved domains: * example.com. * example.net. * example.org. Reserved IP Space ----------------- Reserved IP space is documented here: `IANA IPv4 Special Registry`_, and `IANA IPv6 Special Registry`_. Several common reserved IP blocks: * 192.0.2.0/24 * 198.51.100.0/24 * 203.0.113.0/24 * 2001:db8::/32 .. _IANA Special Use Domain Names: http://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml .. _IANA IPv4 Special Registry: http://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml .. _IANA IPv6 Special Registry: http://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml designate-2.0.0/doc/source/pools/0000775000567000056710000000000012701406373020021 5ustar jenkinsjenkins00000000000000designate-2.0.0/doc/source/pools/scheduler.rst0000664000567000056710000000546612701406241022536 0ustar jenkinsjenkins00000000000000.. Copyright 2016 Hewlett Packard Enterprise Development Company, L.P. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. .. _pool_scheduler: ============== Pool Scheduler ============== In designate we have a plugable scheduler filter interface. You can set an ordered list of filters to run on each zone create api request. We provide a few basic filters below, and creating custom filters follows a similar pattern to schedulers. You can create your own by extending :class:`designate.scheduler.filters.base.Filter` and registering a new entry point in the ``designate.scheduler.filters`` namespace like so in your ``setup.cfg`` file: .. code-block:: ini [entry_points] designate.scheduler.filters = my_custom_filter = my_extention.filters.my_custom_filter:MyCustomFilter The new filter can be added to the ``scheduler_filters`` list in the ``[service:central]`` section like so: .. code-block:: ini [service:central] scheduler_filters = attribute, pool_id_attribute, fallback, random, my_custom_filter The filters list is ran from left to right, so if the list is set to: .. code-block:: ini [service:central] scheduler_filters = attribute, random There will be two filters ran, the :class:`designate.scheduler.filters.attribute_filter.AttributeFilter` followed by :class:`designate.scheduler.filters.random_filter.RandomFilter` Default Provided Filters ======================== Base Class - Filter ------------------- .. autoclass:: designate.scheduler.filters.base.Filter :members: Attribute Filter ---------------- .. autoclass:: designate.scheduler.filters.attribute_filter.AttributeFilter :members: name :show-inheritance: Pool ID Attribute Filter ------------------------ .. autoclass:: designate.scheduler.filters.pool_id_attribute_filter.PoolIDAttributeFilter :members: :undoc-members: :show-inheritance: Random Filter ------------- .. autoclass:: designate.scheduler.filters.random_filter.RandomFilter :members: name :show-inheritance: Fallback Filter --------------- .. autoclass:: designate.scheduler.filters.fallback_filter.FallbackFilter :members: name :show-inheritance: Default Pool Filter ------------------- .. autoclass:: designate.scheduler.filters.default_pool_filter.DefaultPoolFilter :members: name :show-inheritance: designate-2.0.0/doc/source/quota.rst0000664000567000056710000000047712701406241020552 0ustar jenkinsjenkins00000000000000.. _quota: ***** Quota ***** .. _quota-base: Quota Base ========== .. automodule:: designate.quota.base :members: :undoc-members: :show-inheritance: .. _quota-storage: Quota Storage ============= .. automodule:: designate.quota.impl_storage :members: :undoc-members: :show-inheritance: designate-2.0.0/doc/source/howtos/0000775000567000056710000000000012701406373020210 5ustar jenkinsjenkins00000000000000designate-2.0.0/doc/source/howtos/manage-ptr-records.rst0000664000567000056710000003052512701406241024433 0ustar jenkinsjenkins00000000000000.. Copyright 2015 Rackspace Hosting Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. =========================== How To Manage PTR Records =========================== PTR Record Basics ================= `PTR` records provide a reverse mapping from a single IP or set of IP addresses to a domain. For example, .. code-block:: bash $ dig -x 192.0.2.5 +short example.org. The way this works in the DNS system it through the `in-addr.arpa.` zone. For example .. code-block:: bash $ dig example.org +short 192.0.2.12 $ dig -x 192.0.2.12 ; <<>> DiG 9.9.5-3ubuntu0.1-Ubuntu <<>> -x 192.0.2.12 ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 3431 ;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4000 ;; QUESTION SECTION: ;12.55.168.192.in-addr.arpa. IN PTR example.org. ;; AUTHORITY SECTION: 12.55.168.192.in-addr.arpa. 3600 IN NS ns1.example.org. ;; Query time: 40 msec ;; SERVER: 127.0.0.1#53(127.0.0.1) ;; WHEN: Fri Feb 20 19:05:44 UTC 2015 ;; MSG SIZE rcvd: 119 In the question section we see the address being requested from the DNS system as `12.55.168.192.in-addr.arpa.`. As you can see, the IP address has been reversed in order to function similarly to a domain name where the more specific elements come first. The reversed IP address is then added to the `in-addr.arpa.` domain, at which point the DNS system can perform a simple look up to find any `PTR` records that describe what domain name, if any, maps to that IP. Create a PTR Record in Designate ================================ To create a `PTR` record in Designate, there are two requirements. 1. A domain that should be pointed to from the IP 2. A `in-addr.arpa.` zone entry that will receive the actual `PTR` record Using the V2 API ---------------- To begin lets create a zone that we want to return when we do our reverse lookup. .. code-block:: http POST /v2/zones HTTP/1.1 Accept: application/json Content-Type: application/json { "name": "example.org.", "email": "admin@example.org", "ttl": 3600, "description": "A great example zone" } Here is the JSON response describing the new zone. .. code-block:: http HTTP/1.1 202 Accepted Location: http://127.0.0.1:9001/v2/zones/fe078042-0aa3-4500-a81e-8f328f79bf75 Content-Length: 476 Content-Type: application/json; charset=UTF-8 X-Openstack-Request-Id: req-bfcd0723-624c-4ec2-bbd5-99e985efe8db Date: Fri, 20 Feb 2015 21:20:28 GMT Connection: keep-alive { "email": "admin@example.org", "project_id": "noauth-project", "action": "CREATE", "version": 1, "pool_id": "794ccc2c-d751-44fe-b57f-8894c9f5c842", "created_at": "2015-02-20T21:20:28.000000", "name": "example.org.", "id": "fe078042-0aa3-4500-a81e-8f328f79bf75", "serial": 1424467228, "ttl": 3600, "updated_at": null, "links": { "self": "http://127.0.0.1:9001/v2/zones/fe078042-0aa3-4500-a81e-8f328f79bf75" }, "description": "A great example zone", "status": "PENDING" } .. note:: The `status` is `PENDING`. If we make a `GET` request to the `self` field in the zone, it will most likely have been processed and updated to `ACTIVE`. Now that we have a zone we'd like to use for our reverse DNS lookup, we need to add an `in-addr.arpa.` zone that includes the IP address we'll be looking up. Lets configure `192.0.2.11` to return our `example.org.` domain name when we do a reverse look up. .. code-block:: http POST /v2/zones HTTP/1.1 Accept: application/json Content-Type: application/json { "name": "11.2.0.192.in-addr.arpa.", "email": "admin@example.org", "ttl": 3600, "description": "A in-addr.arpa. zone for reverse lookups." } As you can see, in the `name` field we've reversed our IP address and used that as a subdomain in the `in-addr.arpa.` zone. Here is the response. .. code-block:: http HTTP/1.1 202 Accepted Location: http://127.0.0.1:9001/v2/zones/1bed5d24-d487-4410-b813-f1c637db0ba3 Content-Length: 512 Content-Type: application/json; charset=UTF-8 X-Openstack-Request-Id: req-4e691123-045e-4f8e-ae50-b5eabb5af3fa Date: Fri, 20 Feb 2015 21:35:41 GMT Connection: keep-alive { "email": "admin@example.org", "project_id": "noauth-project", "action": "CREATE", "version": 1, "pool_id": "794ccc2c-d751-44fe-b57f-8894c9f5c842", "created_at": "2015-02-20T21:35:41.000000", "name": "11.2.0.192.in-addr.arpa.", "id": "1bed5d24-d487-4410-b813-f1c637db0ba3", "serial": 1424468141, "ttl": 3600, "updated_at": null, "links": { "self": "http://127.0.0.1:9001/v2/zones/1bed5d24-d487-4410-b813-f1c637db0ba3" }, "description": "A in-addr.arpa. zone for reverse lookups.", "status": "PENDING" } Now that we have our `in-addr.arpa.` zone, we add a new `PTR` record to the zone. .. code-block:: http POST /v2/zones/1bed5d24-d487-4410-b813-f1c637db0ba3/recordsets HTTP/1.1 Content-Type: application/json Accept: application/json { "name": "11.2.0.192.in-addr.arpa.", "description": "A PTR recordset", "type": "PTR", "ttl": 3600, "records": [ "example.org." ] } Here is the response. .. code-block:: http HTTP/1.1 202 Accepted Location: http://127.0.0.1:9001/v2/zones/1bed5d24-d487-4410-b813-f1c637db0ba3/recordsets/a3dca24e-3eba-4523-8607-c0ad4b9a9272 Content-Length: 499 Content-Type: application/json; charset=UTF-8 X-Openstack-Request-Id: req-5b7044d0-591a-445a-839f-1403b1455824 Date: Fri, 20 Feb 2015 21:42:45 GMT Connection: keep-alive { "type": "PTR", "action": "CREATE", "version": 1, "created_at": "2015-02-20T21:42:45.000000", "zone_id": "1bed5d24-d487-4410-b813-f1c637db0ba3", "name": "11.2.0.192.in-addr.arpa.", "id": "a3dca24e-3eba-4523-8607-c0ad4b9a9272", "ttl": 3600, "records": [ "example.org." ], "updated_at": null, "links": { "self": "http://127.0.0.1:9001/v2/zones/1bed5d24-d487-4410-b813-f1c637db0ba3/recordsets/a3dca24e-3eba-4523-8607-c0ad4b9a9272" }, "description": "A PTR recordset", "status": "PENDING" } We should now have a correct `PTR` record assigned in our nameserver that we can test. .. note:: As the `in-addr.arpa.` zone is considered an admin zone, you may need to get admin rights in order to create the necessary subdomains. Lets test it out! .. code-block:: bash $ dig @localhost -x 192.0.2.11 ; <<>> DiG 9.9.5-3ubuntu0.1-Ubuntu <<>> @localhost -x 192.0.2.11 ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32832 ;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1 ;; WARNING: recursion requested but not available ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;11.2.0.192.in-addr.arpa. IN PTR ;; ANSWER SECTION: 11.2.0.192.in-addr.arpa. 3600 IN PTR example.org. ;; AUTHORITY SECTION: 11.2.0.192.in-addr.arpa. 3600 IN NS ns1.example.org. ;; Query time: 3 msec ;; SERVER: 127.0.0.1#53(127.0.0.1) ;; WHEN: Fri Feb 20 21:45:53 UTC 2015 ;; MSG SIZE rcvd: 98 As you can see from the answer section everything worked as expected. Advanced Usage -------------- You can add many `PTR` records to a larger subnet by using a more broadly defined `in-addr.arpa.` zone. For example, if we wanted to ensure *any* IP in a subnet resolves to a specific domain. .. code-block:: http POST /v2/zones HTTP/1.1 Accept: application/json Content-Type: application/json { "name": "2.0.192.in-addr.arpa.", "ttl": 3600, "email": "admin@example.com" } We then could use the corresponding domain to create a `PTR` record for a specific IP. .. code-block:: http POST /v2/zones/$domain_uuid/recordsets HTTP/1.1 Accept: application/json Content-Type: application/json { "name": "3.2.0.192.in-addr.arpa.", "type": "PTR" "ttl": 3600, "records": [ "cats.example.com." ] } When we do our reverse look, we should see `cats.example.com.` .. code-block:: bash $ dig @localhost -x 192.0.2.3 +short cats.example.com. Success! You can further specify `in-addr.arpa.` zones to chunks of IP addresses by using Classless in-addr.arpa. Delegation. See `RFC 2317`_ for more information. .. note:: In BIND9, when creating a new `PTR` we could skip the zone name. For example, if the zone is `2.0.192.in-addr.arpa.`, using `12` for the record name is ends up as `12.2.0.192.in-addr.arpa.`. In Designate, the name of a record MUST be a complete host name. .. _RFC 2317: https://tools.ietf.org/html/rfc2317 Using the V1 API ---------------- Using the V1 REST interface lets start by creating a domain. .. code-block:: http POST /v1/domains HTTP/1.1 Content-Type: application/json { "name": "example.com.", "ttl": 3600, "email": "admin@example.com" } This should return the JSON document describing the new domain. .. code-block:: http HTTP/1.1 200 OK Content-Type: application/json Content-Length: 238 Location: http://127.0.0.1:9001/v1/domains/77c4f4aa-b8c9-4df5-af8e-b54e5fcadef7 X-Openstack-Request-Id: req-c3f8478d-1665-4b40-9545-9a856fac17ea Date: Fri, 20 Feb 2015 19:35:37 GMT Connection: keep-alive { "updated_at": null, "ttl": 3600, "serial": 1424460937, "name": "example.com.", "id": "77c4f4aa-b8c9-4df5-af8e-b54e5fcadef7", "email": "admin@example.com", "description": null, "created_at": "2015-02-20T19:35:37.000000" } Now that we have a domain we want to return when we use our `PTR` record, we'll create the `in-addr.arpa.` domain that will be used when looking up the IP address. Lets configure `192.0.2.10` to return our `example.com.` domain name when we do a reverse look up. .. code-block:: http POST /v1/domains HTTP/1.1 Content-Type: application/json { "name": "10.2.0.192.in-addr.arpa.", "ttl": 1200, "email": "admin@thedns.com" } We should get a response like .. code-block:: http HTTP/1.1 200 OK Content-Type: application/json Content-Length: 252 Location: http://127.0.0.1:9001/v1/domains/d098abaa-37e3-40e5-b7c5-3794b5a0ec32 X-Openstack-Request-Id: req-bc2b1796-bd11-47a9-bb06-fd6a870a4bc2 Date: Fri, 20 Feb 2015 19:43:15 GMT Connection: keep-alive { "updated_at": null, "ttl": 1200, "serial": 1424461395, "name": "10.2.0.192.in-addr.arpa.", "id": "d098abaa-37e3-40e5-b7c5-3794b5a0ec32", "email": "admin@thedns.com", "description": null, "created_at": "2015-02-20T19:43:15.000000" } We will use this `in-addr.arpa.` domain to create the actual `PTR` record. .. code-block:: http POST /v1/domains/d098abaa-37e3-40e5-b7c5-3794b5a0ec32/records HTTP/1.1 Content-Type: application/json { "name": "10.2.0.192.in-addr.arpa.", "type": "PTR", "data": "example.com." } Here is the response. .. code-block:: http HTTP/1.1 200 OK Content-Type: application/json Content-Length: 315 Location: http://127.0.0.1:9001/v1/domains/d098abaa-37e3-40e5-b7c5-3794b5a0ec32/records/0476ed89-9823-4f8e-a991-79422bc2e490 X-Openstack-Request-Id: req-36588ba6-e91a-4456-9706-8d156ea7cfd2 Date: Fri, 20 Feb 2015 19:48:01 GMT Connection: keep-alive { "updated_at": null, "type": "PTR", "ttl": null, "priority": null, "name": "11.2.0.192.in-addr.arpa.", "id": "0476ed89-9823-4f8e-a991-79422bc2e490", "domain_id": "d098abaa-37e3-40e5-b7c5-3794b5a0ec32", "description": null, "data": "example.com.", "created_at": "2015-02-20T19:48:01.000000" } We should now have a correct `PTR` record assigned in our nameserver that we can test. We'll use dig to make sure our reverse lookup is resolving correctly. .. code-block:: bash $ dig @localhost -x 192.0.2.10 +short example.com. It worked! designate-2.0.0/doc/source/howtos/secondary_zones.rst0000664000567000056710000003044212701406241024144 0ustar jenkinsjenkins00000000000000.. Copyright 2014 Hewlett-Packard Development Company, L.P. Author: Endre Karlson Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Secondary Zones =============== The Designate v2 API introduced functionality that allows Designate to act as a DNS slave, rather than a master for a zone. This is accomplished by completing a zone transfer (AXFR) from a DNS server managed outside of Designate. RecordSets / Records -------------------- Changes to secondary zones are managed outside of Designate. Users must make the changes they wish, and prompt a fresh zone transfer (AXFR) into Designate to make those changes live on any DNS servers Designate manages. Setup ----- To add a secondary zone to Designate, there must be a DNS master for the zone, to which Designate can act as a slave. For this guide, we assume that you have already set this up. The remaining Designate set up will be similar to a non-secondary zone setup. You'll need a primary DNS server for Designate to manage and transfer secondary zones to. In our examples we'll use the following values: *Name* - example.com. *Masters* - 192.168.27.100 Setup - example NSD4 ^^^^^^^^^^^^^^^^^^^^ Skip this section if you have a master already to use. .. note:: For this it is assumed that you are running on Ubuntu. Install ^^^^^^^ For some reason there's a bug with the nsd package so it doesn't create the user that it needs for the installation. So we'll create that before installing the package. .. code-block:: bash $ sudo apt-get install nsd Configure ^^^^^^^^^ .. code-block:: bash $ sudo zcat /usr/share/doc/nsd/examples/nsd.conf.sample.gz >/tmp/nsd.conf $ sudo mv /tmp/nsd.conf /etc/nsd/nsd.conf Add the following to /etc/nsd/nsd.conf .. note:: If you're wondering why we set notify to `192.168.27.100`:`5354` it's because MDNS runs on 5354 by default. .. code-block:: bash $ sudo vi /etc/nsd/nsd.conf Add the contents: .. code-block:: yaml pattern: name: "mdns" zonefile: "%s.zone" notify: 192.168.27.100@5354 NOKEY provide-xfr: 192.168.27.100 NOKEY allow-axfr-fallback: yes Add a zone file ^^^^^^^^^^^^^^^ Create a new *Zone* in NSD called *example.com.* **/etc/nsd/example.com.zone** .. code-block:: bash $ sudo vi /etc/nsd/example.com.zone And add the contents: :: $TTL 1800 ;minimum ttl example.com. IN SOA ns1.example.com. admin.example.net. ( 2014111301 ;serial 3600 ;refresh 600 ;retry 180000 ;expire 600 ;negative ttl ) TXT "v=spf1 +a +mx ~all" SPF "v=spf1 +a +mx ~all" NS ns1.example.com. NS ns2.example.com. NS ns3.example.com. MX 0 mail1.example.com. MX 5 mail2.example.com. MX 10 mail3.example.com. A 10.0.0.1 A 10.0.0.2 A 10.0.0.3 ns1 A 172.16.28.100 ns2 A 172.16.28.101 ns3 A 172.16.28.103 mail1 A 10.0.10.1 mail2 A 10.0.10.2 mail3 A 10.0.10.3 google CNAME google.com. Restart NSD ^^^^^^^^^^^ .. code-block:: bash $ sudo service nsd restart Check that it's working .. code-block:: bash $ sudo nsd-control status Activate the zone in NSD .. code-block:: bash $ sudo nsd-control addzone example.com mdns Creating the Zone ----------------- When you create a domain in Designate there are two possible initial actions: - Domain is created but transfer fails if it's not available yet in master, then typically the initial transfer will be done once the master sends first NOTIFY. - Domain is created and transfers straight away. In both cases the interaction between your master and Designate is handled by the MDNS instance at the Designate side. Definition of values: - *email* set to the value of the *managed_resource_email* option in the *central* section of the Designate configuration. - *transferred_at* is **null** and *version* is **1** since the zone has not transferred yet. - *serial* gets set automatically by the system initially and to the value of the master's serial post initial AXFR. .. http:post:: /zones Creates a new zone. **Example request:** .. sourcecode:: http POST /v2/zones HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json { "name": "example.com.", "type": "SECONDARY", "masters": ["192.168.27.100"], "description": "This is a slave for example.com." } **Example response:** .. sourcecode:: http HTTP/1.1 201 Created Content-Type: application/json { "id": "a86dba58-0043-4cc6-a1bb-69d5e86f3ca3", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "project_id": "4335d1f0-f793-11e2-b778-0800200c9a66", "name": "example.com.", "email": "email@example.io", "ttl": 3600, "serial": 1404757531, "status": "ACTIVE", "description": "This is a slave for example.com." "masters": ["192.168.27.100"], "type": "SECONDARY", "transferred_at": null, "version": 1, "created_at": "2014-07-07T18:25:31.275934", "updated_at": null, "links": { "self": "https://127.0.0.1:9001/v2/zones/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3" } } Get Zone -------- .. http:get:: /zones/(uuid:id) Retrieves a secondary zone with the specified zone ID. **Example request:** .. sourcecode:: http GET /v2/zones/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3 HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json **Example response:** .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "id": "a86dba58-0043-4cc6-a1bb-69d5e86f3ca3", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "project_id": "4335d1f0-f793-11e2-b778-0800200c9a66", "name": "example.com.", "email": "email@example.io", "ttl": 3600, "serial": 1404757531, "status": "ACTIVE", "description": "This is a slave for example.com." "masters": ["192.168.27.100"], "type": "SECONDARY", "transferred_at": null, "version": 1, "created_at": "2014-07-07T18:25:31.275934", "updated_at": null, "links": { "self": "https://127.0.0.1:9001/v2/zones/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3" } } :statuscode 200: Success :statuscode 401: Access Denied List Secondary Zones -------------------- .. http:get:: /zones Lists all zones. **Example Request:** .. sourcecode:: http GET /v2/zones?type=SECONDARY HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json **Example Response:** .. sourcecode:: http HTTP/1.1 200 OK Vary: Accept Content-Type: application/json { "zones": [{ "id": "a86dba58-0043-4cc6-a1bb-69d5e86f3ca3", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "project_id": "4335d1f0-f793-11e2-b778-0800200c9a66", "name": "example.com.", "email": "email@example.io", "ttl": 3600, "serial": 1404757531, "status": "ACTIVE", "description": "This is a slave for example.com.", "masters": ["192.168.27.100"], "type": "SECONDARY", "transferred_at": null, "version": 1, "created_at": "2014-07-07T18:25:31.275934", "updated_at": null, "links": { "self": "https://127.0.0.1:9001/v2/zones/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3" } }, { "id": "a86dba58-0043-4cc6-a1bb-69d5e86f3ca4", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "project_id": "4335d1f0-f793-11e2-b778-0800200c9a66", "name": "bar.io.", "email": "email@example.io", "ttl": 3600, "serial": 10, "status": "ACTIVE", "description": "This is a slave for bar.io.", "masters": ["192.168.27.100"], "type": "SECONDARY", "transferred_at": "2014-07-07T18:25:35.275934", "version": 2, "created_at": "2014-07-07T18:25:31.275934", "updated_at": null, "links": { "self": "https://127.0.0.1:9001/v2/zones/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3" } }], "links": { "self": "https://127.0.0.1:9001/v2/zones" } } :statuscode 200: Success :statuscode 401: Access Denied Update Zone ----------- .. http:patch:: /zones/(uuid:id) Changes the specified attribute(s) for an existing zone. In the example below, we update the TTL to 3600. **Request:** .. sourcecode:: http PATCH /v2/zones/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3 HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json { "masters": ["192.168.27.101"] } **Response:** .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json { "id": "a86dba58-0043-4cc6-a1bb-69d5e86f3ca3", "pool_id": "572ba08c-d929-4c70-8e42-03824bb24ca2", "project_id": "4335d1f0-f793-11e2-b778-0800200c9a66", "name": "example.com.", "email": "email@example.io", "ttl": 3600, "serial": 1404757531, "status": "ACTIVE", "description": "This is a slave for example.com.", "masters": ["192.168.27.101"], "type": "SECONDARY", "transferred_at": null, "version": 2, "created_at": "2014-07-07T18:25:31.275934", "updated_at": "2014-07-07T18:25:34.275934", "links": { "self": "https://127.0.0.1:9001/v2/zones/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3" } } :form description: UTF-8 text field. :form name: Valid zone name (Immutable). :form type: Enum PRIMARY/SECONDARY, default PRIMARY (Immutable). :form email: email address, required for type PRIMARY, NULL for SECONDARY. :form ttl: time-to-live numeric value in seconds, NULL for SECONDARY :form masters: Array of master nameservers. (NULL for type PRIMARY, required for SECONDARY otherwise zone will not be transferred before set.) :statuscode 200: Success :statuscode 202: Accepted :statuscode 401: Access Denied Delete Zone ----------- .. http:delete:: zones/(uuid:id) Deletes a zone with the specified zone ID. **Example Request:** .. sourcecode:: http DELETE /v2/zones/a86dba58-0043-4cc6-a1bb-69d5e86f3ca3 HTTP/1.1 Host: 127.0.0.1:9001 Accept: application/json Content-Type: application/json **Example Response:** .. sourcecode:: http HTTP/1.1 204 No Content :statuscode 204: No content designate-2.0.0/doc/source/howtos/manage-domains.rst0000664000567000056710000001732512701406241023624 0ustar jenkinsjenkins00000000000000.. Copyright 2015 Hewlett-Packard Development Company, L.P. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. How To Create and Manage Domains ================================ Install Client -------------- To install Designate client, see `OpenStack Command-Line Interface Reference `_. Create and View Domains ----------------------- To create a new domain, a minimum of two pieces of information are required: +-------+---------------------------------------------------------------------------+ | Name | Description | +=======+===========================================================================+ | Name | The name of the domain you are creating. The name must end with a period. | +-------+---------------------------------------------------------------------------+ | Email | An email address of the person responsible for the domain. | +-------+---------------------------------------------------------------------------+ Create the domain ^^^^^^^^^^^^^^^^^ .. code-block:: bash $ designate domain-create --name designate-example.com. --email designate@example.org +-------------+--------------------------------------+ | Field | Value | +-------------+--------------------------------------+ | description | None | | created_at | 2015-02-13T16:23:26.533547 | | updated_at | None | | email | designate@example.org | | ttl | 3600 | | serial | 1423844606 | | id | ae59d62b-d655-49a0-ab4b-ea536d845a32 | | name | designate-example.com. | +-------------+--------------------------------------+ List the Servers Hosting a Domain ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. note:: This list of servers are the "nameservers" you must provide to your domain registrar in order to delegate the domain to Designate. Without performing this step, the domain and records created will not resolve. .. code-block:: bash $ designate domain-servers-list ae59d62b-d655-49a0-ab4b-ea536d845a32 +------------------+ | name | +------------------+ | ns1.example.org. | | ns2.example.org. | | ns3.example.org. | +------------------+ List and Show Domains ^^^^^^^^^^^^^^^^^^^^^ .. code-block:: bash $ designate domain-list +--------------------------------------+-------------------------------------------+------------+ | id | name | serial | +--------------------------------------+-------------------------------------------+------------+ | ae59d62b-d655-49a0-ab4b-ea536d845a32 | designate-example.com. | 1423844606 | +--------------------------------------+-------------------------------------------+------------+ $ designate domain-get ae59d62b-d655-49a0-ab4b-ea536d845a32 +-------------+--------------------------------------+ | Field | Value | +-------------+--------------------------------------+ | description | None | | created_at | 2015-02-13T16:23:26.000000 | | updated_at | None | | email | designate@example.org | | ttl | 3600 | | serial | 1423844606 | | id | ae59d62b-d655-49a0-ab4b-ea536d845a32 | | name | designate-example.com. | +-------------+--------------------------------------+ Create and View Records ----------------------- To create a new record in the domain, a minimum of four pieces of information are required: +-----------+-----------------------------------------------------------+ | Name | Description | +===========+===========================================================+ | Domain ID | The Domain ID which the record will belong to. | +-----------+-----------------------------------------------------------+ | Name | The fully qualified record name to create. | +-----------+-----------------------------------------------------------+ | Type | The record type to be created (e.g: A, AAAA, MX etc). | +-----------+-----------------------------------------------------------+ | Data | The type specific value to be associated with the record. | +-----------+-----------------------------------------------------------+ Create the Record ^^^^^^^^^^^^^^^^^ .. code-block:: bash $ designate record-create ae59d62b-d655-49a0-ab4b-ea536d845a32 --name www.designate-example.com. --type A --data 192.0.2.1 +-------------+--------------------------------------+ | Field | Value | +-------------+--------------------------------------+ | description | None | | type | A | | created_at | 2015-02-13T16:43:10.952601 | | updated_at | None | | domain_id | ae59d62b-d655-49a0-ab4b-ea536d845a32 | | priority | None | | ttl | None | | data | 192.0.2.1 | | id | 10b31f72-2358-466c-90d2-79aa015fbea4 | | name | www.designate-example.com. | +-------------+--------------------------------------+ List and Show Records ^^^^^^^^^^^^^^^^^^^^^ .. code-block:: bash $ designate record-list ae59d62b-d655-49a0-ab4b-ea536d845a32 +--------------------------------------+------+----------------------------+-----------+ | id | type | name | data | +--------------------------------------+------+----------------------------+-----------+ | 10b31f72-2358-466c-90d2-79aa015fbea4 | A | www.designate-example.com. | 192.0.2.1 | +--------------------------------------+------+----------------------------+-----------+ $ designate record-get ae59d62b-d655-49a0-ab4b-ea536d845a32 10b31f72-2358-466c-90d2-79aa015fbea4 +-------------+--------------------------------------+ | Field | Value | +-------------+--------------------------------------+ | description | None | | type | A | | created_at | 2015-02-13T16:43:10.000000 | | updated_at | None | | domain_id | ae59d62b-d655-49a0-ab4b-ea536d845a32 | | priority | None | | ttl | None | | data | 192.0.2.1 | | id | 10b31f72-2358-466c-90d2-79aa015fbea4 | | name | www.designate-example.com. | +-------------+--------------------------------------+ designate-2.0.0/doc/source/related.rst0000664000567000056710000000304712701406241021035 0ustar jenkinsjenkins00000000000000.. Copyright 2013 Hewlett-Packard Development Company, L.P. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. .. _related: .. index:: double: related; brief ============= Related Links ============= * `Bug Tracker`_ * `Blueprints`_ * `Git`_ ================ Related Projects ================ * `Chef Cookbook`_ * `Debian Packaging`_ * `Launchpad PPA`_ * `Sample Plugin`_ * `Symantec Nova Plugin`_ * `Symantec Neutron Plugin`_ .. _Bug Tracker: https://bugs.launchpad.net/designate .. _Blueprints: https://blueprints.launchpad.net/designate .. _Git: https://git.openstack.org/cgit/openstack/designate .. _Chef Cookbook: https://github.com/moniker-dns/designate-cookbook .. _Debian Packaging: https://github.com/moniker-dns/debian-designate .. _Launchpad PPA: https://launchpad.net/~designate-ppa/+archive/havana .. _Sample Plugin: https://github.com/kiall/designate-ext-samplehandler .. _Symantec Nova Plugin: https://github.com/Symantec/nova-designate-dns-plugin .. _Symantec Neutron Plugin: https://github.com/Symantec/neutron-designate-fip-plugin designate-2.0.0/doc/source/storage.rst0000664000567000056710000000027012701406241021054 0ustar jenkinsjenkins00000000000000.. _storage: ******* Storage ******* .. _storage-base: Storage Base ============= .. automodule:: designate.storage.base :members: :undoc-members: :show-inheritance: designate-2.0.0/doc/source/integrations.rst0000664000567000056710000000410012701406241022112 0ustar jenkinsjenkins00000000000000============ Integrations ============ This page overviews integrations with other services like Neutron and others to make use of Designate more convenient. Reverse - FloatingIP ==================== The FloatingIP PTR feature of Designate relies on information of the FloatingIP which is in a different service than Designate itself. It can be in any service as long as their is a "plugin" for it that can be loaded via the configuration setting called "network_api". * Controller, views and schemas in the V2 API * RPC Client towards Central used by the API and Sink * Logic in Central to make it convenient for setting, unsetting, listing and getting FloatingIP PTR records compared to the Records themselves which would be more work. (This is outlined in code docstrings for the specific methods.) * Sink handlers for the various backend to help us be more consistent. Record invalidation ^^^^^^^^^^^^^^^^^^^ Happens mainly happens via comparing a Tenant's FloatingIPs towards the list we have of Records which are of a certain plugin type and with the use of a Sink handler that listens for incoming events from the various services. Configuring Neutron ------------------- Configuring the FloatingIP feature is really simple: .. code-block:: ini [network_api:neutron] endpoints = RegionOne|http://localhost:9696 endpoint_type = publicURL timeout = 30 # This is optional - if these credentials are not provided designate will # use the users context and auth token to query neutron #admin_username = designate #admin_password = designate #admin_tenant_name = designate auth_url = http://localhost:35357/v2.0 insecure = False auth_strategy = keystone ca_certificates_file = /etc/path/to/ca.pem Note that using admin_user, admin_password and admin_tenant_name is optional, if not present we'll piggyback on the context.auth_token passed in by the API. .. note:: If "endpoints" is not configured and there's no service catalog is present in the context passed by the API to Central the request will fail in a NoEndpoint exception. designate-2.0.0/doc/source/conf.py0000664000567000056710000001763512701406241020172 0ustar jenkinsjenkins00000000000000# -*- coding: utf-8 -*- # # designate documentation build configuration file, created by # sphinx-quickstart on Wed Oct 31 18:58:17 2012. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath('../')) sys.path.insert(0, os.path.abspath('./')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinxcontrib.httpdomain', 'oslosphinx', 'ext.support_matrix'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'designate' copyright = u'2012, Managed I.T.' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. from designate.version import version_info as designate_version version = designate_version.canonical_version_string() # The full version, including alpha/beta/rc tags. release = designate_version.version_string_with_vcs() # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. modindex_common_prefix = ["designate."] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'designatedoc' # -- Options for LaTeX output -------------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'designate.tex', u'Designate Documentation', u'Managed I.T.', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ # ('index', 'designate', u'Designate Documentation', # [u'Managed I.T.'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'designate', u'Designate Documentation', u'Managed I.T.', 'designate', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' designate-2.0.0/doc/source/examples/0000775000567000056710000000000012701406373020503 5ustar jenkinsjenkins00000000000000designate-2.0.0/doc/source/examples/basic-config-sample-juno.conf0000664000567000056710000000475412701406241026132 0ustar jenkinsjenkins00000000000000[DEFAULT] ######################## ## General Configuration ######################## # Show more verbose log output (sets INFO log level output) verbose = True # Show debugging output in logs (sets DEBUG log level output) debug = True # Top-level directory for maintaining designate's state state_path = /var/lib/designate # Log directory #Make sure and create this directory, or set it to some other directory that exists logdir = /var/log/designate # Driver used for issuing notifications notification_driver = messaging # Use "sudo designate-rootwrap /etc/designate/rootwrap.conf" to use the real # root filter facility. # Change to "sudo" to skip the filtering and just run the command directly # root_helper = sudo ######################## ## Service Configuration ######################## #----------------------- # Central Service #----------------------- [service:central] # Driver used for backend communication (e.g. fake, rpc, bind9, powerdns) backend_driver = powerdns # Maximum domain name length max_domain_name_len = 255 # Maximum record name length max_record_name_len = 255 #----------------------- # API Service #----------------------- [service:api] # Address to bind the API server api_host = 0.0.0.0 # Port the bind the API server to api_port = 9001 # Authentication strategy to use - can be either "noauth" or "keystone" auth_strategy = keystone # Enabled API Version 1 extensions enabled_extensions_v1 = diagnostics, quotas, reports, sync #----------------------- # Keystone Middleware #----------------------- [keystone_authtoken] auth_host = 127.0.0.1 auth_port = 35357 auth_protocol = http admin_tenant_name = service admin_user = designate admin_password = designate ######################## ## Storage Configuration ######################## #----------------------- # SQLAlchemy Storage #----------------------- [storage:sqlalchemy] # Database connection string - to configure options for a given implementation # like sqlalchemy or other see below connection = mysql://designate:designate@localhost/designate #connection_debug = 100 #connection_trace = True #sqlite_synchronous = True idle_timeout = 3600 max_retries = 10 retry_interval = 10 ######################## ## Backend Configuration ######################## #----------------------- # PowerDNS Backend #----------------------- [backend:powerdns] connection = mysql://powerdns:powerdns@localhost/powerdns #connection_debug = 100 #connection_trace = True #sqlite_synchronous = True idle_timeout = 3600 max_retries = 10 retry_interval = 10 designate-2.0.0/doc/source/examples/basic-config-sample-kilo.conf0000664000567000056710000000661012701406241026106 0ustar jenkinsjenkins00000000000000[DEFAULT] ######################## ## General Configuration ######################## # Show more verbose log output (sets INFO log level output) verbose = True # Show debugging output in logs (sets DEBUG log level output) debug = True # Top-level directory for maintaining designate's state. state_path = $pybasedir/state # Log directory logdir = $pybasedir/log # Driver used for issuing notifications notification_driver = messaging # Use "sudo designate-rootwrap /etc/designate/rootwrap.conf" to use the real # root filter facility. # Change to "sudo" to skip the filtering and just run the command directly # root_helper = sudo # RabbitMQ Config rabbit_userid = designate rabbit_password = designate #rabbit_virtual_host = / #rabbit_use_ssl = False #rabbit_hosts = 127.0.0.1:5672 ######################## ## Service Configuration ######################## #----------------------- # Central Service #----------------------- [service:central] # Maximum domain name length #max_domain_name_len = 255 # Maximum record name length #max_record_name_len = 255 #----------------------- # API Service #----------------------- [service:api] # Address to bind the API server api_host = 0.0.0.0 # Port to bind the API server api_port = 9001 # Authentication strategy to use - can be either "noauth" or "keystone" auth_strategy = noauth # Enable API Version 1 enable_api_v1 = True # Enabled API Version 1 extensions enabled_extensions_v1 = diagnostics, quotas, reports, sync, touch # Enable API Version 2 enable_api_v2 = True # Enabled API Version 2 extensions enabled_extensions_v2 = quotas, reports #----------------------- # mDNS Service #----------------------- [service:mdns] #workers = None #host = 0.0.0.0 #port = 5354 #tcp_backlog = 100 #----------------------- # Pool Manager Service #----------------------- [service:pool_manager] pool_id = 794ccc2c-d751-44fe-b57f-8894c9f5c842 #workers = None #threshold_percentage = 100 #poll_timeout = 30 #poll_retry_interval = 2 #poll_max_retries = 3 #poll_delay = 1 #periodic_recovery_interval = 120 #periodic_sync_interval = 300 #periodic_sync_seconds = None #cache_driver = sqlalchemy ##################### ## Pool Configuration ##################### [pool:794ccc2c-d751-44fe-b57f-8894c9f5c842] nameservers = f02a0c72-c701-4ec2-85d7-197b30992ce8 targets = f02a0c72-c701-4ec2-85d7-197b30992ce9 [pool_nameserver:f02a0c72-c701-4ec2-85d7-197b30992ce8] host = 127.0.0.1 port = 53 [pool_target:f02a0c72-c701-4ec2-85d7-197b30992ce9] masters = 127.0.0.1:5354 type = bind9 options = port: 53, host: 127.0.0.1 ################################### ## Pool Manager Cache Configuration ################################### #----------------------- # SQLAlchemy Pool Manager Cache #----------------------- [pool_manager_cache:sqlalchemy] connection = mysql://root:password@127.0.0.1/designate_pool_manager #connection_debug = 100 #connection_trace = False #sqlite_synchronous = True #idle_timeout = 3600 #max_retries = 10 #retry_interval = 10 ######################## ## Storage Configuration ######################## #----------------------- # SQLAlchemy Storage #----------------------- [storage:sqlalchemy] # Database connection string - to configure options for a given implementation # like sqlalchemy or other see below connection = mysql://root:password@127.0.0.1/designate #connection_debug = 100 #connection_trace = True #sqlite_synchronous = True #idle_timeout = 3600 #max_retries = 10 #retry_interval = 10 designate-2.0.0/doc/source/examples/basic-config-sample.conf0000664000567000056710000000703412701406241025153 0ustar jenkinsjenkins00000000000000[DEFAULT] ######################## ## General Configuration ######################## # Show more verbose log output (sets INFO log level output) verbose = True # Show debugging output in logs (sets DEBUG log level output) debug = True # Top-level directory for maintaining designate's state. state_path = $pybasedir/state # Log directory logdir = $pybasedir/log # Driver used for issuing notifications notification_driver = messaging # Use "sudo designate-rootwrap /etc/designate/rootwrap.conf" to use the real # root filter facility. # Change to "sudo" to skip the filtering and just run the command directly # root_helper = sudo # Supported record types #supported_record_type = A, AAAA, CNAME, MX, SRV, TXT, SPF, NS, PTR, SSHFP, SOA # RabbitMQ Config rabbit_userid = designate rabbit_password = designate #rabbit_virtual_host = / #rabbit_use_ssl = False #rabbit_hosts = 127.0.0.1:5672 ######################## ## Service Configuration ######################## #----------------------- # Central Service #----------------------- [service:central] # Maximum domain name length #max_domain_name_len = 255 # Maximum record name length #max_record_name_len = 255 #----------------------- # API Service #----------------------- [service:api] # Address to bind the API server api_host = 0.0.0.0 # Port to bind the API server api_port = 9001 # Authentication strategy to use - can be either "noauth" or "keystone" auth_strategy = noauth # Enable API Version 1 enable_api_v1 = True # Enabled API Version 1 extensions enabled_extensions_v1 = diagnostics, quotas, reports, sync, touch # Enable API Version 2 enable_api_v2 = True # Enabled API Version 2 extensions enabled_extensions_v2 = quotas, reports #----------------------- # mDNS Service #----------------------- [service:mdns] #workers = None #host = 0.0.0.0 #port = 5354 #tcp_backlog = 100 #----------------------- # Pool Manager Service #----------------------- [service:pool_manager] pool_id = 794ccc2c-d751-44fe-b57f-8894c9f5c842 #workers = None #threshold_percentage = 100 #poll_timeout = 30 #poll_retry_interval = 2 #poll_max_retries = 3 #poll_delay = 1 #periodic_recovery_interval = 120 #periodic_sync_interval = 300 #periodic_sync_seconds = None #cache_driver = sqlalchemy ##################### ## Pool Configuration ##################### [pool:794ccc2c-d751-44fe-b57f-8894c9f5c842] nameservers = f02a0c72-c701-4ec2-85d7-197b30992ce8 targets = f02a0c72-c701-4ec2-85d7-197b30992ce9 [pool_nameserver:f02a0c72-c701-4ec2-85d7-197b30992ce8] host = 127.0.0.1 port = 53 [pool_target:f02a0c72-c701-4ec2-85d7-197b30992ce9] masters = 127.0.0.1:5354 type = bind9 options = port: 53, host: 127.0.0.1 ################################### ## Pool Manager Cache Configuration ################################### #----------------------- # SQLAlchemy Pool Manager Cache #----------------------- [pool_manager_cache:sqlalchemy] connection = mysql+pymysql://root:password@127.0.0.1/designate_pool_manager?charset=utf8 #connection_debug = 100 #connection_trace = False #sqlite_synchronous = True #idle_timeout = 3600 #max_retries = 10 #retry_interval = 10 ######################## ## Storage Configuration ######################## #----------------------- # SQLAlchemy Storage #----------------------- [storage:sqlalchemy] # Database connection string - to configure options for a given implementation # like sqlalchemy or other see below connection = mysql+pymysql://root:password@127.0.0.1/designate?charset=utf8 #connection_debug = 100 #connection_trace = True #sqlite_synchronous = True #idle_timeout = 3600 #max_retries = 10 #retry_interval = 10 designate-2.0.0/doc/source/objects.rst0000664000567000056710000000571712701406241021054 0ustar jenkinsjenkins00000000000000.. _objects: ******* Objects ******* Objects Base ============ .. automodule:: designate.objects.base :members: :undoc-members: :show-inheritance: Objects Backlist ================ .. automodule:: designate.objects.blacklist :members: :undoc-members: :show-inheritance: Objects Zone ============ .. automodule:: designate.objects.zone :members: :undoc-members: :show-inheritance: Objects Pool ============ .. automodule:: designate.objects.pool :members: :undoc-members: :show-inheritance: Objects Quota ============= .. automodule:: designate.objects.quota :members: :undoc-members: :show-inheritance: Objects Record ============== .. automodule:: designate.objects.record :members: :undoc-members: :show-inheritance: Objects Recordset ================= .. automodule:: designate.objects.recordset :members: :undoc-members: :show-inheritance: Objects Server ============== .. automodule:: designate.objects.server :members: :undoc-members: :show-inheritance: Objects Tenant ============== .. automodule:: designate.objects.tenant :members: :undoc-members: :show-inheritance: Objects TLD =========== .. automodule:: designate.objects.tld :members: :undoc-members: :show-inheritance: Objects TSigKey =============== .. automodule:: designate.objects.tsigkey :members: :undoc-members: :show-inheritance: Objects A Record ================ .. automodule:: designate.objects.rrdata_a :members: :undoc-members: :show-inheritance: Objects AAAA Record =================== .. automodule:: designate.objects.rrdata_aaaa :members: :undoc-members: :show-inheritance: Objects CNAME Record ==================== .. automodule:: designate.objects.rrdata_cname :members: :undoc-members: :show-inheritance: Objects MX Record ================= .. automodule:: designate.objects.rrdata_mx :members: :undoc-members: :show-inheritance: Objects NS Record ================= .. automodule:: designate.objects.rrdata_ns :members: :undoc-members: :show-inheritance: Objects PTR Record ================== .. automodule:: designate.objects.rrdata_ptr :members: :undoc-members: :show-inheritance: Objects SOA Record ================== .. automodule:: designate.objects.rrdata_soa :members: :undoc-members: :show-inheritance: Objects SPF Record ================== .. automodule:: designate.objects.rrdata_spf :members: :undoc-members: :show-inheritance: Objects SRV Record ================== .. automodule:: designate.objects.rrdata_srv :members: :undoc-members: :show-inheritance: Objects TXT Record ================== .. automodule:: designate.objects.rrdata_txt :members: :undoc-members: :show-inheritance: Objects SSHFP Record ==================== .. automodule:: designate.objects.rrdata_sshfp :members: :undoc-members: :show-inheritance: designate-2.0.0/doc/source/production-architecture.rst0000664000567000056710000000733612701406241024270 0ustar jenkinsjenkins00000000000000.. _production-architecture: ============================= Production Architecture ============================= Outline ------- This document outlines what a production environment hosting Designate could look like, it follows an in-cloud model, where Designate would be hosted on instances in an OpenStack cloud. It's supposed to complement the :doc:`architecture` document, please start there if you are unfamiliar with the designate components. Designate Dependencies ---------------------- Designate has been designed to integrate with Keystone, or a Keystone-like service, for authentication & authorization, in a production environment it should rely on your Keystone service, and be registered in your service catalog. Expectations ------------ This architecture expects your environment to have an external loadbalancer that is the first touch point for customer traffic, this will distribute requests across the available API nodes, which should span your AZs & regions where possible. Roles ----- A Designate deploy breaks down into several key roles: - `Designate API`_ - `Designate Sink`_ - `Designate Central`_ - `Designate MiniDNS`_ - `Designate Pool Manager`_ - `Message Queue`_ - `Database`_ (MySQL or derivative) - `DNS Backend`_ Designate API ~~~~~~~~~~~~~~~~~~~ Typically, API nodes would be made available in multiple AZs, providing redundancy should an individual AZ have issues. In a Multi-AZ deployment, the API nodes should be configured to talk to all members of the MQ Cluster - so that in the event of MQ node failing, requests continue to flow to the MQ. Designate Sink ~~~~~~~~~~~~~~~~~~~~~~~ In a Multi-AZ deployment, the sink node should be configured to talk to all members of the MQ Cluster - so that in the event of MQ node failing, requests continue to flow to the MQ. Designate Central ~~~~~~~~~~~~~~~~~~~~~~~ In a Multi-AZ deployment, the Central nodes should be configured to talk to all members of the MQ Cluster - so that in the event of MQ node failing, requests continue to be processed. Designate MiniDNS ~~~~~~~~~~~~~~~~~~~~~~~ In a Multi-AZ deployment, the MiniDNS nodes should be configured to talk to all members of the MQ Cluster - so that in the event of MQ node failing, requests continue to be processed. It should also be configured to talk to multiple DB servers, to allow for reliable access to the data store Designate Pool Manager ~~~~~~~~~~~~~~~~~~~~~~~ In a Multi-AZ deployment, the Pool Manager nodes should be configured to talk to all members of the MQ Cluster - so that in the event of MQ node failing, requests continue to be processed. Message Queue ~~~~~~~~~~~~~ An AMQP implementation is required for all communication between api & central nodes, in practice this means an RabbitMQ installation, preferably a cluster that spans across the AZs in a given region. Database ~~~~~~~~~~~~~~~~ Designate needs a SQLAlchemy supported :ref:`database` engine for the persistent storage of data, the recommended driver is MySQL. In a Multi-AZ environment, a MySQL Galera Cluster, built using Percona's MySQL packages has performed well. DNS Backend ~~~~~~~~~~~ Designate supports multiple backend implementations, PowerDNS, BIND and MySQL BIND, you are also free to implement your own backend to fit your needs, as well as extensions to provide extra functionality to complement existing backends. There are various ways to provide a highly available authoritative DNS service, here are some suggestions: * Multiple PowerDNS instances using the same database being maintained by :ref:`designate-central`, optionally using MySQL Replication to propagate the data to multiple locations. * DNS AXFR (Zone Transfer) multiple slave DNS server get notified of zone updates from a DNS server being managed by :ref:`designate-central`. designate-2.0.0/doc/source/rest.rst0000664000567000056710000000460512701406241020373 0ustar jenkinsjenkins00000000000000.. _rest: ======================== REST API Documentation ======================== Intro ===== In the REST API examples, HTTP requests are defined as raw HTTP. For example: .. code-block:: http POST /v2/pools HTTP/1.1 # The HTTP Method, Path and HTTP Version Accept: application/json # Headers Content-Type: application/json { # The rest is the body of request "name": "Example Pool", "ns_records": [ { "hostname": "ns1.example.org.", "priority": 1 } ] } With this info we can make this request using the cURL_ tool. We'll assume we are running Designate on `localhost`. .. code-block:: bash curl -X POST -i \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"name": "ns1.example.org."}' \ http://localhost:9001/v1/servers The `-i` flag is used to dump the response headers as well as the response body. The cURL tool is extremely robust. Please take a look at the `cURL tutorial`_ for more info. .. _cURL: http://curl.haxx.se/ .. _cURL tutorial: http://curl.haxx.se/docs/manual.html HTTP Headers ============ These headers work for all APIs * X-Designate-Edit-Managed-Records - Allows admins (or users with the right role) to modify managed records (records created by designate-sink / reverse floating ip API) * X-Auth-All-Projects - Allows admins (or users with the right role) to view and edit zones / recordsets for all tenants * X-Auth-Sudo-Tenant-ID / X-Auth-Sudo-Project-ID - Allows admins (or users with the right role) to impersonate another tenant specified by this header API Versions ============ The API has 2 versions - V1 and V2. .. note:: V1 has been deprecated since the Kilo release. V1 API ------ .. toctree:: :maxdepth: 2 :glob: rest/v1/servers rest/v1/domains rest/v1/records rest/v1/diagnostics rest/v1/quotas rest/v1/reports rest/v1/sync V2 API ------ .. toctree:: :maxdepth: 2 :glob: rest/v2/collections rest/v2/zones rest/v2/recordsets rest/v2/tlds rest/v2/blacklists rest/v2/pools rest/v2/limits rest/v2/reverse rest/v2/tsigkeys Admin API --------- .. toctree:: :maxdepth: 2 :glob: rest/admin/quotas designate-2.0.0/doc/source/gmr.rst0000664000567000056710000003704512701406241020207 0ustar jenkinsjenkins00000000000000.. _gmr: ========================= Guru Meditation Reports ========================= A Guru Meditation Report (GMR) is generated by the Designate services when service processes receiving SIGUSR2 signal. The report is a general-purpose debug report for developers and system admins which contains the current state of a running Designate service process. Structure of a GMR ================== Package Shows information about the package to which this process belongs, including version information Threads Shows stack traces and thread ids for each of the threads within this process Green Threads Shows stack traces for each of the green threads within this process (green threads don't have thread ids) Processes Shows information about this process, including pid, ppid, uid and process state Configuration Lists all the configuration options currently accessible via the CONF object for the current process Generate a GMR ============== A GMR can be generated by sending the USR2 signal to any Designate processes. For example, suppose ``designate-central`` has pid ``15097``, ``kill -USR2 15097`` will trigger a GMR. If option ``logdir`` has been set in ``designate.conf``, the GMR will be saved in the folder which ``logdir`` specified. Otherwise, the GMR will be printed to the stderr. Reference ========= For more information about GMR, see `GMR wiki`_. .. _GMR wiki: https://wiki.openstack.org/wiki/GuruMeditationReport GMR Example =========== :: ======================================================================== ==== Guru Meditation ==== ======================================================================== |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ======================================================================== ==== Package ==== ======================================================================== product = OpenStack Designate vendor = OpenStack Foundation version = 2015.1 ======================================================================== ==== Threads ==== ======================================================================== ------ Thread #140098874533632 ------ /usr/local/lib/python2.7/dist-packages/eventlet/hubs/hub.py:346 in run `self.wait(sleep_time)` /usr/local/lib/python2.7/dist-packages/eventlet/hubs/poll.py:85 in wait `presult = self.do_poll(seconds)` /usr/local/lib/python2.7/dist-packages/eventlet/hubs/epolls.py:62 in do_poll `return self.poll.poll(seconds)` ======================================================================== ==== Green Threads ==== ======================================================================== ------ Green Thread ------ /usr/local/lib/python2.7/dist-packages/eventlet/greenthread.py:214 in main `result = function(*args, **kwargs)` /opt/stack/designate/designate/openstack/common/service.py:492 in run_service `done.wait()` /usr/local/lib/python2.7/dist-packages/eventlet/event.py:121 in wait `return hubs.get_hub().switch()` /usr/local/lib/python2.7/dist-packages/eventlet/hubs/hub.py:294 in switch `return self.greenlet.switch()` ------ Green Thread ------ /usr/local/lib/python2.7/dist-packages/eventlet/greenthread.py:214 in main `result = function(*args, **kwargs)` /usr/local/lib/python2.7/dist-packages/oslo_utils/excutils.py:95 in inner_func `return infunc(*args, **kwargs)` /usr/local/lib/python2.7/dist-packages/oslo_messaging/_executors/impl_eventlet.py:96 in _executor_thread `incoming = self.listener.poll()` /usr/local/lib/python2.7/dist-packages/oslo_messaging/_drivers/amqpdriver.py:121 in poll `self.conn.consume(limit=1, timeout=timeout)` /usr/local/lib/python2.7/dist-packages/oslo_messaging/_drivers/impl_rabbit.py:867 in consume `six.next(it)` /usr/local/lib/python2.7/dist-packages/oslo_messaging/_drivers/impl_rabbit.py:782 in iterconsume `yield self.ensure(_error_callback, _consume)` /usr/local/lib/python2.7/dist-packages/oslo_messaging/_drivers/impl_rabbit.py:688 in ensure `ret, channel = autoretry_method()` /usr/local/lib/python2.7/dist-packages/kombu/connection.py:436 in _ensured `return fun(*args, **kwargs)` /usr/local/lib/python2.7/dist-packages/kombu/connection.py:508 in __call__ `return fun(*args, channel=channels[0], **kwargs), channels[0]` /usr/local/lib/python2.7/dist-packages/oslo_messaging/_drivers/impl_rabbit.py:675 in execute_method `method()` /usr/local/lib/python2.7/dist-packages/oslo_messaging/_drivers/impl_rabbit.py:774 in _consume `return self.connection.drain_events(timeout=poll_timeout)` /usr/local/lib/python2.7/dist-packages/kombu/connection.py:275 in drain_events `return self.transport.drain_events(self.connection, **kwargs)` /usr/local/lib/python2.7/dist-packages/kombu/transport/pyamqp.py:91 in drain_events `return connection.drain_events(**kwargs)` /usr/local/lib/python2.7/dist-packages/amqp/connection.py:302 in drain_events `chanmap, None, timeout=timeout,` /usr/local/lib/python2.7/dist-packages/amqp/connection.py:365 in _wait_multiple `channel, method_sig, args, content = read_timeout(timeout)` /usr/local/lib/python2.7/dist-packages/amqp/connection.py:336 in read_timeout `return self.method_reader.read_method()` /usr/local/lib/python2.7/dist-packages/amqp/method_framing.py:186 in read_method `self._next_method()` /usr/local/lib/python2.7/dist-packages/amqp/method_framing.py:107 in _next_method `frame_type, channel, payload = read_frame()` /usr/local/lib/python2.7/dist-packages/amqp/transport.py:154 in read_frame `frame_header = read(7, True)` /usr/local/lib/python2.7/dist-packages/amqp/transport.py:277 in _read `s = recv(n - len(rbuf))` /usr/local/lib/python2.7/dist-packages/eventlet/greenio/base.py:326 in recv `timeout_exc=socket.timeout("timed out"))` /usr/local/lib/python2.7/dist-packages/eventlet/greenio/base.py:201 in _trampoline `mark_as_closed=self._mark_as_closed)` /usr/local/lib/python2.7/dist-packages/eventlet/hubs/__init__.py:162 in trampoline `return hub.switch()` /usr/local/lib/python2.7/dist-packages/eventlet/hubs/hub.py:294 in switch `return self.greenlet.switch()` ------ Green Thread ------ /usr/local/bin/designate-central:10 in `sys.exit(main())` /opt/stack/designate/designate/cmd/central.py:37 in main `service.wait()` /opt/stack/designate/designate/service.py:356 in wait `_launcher.wait()` /opt/stack/designate/designate/openstack/common/service.py:187 in wait `status, signo = self._wait_for_exit_or_signal(ready_callback)` /opt/stack/designate/designate/openstack/common/service.py:170 in _wait_for_exit_or_signal `super(ServiceLauncher, self).wait()` /opt/stack/designate/designate/openstack/common/service.py:133 in wait `self.services.wait()` /opt/stack/designate/designate/openstack/common/service.py:473 in wait `self.tg.wait()` /opt/stack/designate/designate/openstack/common/threadgroup.py:145 in wait `x.wait()` /opt/stack/designate/designate/openstack/common/threadgroup.py:47 in wait `return self.thread.wait()` /usr/local/lib/python2.7/dist-packages/eventlet/greenthread.py:175 in wait `return self._exit_event.wait()` /usr/local/lib/python2.7/dist-packages/eventlet/event.py:121 in wait `return hubs.get_hub().switch()` /usr/local/lib/python2.7/dist-packages/eventlet/hubs/hub.py:294 in switch `return self.greenlet.switch()` ------ Green Thread ------ No Traceback! ======================================================================== ==== Processes ==== ======================================================================== Process 15097 (under 7312) [ run by: stanzgy (1000), state: running ] ======================================================================== ==== Configuration ==== ======================================================================== backend:agent:bind9: query-destination = 127.0.0.1 rndc-config-file = None rndc-host = 127.0.0.1 rndc-key-file = None rndc-port = 953 zone-file-path = /opt/stack/data/designate/zones backend:bind9: masters = 127.0.0.1:5354 rndc-config-file = None rndc-host = 127.0.0.1 rndc-key-file = None rndc-port = 953 server_ids = backend:fake: masters = 127.0.0.1:5354 server_ids = backend:powerdns: backend = sqlalchemy connection = *** connection_debug = 0 connection_trace = False db_inc_retry_interval = True db_max_retries = 20 db_max_retry_interval = 10 db_retry_interval = 1 idle_timeout = 3600 masters = 10.180.64.117:5354 max_overflow = None max_pool_size = None max_retries = 10 min_pool_size = 1 mysql_sql_mode = TRADITIONAL pool_timeout = None retry_interval = 10 server_ids = f26e0b32-736f-4f0a-831b-039a415c481e slave_connection = *** sqlite_db = oslo.sqlite sqlite_synchronous = True use_db_reconnect = False backend:powerdns:f26e0b32-736f-4f0a-831b-039a415c481e: backend = None connection = *** connection_debug = None connection_trace = None db_inc_retry_interval = None db_max_retries = None db_max_retry_interval = None db_retry_interval = None host = 10.180.64.117 idle_timeout = None masters = None max_overflow = None max_pool_size = None max_retries = None min_pool_size = None mysql_sql_mode = None pool_timeout = None port = 53 retry_interval = None slave_connection = *** sqlite_db = None sqlite_synchronous = None tsig-key = None use_db_reconnect = None default: allowed_remote_exmods = backdoor_port = None backlog = 4096 central-topic = central config-dir = None config-file = /etc/designate/designate.conf control_exchange = designate debug = True default-soa-expire = 86400 default-soa-minimum = 3600 default-soa-refresh-min = 3500 default-soa-refresh-max = 3600 default-soa-retry = 600 default-ttl = 3600 default_log_levels = amqp=WARN amqplib=WARN boto=WARN eventlet.wsgi.server=WARN keystone=INFO keystonemiddleware.auth_token=INFO oslo.messaging=WARN sqlalchemy=WARN stevedore=WARN suds=INFO fatal_deprecations = False host = cns-dev2 instance_format = [instance: %(uuid)s] instance_uuid_format = [instance: %(uuid)s] log-config-append = None log-date-format = %Y-%m-%d %H:%M:%S log-dir = /opt/stack/logs/designate log-file = None log-format = None logging_context_format_string = %(asctime)s.%(msecs)03d %(color)s%(levelname)s %(name)s [%(request_id)s %(user)s %(tenant)s%(color)s] %(instance)s%(color)s%(message)s logging_debug_format_suffix = from (pid=%(process)d) %(funcName)s %(pathname)s:%(lineno)d logging_default_format_string = %(asctime)s.%(msecs)03d %(color)s%(levelname)s %(name)s [-%(color)s] %(instance)s%(color)s%(message)s logging_exception_prefix = %(color)s%(asctime)s.%(msecs)03d TRACE %(name)s %(instance)s mdns-topic = mdns network_api = neutron notification_driver = notification_topics = notifications policy_default_rule = default policy_dirs = policy.d policy_file = /etc/designate/policy.json pool-manager-topic = pool_manager publish_errors = False pybasedir = /opt/stack/designate quota-domain-records = 500 quota-domain-recordsets = 500 quota-domains = 10 quota-driver = storage quota-recordset-records = 20 root-helper = sudo designate-rootwrap /etc/designate/rootwrap.conf rpc_backend = rabbit rpc_thread_pool_size = 64 state-path = /opt/stack/data/designate syslog-log-facility = LOG_USER tcp_keepidle = 600 transport_url = None use-syslog = False use-syslog-rfc-format = False use_stderr = True verbose = True network_api:neutron: admin_password = *** admin_tenant_name = None admin_username = None auth_strategy = keystone auth_url = None ca_certificates_file = None endpoint_type = publicURL endpoints = None insecure = False timeout = 30 oslo_concurrency: disable_process_locking = False lock_path = None oslo_messaging_rabbit: amqp_auto_delete = False amqp_durable_queues = False fake_rabbit = False kombu_reconnect_delay = 1.0 kombu_ssl_ca_certs = kombu_ssl_certfile = kombu_ssl_keyfile = kombu_ssl_version = rabbit_ha_queues = False rabbit_host = localhost rabbit_hosts = 127.0.0.1 rabbit_login_method = AMQPLAIN rabbit_max_retries = 0 rabbit_password = *** rabbit_port = 5672 rabbit_retry_backoff = 2 rabbit_retry_interval = 1 rabbit_use_ssl = False rabbit_userid = stackrabbit rabbit_virtual_host = / rpc_conn_pool_size = 30 proxy: http_proxy = None https_proxy = None no_proxy = service:central: default_pool_id = 794ccc2c-d751-44fe-b57f-8894c9f5c842 enabled-notification-handlers = managed_resource_email = hostmaster@example.com managed_resource_tenant_id = None max_domain_name_len = 255 max_recordset_name_len = 255 min_ttl = None storage-driver = sqlalchemy workers = None service:pool_manager: backends = powerdns cache-driver = sqlalchemy enable-recovery-timer = True enable-sync-timer = True periodic-recovery-interval = 120 periodic-sync-interval = 300 periodic-sync-seconds = None poll-delay = 1 poll-max-retries = 3 poll-retry-interval = 2 poll-timeout = 30 pool-id = 794ccc2c-d751-44fe-b57f-8894c9f5c842 threshold-percentage = 100 workers = None ssl: ca_file = None cert_file = None key_file = None storage:sqlalchemy: backend = sqlalchemy connection = *** connection_debug = 0 connection_trace = False db_inc_retry_interval = True db_max_retries = 20 db_max_retry_interval = 10 db_retry_interval = 1 idle_timeout = 3600 max_overflow = None max_pool_size = None max_retries = 10 min_pool_size = 1 mysql_sql_mode = TRADITIONAL pool_timeout = None retry_interval = 10 slave_connection = *** sqlite_db = oslo.sqlite sqlite_synchronous = True use_db_reconnect = False designate-2.0.0/doc/source/functional-tests.rst0000664000567000056710000000507212701406243022721 0ustar jenkinsjenkins00000000000000.. _functional-tests: =================== Functional tests =================== The functional tests run against a live Designate, making real requests and verifying they were successful. Installation ============ The functional tests are written using ``tempest-lib``. All the dependencies should be in the requirements files: :: cd designate pip install -r requirements.txt -r test-requirements.txt pip install -e . Configuration ============= The Tempest tests require a config file. The config specifies the keystone endpoint to authenticate against, or to run in noauth mode against a Designate without keystone. Set the ``TEMPEST_CONFIG`` environment variable to specify where the config file is: :: export TEMPEST_CONFIG=tempest.conf The config file should look like the following: :: [identity] # optionally override the url from the service catalog # designate_override_url = http://designate.example.com # Replace these with values that represent your identity configuration uri = http://localhost:5000/v2.0 uri_v3 = http://localhost:5000/v3 auth_version = v2 region = RegionOne username = demo tenant_name = demo password = password domain_name = Default alt_username = alt_demo alt_tenant_name = alt_demo alt_password = password alt_domain_name = Default admin_username = admin admin_tenant_name = admin admin_password = password admin_domain_name = Default [noauth] # set this to True to run against designate in noauth mode use_noauth = False designate_endpoint = http://127.0.0.1:9001 tenant_id = demo alt_tenant_id = alt_demo admin_tenant_id = admin [designate] # the tests will verify changes propagate out to these nameservers nameservers = 127.0.0.1:53,127.0.0.2:53 [testconfig] # Specify how build the path for the request. This will be appended # directly to the url from the service catalog (or the override url). # {tenant_id} - the tenant id # {tenant_name} - the tenant name # {user} - the username of the tenant # {user_id} - the user_id of the tenant # {path} - the versionless resource path, e.g. /zones/ID"), v2_path_pattern = '/v2/{path}' # if true, skip doing admin actions like increasing quotas in test setups no_admin_setup = False Running the tests ================= Make sure to set the ``TEMPEST_CONFIG`` environment variable to point to your test config file. Then run the tests with tox (you may need to ``pip install tox``): :: tox -e functional designate-2.0.0/doc/source/mdns.rst0000664000567000056710000000134312701406241020353 0ustar jenkinsjenkins00000000000000.. _mdns: **** MDNS **** MDNS Base ========= .. automodule:: designate.mdns.base :members: :undoc-members: :show-inheritance: MDNS Handler ============ .. automodule:: designate.mdns.handler :members: :undoc-members: :show-inheritance: MDNS Notify =========== .. automodule:: designate.mdns.notify :members: :undoc-members: :show-inheritance: MDNS RPC API ============ .. automodule:: designate.mdns.rpcapi :members: :undoc-members: :show-inheritance: MDNS Service ============ .. automodule:: designate.mdns.service :members: :undoc-members: :show-inheritance: MDNS XFR ======== .. automodule:: designate.mdns.xfr :members: :undoc-members: :show-inheritance: designate-2.0.0/doc/source/backend.rst0000664000567000056710000000234012701406243021001 0ustar jenkinsjenkins00000000000000.. _backend: ******* Backend ******* Backend Base ============ .. automodule:: designate.backend.base :members: :undoc-members: :show-inheritance: Backend Akamai ============== .. automodule:: designate.backend.impl_akamai :members: :undoc-members: :show-inheritance: Backend Bind9 ============= .. automodule:: designate.backend.impl_bind9 :members: :undoc-members: :show-inheritance: Backend Designate ================= .. automodule:: designate.backend.impl_designate :members: :undoc-members: :show-inheritance: Backend Dynect ============== .. automodule:: designate.backend.impl_dynect :members: :undoc-members: :show-inheritance: Backend Infoblox ================ .. automodule:: designate.backend.impl_infoblox :members: :undoc-members: :show-inheritance: Backend Nsd4 ============ .. automodule:: designate.backend.impl_nsd4 :members: :undoc-members: :show-inheritance: Backend Fake ============ .. automodule:: designate.backend.impl_fake :members: :undoc-members: :show-inheritance: Backend Powerdns ================ .. automodule:: designate.backend.impl_powerdns :members: :undoc-members: :show-inheritance: designate-2.0.0/doc/source/support-matrix.rst0000664000567000056710000000066012701406241022431 0ustar jenkinsjenkins00000000000000 DNS Server Driver Support Matrix ================================ This info should be maintained along with the list of current driver maintainers responsible for the “Non Integrated†backends. The upkeep of this list will fall on the PTL or his/her delegate. Should a backend’s grade be in dispute, it falls on the current project PTL to make the final decision after listening to all sides concerns. .. support_matrix:: designate-2.0.0/doc/source/images/0000775000567000056710000000000012701406373020132 5ustar jenkinsjenkins00000000000000designate-2.0.0/doc/source/images/Designate-PowerDNS-Detail.png0000664000567000056710000012766312701406241025413 0ustar jenkinsjenkins00000000000000‰PNG  IHDR–Ⱥrâ‡sBITÛáOà pHYsÐй‹çŸ IDATxœìÝy\Tåþðç̾° (Ȧ,*Š"‚Š‘Þ¼Vn-¶h.ݳL3MoV–fšfzo¥f™^5¯EêÏJ½š;î(ˆ Š Ã¾3Ì>sÎïs›?Paù¼ÿðuæÌóœó}žs/ÏyÎ9Ã0àaDÓtym]J¥ÖêªêëÍ4M¦>ìEˆH àóxB_Àç x<Š¢8EQTãíM&“Ùl4›Íf³Ñdf?L&ËvØŠ¢\¤‰T*yÊ\ÄâNoqwA!…€‡MÓ¥Õ5¥ÕÕå5µfš&„p(JÀç»9;¹9;KE"O7ÕêVîCH]ƒZ¥Q7hu•µu5 ÏLÓF“ÉCæªÉzÈåÎäµRXpHF³ùvQqIe•F¯'„ð¸\/77o¹›ÂÍCut²ÚnujuyMmiUuMC—Ã1Ó´¿·WO¹ÜSæjïÐRXpÊŠŠ;Å¥uj5{Ñ¿—³—ÂSÀçÛ;®vc),+/­®.,¯p–H!=¼{xó¸\{‡æÂ@—¦7ÏgeשÕ&³ÙßÛ+<(ÿÐåyf³ùvqÉ’RƒÑ( Czùúy)ìT—† 2dȹsç’’’þøãÝÑwß}7}útBHFFFxxx‡î«š´½ÓºîYQEå•Ü[ ø¹8GºH¥öލ“˜i:ãö¼âŠ¢zzÈ……p8{Õå G K˜4iÕˆ\.4hÐÆM&S ŒÃáH$’^½z¥¤¤lÚ´Éh46/óôÓO[V&$$PÅ~4™L_|ñETT”«««T* 3fÌ–-[ZÝ/EQ\.W&“ :ô‡~踖v¦¶ôªmóçϧ(ŠÇãuhœ`Å•UΤí;}¶¬¦æÑÁ±64a@x÷É_ !\'*¸÷„¤„'‡ùzzL;øâ¥Ì;ù4†Á/èZ¤R)MÓÕÕÕÕÕÕ/^¼víÚ×_m—HŒFcã¿z†ÑjµJ¥R©T>|xË–-¿ýö›L&k\e÷îÝo¾ùæ!CšomÁ‚ëÖ­c—ù|~AAAAAÇ›1c†í0úöíK¹}ûvZZZZZš§§ç˜1cî·m]F[zõA9qâMÓÉè²4zý…9fÚì*•ŽÄ}è¦ ÜOO†;Å%?Ÿ8Åçñ’¢"\»SBßüo]‹R©Ôh4·nÝR(„ï¿ÿž¦iBÃ0ÿøÇ?¢££Åb±X,މ‰ùæ›oØ*;vì`‡ôŠ‹‹ !Ÿ~ú)EQ~~~ì·O<ñEQñññìÇÍ›74H*•J$’øøø}ûöYv=dÈŠ¢FŒ±qãÆÀÀ@‘HTRRbù¶´´´´´ôðáÃì¦Î;÷Ê+¯4ÿ­·Þ²Ú®]»vBy䑚šƒÁPUUõÛo¿Mš4©Õ9sæLVVÖ¯¿þÊ~>>ÞÙÙY"‘ôíÛ÷Ÿÿüg“-«TªaÆQåååuõêUÛýcéœuëÖI¥ÒaÆeffZ¶¦Õj_~ùe™L&“ÉfΜ©R©Zmi­W[ &**jÍš5„³ÙÌú™3g¶Ú'‰‰‰b±8%%¥-@gº[V¾ç؉3×ãú…Š‚üµ Š ž=&& ;dpV~Áoç.dåt÷!Y  ˜8q"{BÖÔÔ0 “——Ǧ°B¡Ðl63 óú믳|}}}}}Ùåùóç3 Ãf®„;w2 3vìXöc^^MÓîîî„%K–0 Ãæ—gäȑÇg‹}÷Ýwl qqq„±XÌîE&“6 Œa•JÀn§¼¼Ü¼««kpp°%ŒaÆB"##ÙZìW111§OŸÖétíê³Ù¼uëVöãªU«Ø?þx```JJÊO<Áæë\.÷Â… ì·óçÏgË;99EDD¸¹¹M:ÕÒÆ¤¤¤úúz6kôõõÍÎÎfkÙè¶"‡ÃquuMJJb¯à÷ïߟ¦i¶®e8ÙËËËÝÝÝÙÙ™ý˜‘‘Ñêá¶Ú«6‚yþùç{ôèÁ®‰‹‹‹‹‹ûä“OZíKÛ­~»¸Y¨üþ×Cg2¯[þ36ʹ[øó‰Sçod›»k×!…….Á’ÓH¥Rq£w™Ìž=›a˜;wî°oI™0a‚Ùl6™L=ö› 3 Ã^mõÕWM&“‹‹‹««+›îX;–ŸŸÏ^D¶dÓ¦M#„ôèуý¯“Íi!;vì`Æd2™L¦æÉÃ0³fͲlÖ¼\.ÿé§Ÿ!:®I »mÛ6Ë Ç‹ŠŠz÷ÝwKKK[íÆÆŽ«V«Ùeee ÃTUUåååeddˆD"ògN_PPÀ¶tÈ!lØF£ñêÕ«–6ÆÄİáõîÝ;??ŸÝ íþa+r¹Üëׯ3 ³dÉ6$¥RÉ0LQQ[÷/ù‹ÉdÒh4ƒ jW Û¤W[=Xo¿ý6OãÍÚè),@STQ¹õàï§32íˆc+«®Ù{üä…9Ý0ÅDèZÔjµV«uss‹‰‰Ù°aÃÆ !ì@!dêÔ©‡Ëå>û쳄³Ù|éÒ%BHrr2!äĉéééõõõ¯¾ú*‡Ã9~üøñãÇ !b±xèСçÏŸgç$¼óÎ;ìÕçï¾ûŽRRRbÇ%„ôîÝ›Ý8—Ëm'Ÿ|2111??íÚµM¾zþùçÓÓÓ.\ÇãñÒÓÓW®\WWWg{›}ûöíׯŸ‹‹ !äèÑ£–‹é¿ÿþ»¿¿¿\. 0`€N§#„° ±´tîܹì¼RaÙæ¥K—NŸ>íêêzâÄ ve[úgÀ€ýúõ#„ôéÓ‡]SZZJ¹~ý:[÷ùçŸçr¹b±ø™gžiW×5ÑÆƒÕ„>€®C¥ÑîLáp8ýû7ýÏwÍš5ƒ^±b…åJ·ExxøÊ•+ !:îƒ>X¹reAAÁ±cÇžxâ »;sæŒL&ÓjµÑÑÑÙÙÙsçÎ}úé§srr¦M›FÓôÈ‘#_zé%‘HôÒK/©T*³Ùl;x–““SCCC]]Ý矾zõê&ßÚèvx›bIî›@Ðd¡šôªåAW¶Vc÷Ù'Ð BN]˨Wk&L|øìjG¾ž“G%ÏÊnÐjGDEt“™ÄHaÁ 4ˆ¢(†aþõ¯=ùä“ Ãìܹ“Âårcbb!#FŒàp84MoذA"‘ÄÄÄ$&&®_¿¾¬¬Œü9FkÙˆ———%o«ªª:zô¨\.·ì‹já„z½¾¼¼<33sÙ²eùùù„)S¦xzz6);uêÔíÛ·³Ù³Å‹/¾8lذѣGûùùq¹\þŸ/’aÇÛ®¢¢Âd2eff²?üðÄ„„;wî4¾}jðàÁlo¬[·n̘12™Ìl6gee 0€-“’’òÞ{ï­Y³F$-_¾¼íýcUÿþýÙ==zt„ ¤Ñmg¶µÔ«­#‘H!4Mk4vÙvŸÃ0ujuu½ªF¥ªmPWÕ׋—KÂþ%jY ÿÿ#»`ùÈçrå®.ž2Wg‰TæÔŽûâµzý/§Î$ÇDã}ª"$®_˜J£Ýólj!ýûx{Ù;¢‡@@@Àk¯½¶aÆŸ~ú‰½ð­T* !o½õ;Øéææ6pàÀK—.ÕÖÖ&''óùü¤¤¤õë×744?SØ€€€9sæ¬_¿~Æ Ç *((¸~ýúàÁƒ'OžÜj ÞÞÞ?ÆÅÅ5¿ÇŸµbÅŠ½{÷jµÚÆ+OŸ>½mÛ6òçôM6Ùòòòbc³!>>ž¢(¥RÉæÄcÆŒa§Òòù|£Ñ8þü1cÆìرƒÍ Ù*~~~óæÍ[½zõ¹sçzõê¤T*ÇŽ»}ûvËf/^\SS³zõê?þX$-Y²ä~ú§gÏž/¾øâÖ­[7nÜxûömFsêÔ)ÛUX-õj«Á°ãß ÃôíÛ·G‹/¶Ý'ÝPayyu½ª´º†a3MóyüðCË¥ù–ܸqƒ" CBBÆ÷þûïBz÷î½sçÎ÷Þ{ïÊ•+µµµ|ðÁ¼yóØ!gËîÂÃÿú꫌ŒŒœœ???ËcÅ—©­­Ý¼yóÒ¥KÅbñÛo¿}?ý³aÃ.—ûã?ž:u*%%åÃ?´Üòeƒ^µ̤I“fÍš•ššz÷îÝ»wï–——?ÞvŸ<ôB”åå7 ‹Lfs½Zìëã)sèÔÒÅ¥{Ãår½ÝݼÝݯ¤¦´ª:WYt®>›a>àíÕÛ§'—Ã!„dæåWÔÖNM퉑#Ê/-½‘—¢(öÝìyzîmg©DÄç ø|W'©—ÀÇå x<ÞŸÓ L´Ùh2Mf½Ñ ÕÔ:]U}½ÞhlÐjÍfšÝ‡¢Lf³§L&wuñvwsjt¿µÝá³L«×ŸÎ¸®3!~^Šþ\{¿ÂÃl6ç•”få°c~î.Î)ƒbíÒÃM£×‹…ÂŽû ¡ª¾¾ª®¾´ºZ­ÕÑ CÓ´§LÔ³‡Â­CÞDÓFHaOu½êòÍ\BˆH(ˆ –4ºiµK¡i:ãNþü™“SxP€o³[ÀUÕ×ß))-ª¨  ÃôñéÐÛ׹·‘!…pfš>#»¼¦Vá&ÚÉIÃý0™Í·ïUVŠ…Â¡ýûJZxº8š¦¯ÞÎ+ª¨Ôê .RÉðÈóRX ÖêNedšizH¿¾î.ÎöçÞéÆ¼â’¾þ~­G£3N^ͨS«=e²è`gIÎE Ð¥Õk4§®e:‹ÅCÃû9а+tgµ êK97Mf³Ÿ—"Ì߯#æé"…袴ڣ—Ó݇†÷³ûMZ÷ çna®²ÈS&‹ y°ç0RX€.ÇLÓûN¥(2.~F^ÁÑ©uº´ë7Üœ¢C‚Ô6‘Ât-µµG/§2ØE"±w,LQEåÿœ=—28&àÿ¿×æÞ …è*B~?wÁY"‰Ð/€‡ÒÕ[·+jëFFGÝ缤°]‚ÙlÞ{üTbTD“w_KË),ÀƒÁ0̹¬ì»åå.I@ï`Ÿž\.×ÞAtQõjõÕ[y5 nNN‘}‚\¤íËe‘Âܯ’ªêó7²y\n_¿Àž=îíö€î©¶A}õÖí:µÚÝÙ9²O³DÒ–ZHaî]®²(çn¡§LÌǘ+À}¨S«/ßÌ­Wk‚}}Z½Ó ),À½PVTî?}v`pŸ!ýûÚ;€‡Ê­¢â[Ê¢ÄÈQ‹ïaF Ð>&³ùØ•t¹‹KtH°½cx8™Ìæ_Nq‘J‰±Z),@;–W\¾™›2(F,Ú;€‡\QEåéŒëO&ãóš>),@[8“æãé10¸½è.tÿŸ0´Écé´Îl6ï>vz<9f Âíÿ^eDZc@ŽbïñScBþ Ðù8ÎSÉ#_¼¤Õþo¥pûNŸ10ÒÝÅÙÞtSŠzrø°ƒiç,k0‘À–³™Y^înA={Ø;€î.¯¸¤¶¡}FaZTQ[§5è‘¿ÂýëÓ§EQK–,±w ,¨g»eåìà+RX€ýqåꈨH{GÑ]Œ1‚¢(Š¢x<ž««kxxøÜ¹sóóó›رc»&55•]£T*Ù5fÉ’%ÁÁÁb±X.—GFFΘ1£®®ÎꋊŠ^{íµ   ¡PèêêšðÝwßul#áþöìQXVN0‘ %¹Ê"½Á`ï@º‹#F?~¼ÉJ—}ûö%%%5.лwïììl—ššúä“OB }}} !Ó§OgÓP‡CQ”Ùl&„ܹs'  É–³²²’’’*++ÙÂ4M³ë_|ñÅžÈêt:š¦išàÁn¼[Ñê g2¯'Ç Ä(,€u7 îöGþÚ颣£5MnnîªU«D"Q}}ýSO=¥Ñh—¹}ûö–-[š×eæ§Ÿ~"„,^¼X¯×ëtºÜÜܵk×:;[¹綾^ª¬¬Û·o×h4J¥òÑG%„|ÿý÷©©©l™LFQÔºuëØ'ÆåË—‡„„//¯Ù³g×ÔÔX6Ζ|ûí·gΜéêê:cÆŒˆˆggç?ü-`£úÞ½{cbbœ¥RiHHÈŒ3î¯G*b¡@g0L$°Jo4 ù|ÊÞatCE‰Åâ>}ú,X°à£>"„”••íß¿ßR ""‚Ãá|ôÑG:®y]‡C),,ÌËËãñx}úôyóÍ7åry“’·nÝ:wî!dÚ´iS§N …>>>ßÿ=;DºsçÎVã|þùç—.]ZRR2fÌ‘H´iӦѣG›L¦ÆeþñlÛ¶ÍÃÃËå¶±zaaáÓO?}ùòåÁƒ9’¦é½{÷¶±ëº Š¢RX«î—ûúØ;Šîî±Çc²²²,+ûöíûÜsÏmܸ±y•… B~øá‡ÐÐPww÷I“&>|¸y±œœvaèС–•^^^„ÜÜ\ÛeddìÞ½›òÛo¿íÛ·ïÊ•+"‘èòåË¿üòKãbb±øÆ·oßÞ¼ys«ß¾}Ûd2ùúúîÝ»÷À·nݺxñ¢í`ºv,RX+J«k¼ÝÝìX÷Á‚•+WªTª&_½ûî»ÇŸ={vhhhMMÍÞ½{SRR,·5ÇŽÚ6ÑêtUKZ™@Q”\.g‡„¯\¹Ò¸Ø“O>Ù»wïæ´Q=""ÂÍÍM©Tº»»Lœ8±Õ|º[©¬«—»¸BxöŽ +Òèõ‘ÈÞQtwdúõë×x}@@À¬Y³6nܸvíÚæµ !£FÊËËÛ±cÇÔ©S— a.^¼øÂ /°ËwîÜ!„„……±kØkÖ–;½êëëÙËÝðsæÌiœž2¤ñ^¼½½­¶ËFuww÷óçÏõÕWçÏŸÏÌÌüé§ŸRSS/]ºeuSÝÍ•›¹Ãô'Ha KaF«Õ§¦¦.]º”¢P(Æפؒ%K¶nÝÚdÔ“2eÊ”I“&%$$ôèÑC °ƒ¬‰¤I±àààAƒ]¸paóæÍ£F7n\UUÕÌ™3 !Är•B¡¨­­ÍËË#„œ={¶¢¢‚]Ë.ÄÅÅY’ãÇ7IµÙ ¸9Õëêê„BáêÕ« !&“©W¯^¥¥¥/^D KQëtfšfÿ¶D `…Ï7šL|~Qv¶Ë—/7Î8]\\vïÞ-•J›óööž;wîŠ+š¬?tèО={!|>ßh4²+§L™Ò|Gß~ûmRRRuuõ“O>Ù¸ð’%K†Î.9òæÍ›_}õUffæåË—-ÏÞŠˆˆ˜4iÒ¿ÿýï^xáÛo¿åñx™™™ÅÅÅW®\ññi} µê111~~~UUU¥¥¥E!eý~þâ˜ÁÿÍþ1ÀŠrweE¥½£è¦8޳³sß¾}_{íµ+W®Œ1Âj±wÞyG&“5Yùå—_N˜0!00Çã‰ÅânÚ´Éj žžžþꫯZ†K¿þúkö1¬åË—?^,¬Y³†½Ù‹µcÇŽ>ú(88øäÉ“çÏŸ÷òòzçwüýýÛØÆ–ª{yyM˜0¡®®îðáÃ×®]‹ŽŽÞ¾}»eÔ¶;»róV¿Ëô¼ÚÀ µVw1çfRT„½Nòæ›o~ñÅQQQ§OŸn>ñì+WYT^SË΂eaÀ ©XTÛÐ`ï( ó¬Y³&999==}Ú´iöŽþMÓ¿¦/(-kœ¿ŒÂ´ä\V¶¿·ÂÛÝÝÞtG Ã\ÊÉUVT é߯ùîÂXGÓôþ3i'ÄÛ;€n'#ïNnaQlXˆŸ—Âj¤°-:—•ííîæïíeï@º‹[Ê¢ô[·#z…ôòµQ saZ×/ìtÆuÃÿñ=tœÊººI#mç¯),€m“F&þûØ -:…F¯Wi´­C `‹€ÇŸ0tϱã˜zÐ ……^¾™Ûj1¤°­p‹GŒÚöûa³ÙlïXrÎIZÝj1¤°­S¸ÉOˆÿî×CjÎÞ±<ä¤"‘Þ`´]O$h+š¦ÿ}üdlhHPÏöŽà¡•«,"„ûúØ(ƒQX€¶âp8SF&©uºßÏ_Äc :ˆ‡¼¨¢Òv^ç„ðÐÒË÷·sœÅâ„È|.×Þy:ÐÛ{`H{ÇÐÝ.*®U«cB‚ÛX£°Ž¢¨ ‰ rW—_NÑ05àÿ©W«¯ç´=%…èL“é·sÜ]œ‡…÷§(ÊÞáØŸÑdúùÄéI#9íù‰@ ÐÙjTª3™Y>ž‘}z#…îŒ!d÷Žý5~¨T,jWE¤°öQ£j¸’›+srŠ £æH IDATîÓ®ñ'€‡Æ¯i磂ûô»··"RX{*(-»˜sÓËÝmH¿¾­¾¾ë(©ªê!—Û; p` !Ïž  ð÷öº‡êHaìO¥Ñž¿‘M3´—›[x`‡ÓÕï·N=yú‰áÃì8*3MïýãäèØhwç{ÛRX€.¤ ´ìÜlN7 wP?ÿ¶¼iÓ.²ïšÌæðÀ{ŽÇ`2¥ž<2(FæätÏA ÐWVå*‹TPÀêÑ#°g®6_öǣǟH&àñì8’;%¥WoÝþËиûËí¥ðìãÓ³N­9qõÚĤá´kxh–—ŸÍ¼ñX|œTÔ¾‡gµ),€3šÍÊòвêš•Š!„"„ý—"‰$B¡PÀ |O$à‹‚?¿´`´zƒF§3šÍzƒQg0¨u:µNÇçrÙíL&™““ÌIêåîîå&kþ:†»eåé·nÿuØPŒÅv}4Ã<{.)*ÂY"é´ªuº_NžQ¸É’c£àI‚àá¤Ñé4z½Î`Ô F“Ig4êôVÞm+ $"ŸÇò"@* øüví¨¤ªêÐùK“F&>¨6èZ½þ—Sg×iù«Ád:xöœ™¦ÿ:lèŸ3î—Î`8˜v~@P`°¯½c+Š**Og^bx'Ý~g0\º¢7í$wÄ.ÂÀƒqýN~®²èÑÁ±b¡ÐÞ±ÀŒÆÃ/÷”ˆôé„ÝÕ¨N^Ëàr8#¢"ÛûÎØvA ŒÉl>qa˜aá|ÇyÙØC‰a˜ãé×jT ÆÅJ:ø Áp1ç¦Þ`t‘J¢ƒûp;þÐ#…€L«×§]¿!àó‡ô ë„lš`ætÆõ‚Ò²Q1Qúàzµ:óN~e]½Ï9 £åÆÂ@‡hÐjӮߠ(jhÿ¾ÜéÕ)Lfó©k™e55ñáýz)± ƒÉ”[¨Ì/-£iÚÕIÚ?0@îâÒ;² ),t ½ÑxêZfJàímïpZ…åå9w•µu>O*‰…BO_O‘à~ßQ¬Öé Ë+”åz£‘"äóûøöôóò²ïëâÂ@‡cæLfVEm­³D"s’Ú;¢‡„Þ`<•‘YTYÙ;È2mÃh6ç—V×4hµ\‡fB‡¢¤b‘‹TÊãpø<ŸÇãr8‡CQjN«×ëF½Á¨7õF#EÍ0&³YæäÔKáÙKáÉïJ/F Çh2¥eݨQ5¸J¥‘}‚dNõR±‡[ƒV{áFC.‡Ò§ze¦A«Si4&³Ù`2M&š¦iš¡ # EB¡Ï ø¡°ëÏ`F v`4›/çä–×Ôð¸\OAÍ_ýÑ4W\’S¨òùb¡p`HŸÎ¼}ª«A öd4›oßR™Ìf>×?Ðßîó,»†Â²òÛÅÅj­ŽÏãù{)‚{ùr9{ÇeHa «`ïvϾ[Èåp¸ŽŸ·Www…›ÌÞqu*½Ñx³PY\Ye4™h†ñóR  èúWö;RXèŠBŠ**”•ÅUBŸCQ 7Y¹Ü[îþ0Ñ2„”TVUÖÕUTÒ #äóEŸ—Â×ÓƒƒÑÖ–!…À0LymmIeuQe¥eÜÕÅËÍÍCæêÒ¶û™ì®º^U§V—×Ô–ÕÔx<3M3 ÓÓCî)“ùzz`6pÛ!…GU£R•ÕÔVÖÕU׫x^jçP”“Xì$;‰Å¡ÐÍÙI܉·=é •F£ÒhëÔ ZmZÍ>µŠ}@•§««ÌÙIá&swqAºz?ÂÀC…!¤A£Qi´ Z­F¯¯U5Ôk4þ3ç¡a—8%ð¹EËãp8<—Çáp¹\E1 Ã0„aš0´™63´ÙLLÿ}r*‡¢,)”eƒ&³Y$¸;;;KÄ®NR'±ØI,îüèÂ@÷¥3Ì4=þñǾ³0vÐ “Ùl2›Í´ÙL3Š¢(BQ‡âp8—Ãár¸|O(à ºÒCþ»'è¾Ø÷¯št:±€ïîâlïp ­p§tw¸(íp€ƒA @ð@+Ç‚ RXèî0Öá …ƒsa RXp0Ha »Ã\X‡ƒ  RXp0HaÀÁ …€îsaRXÌ…u0HaÀÁ …€î RXp0Ha0ÖÁ …ƒº;Ì…u8HaÀÁ …À\Xƒ RXèî0Öá …ƒsa RXp0Ha »Ã\X‡ƒ  RXp0Ha »ÃD‡ƒ RXÌ…u0HaÀÁ …€îsaRXp0Ha0ÖÁ …ƒº;Ì…u8HaÀÁ …À\Xƒ RXèî0Öá …ÀDƒ RXp0Ha »Ã\X‡ƒsa RXp0Ha »ÃD‡ƒÀáéõz{‡Ð©xö 3œ:uêúõëöŽ¢Cèõú-[¶¼úê«öÀUUUíÝ»÷ܹsö¤û5jTpppÛËS9€îàõ×_߸q£½£ë~øá‡çž{®íå1 ÝÈðáÃû÷ïoï($£Ñ¸mÛ6£Ñ(—Ë'OžlïpÕž={F%—ËíHwtôèÑ›7o¶·RXèFž~úé‡ì‚ûÇÌçóF£^¯Ÿ8qâèÑ£í€C:{öì{ï½iï@º£^xáRXÜÎà¨T*Õ§Ÿ~ªÑh! óçÏ·wD Ï…u,HaÕºuëÌf³åãíÛ·=jÇx: RX‡T__ÿÙgŸ±C°,µZX€{ƒ»ÛRX‡´víÚÆC°„†arss;f¯: RXÇS__¿zõêÆC°, ÄÜ3Ì…u,HaÏš5khšn¾ža˜›7o?~¼óCèLx¨€ƒ©««[³f !ÄÅÅ…ÀGÓ4‡óß! ½^¿hÑ¢3gÎØ3DGƒ¹°),€ƒ©¯¯ß²e û—a˜ÊÊÊ?üpݺu–5 ØÍf.—kïH &8¤°¦W¯^O=õ”åcAAÁçŸ>uêT;†ÐÉ0À±á(ÀýÃÏ‘ÃA àðpº¤°Ž £Gþt,HaÃ0øÕ Ý RX‡‡à>áj†ÃA àØð«º!¤°£°÷?GŽ),€cÃ\Xè†Â86L$¸ø9r8HaFa »A àØ0‘àÀÏ‘cA àØpº!ž½€û…Ñ£{æîîn0ìØŸV«‰‰áp0´×ŸþùìÙ³íµw¤°Ž £°÷C£Ñèõz{G]‚V«µwÆh4ÚqïHaæÂÞ¿ÚÚZ>Ÿoï(Àž¢££wíÚbï@ÃÛo¿ýÕW_Ù7¤°)ì}‹ÅÀÞQ€=Q%‰$‰½q <žýHÌùpl˜HÝý“h¸O…hš¦W­Zeù󢨪ªªÍ›7{zzZÊ<þøãaaav Z‡À±a.,@{q8œ³gÏ8p ñÏÎ_|Á.0 #‹_{í5;Emò߉'Ož;v¬›››““ÓÀW¯^}o÷åEEEíÚµ«½µbccï¡–Ü[6\¼xQ&“5ßÑýhd»6{ lR%,,,55µ][°1bEQE9;;ÇÇÇÿñÇ÷¶{Ø£D" ™={vnnn“oÏœ9cYãááqàÀv933ó±ÇóððJ¥aaa‹/¶½¯ÆÇº%mìÿûéd€¶ÃD€{°bÅ ‘HdnÄô'‘H´hÑ"'''{Ƕp!©©©£GŽŽŽ>wî\YYÙÖ­[oܸqíÚµ¸†aL&ÓÜ`ó¿óÎ;111´‹Æ¬î¨CØ-^¼Øh4ÄÅÅ?¾¶¶¶ƒvdéXv»víÒjµ¼té’¥˜\._°`Aóê4M;ÖÏÏ/33“­ÐA¡ØFaÚ«_¿~ÉÉÉ\.·ùW\.÷7Þèü ]84M¿þú믿þúÇ"•J£¢¢¶lÙ2xð`BH}}ý+¯¼Ò«W/…Bñì³ÏVUU±ÕÂÂÂÞÿý‘#G†‡‡4èúõë„9sædeeÍ™3' `ÆŒl±%K–$$$„……¥¥¥}þùç¡¡¡ÎÎÎ+W®´ÙîÝ»###ÙåW_}U ¨ÕjBÈÖ­[ããã›o|ÕªUlNÓ<Œ–Z±víZ''§ž={~úé§M(,,|ôÑG]\\ÂÃÃÓÒÒ,ë-;jCK;ª­­}å•Wüüü\\\bbbnݺՄ¹¥cmõŒmÞ™6Nì7n <ØÙÙyذaYYY66K¬m<ÐÍa"À½Y¹r¥P(l²R"‘¼ûuW¯^%„\¹r…±fܸq'N¬¬¬Ôh43fÌxâ‰'Øõ¡¡¡±±±555 Ã,_¾|äÈ‘ìúÈÈÈ;wZª‡†††‡‡WVV²wïÞ}çΚ¦/\¸ —ËSSSÙõ111k±ÊËË9NEEÃ0!!!}úôùõ×_†™:uê’%Kšo¼ñFš„aµYYY...999 ÃTVV^¸p¡IqqqÓ§OW«Õ·oßîׯŸ««kó5‰¡¥î3f̸q㊋‹ÍfóÕ«WKJJšÉn¶ººZ$eff²+§OŸþ·¿ý­ùqiRwèСÏ=÷œJ¥*..>>«V­š?>Ã0=zô8vìXó·”¶Ԋ›7oJ$’½{÷Z=S³³³)Šª®®f?~ûí·-¥°–ZÚÑíÛ· !eeeMva5…efêÔ©óæÍcF¥R9995Ï­›ÔÍÎÎ&„TUU±ÿýw‰DBÓ´íÝ5ŽüÊ•+ì´qÄKJJ’J¥^^^R©ÔßßÿÇ´ƒƒhûk|p›§°$„ÔÖÖ2¦°ƒ!88˜MP,),Ã0eeeï¾ûntt4Ç ùñÇ›4ÇÆ±n¬ñÛ¤3[*ºbÅ vÙh4º»»9r¤¥òÍOÈ6h£‡;…ŒŒ´wŽ )l7—™™)‹-ù«T*ýä“Oì”è ),ÇÃÃRTTÔ|€6??Ÿ¢¨AƒDGG»ººZJ² !b±¸¡¡¡¥QÞž={Z–SSS‡îçççïï¿uëÖŠŠ Û#ÄÉÉÉG=räHrrrrrò‘#GnܸQ[[;tèÐæoIK­Þºuëúõë½¼¼’’’Nž<Ù¸–R©”ËånnnìÇàààVØÒŽòóó]\\ E«¡²fÍšµ}ûv£Ñ¸gÏž   ØØXÛå•J¥«««»»;û1((H£ÑÔÔÔ´º#vÁÉɉ=‚¶x“ ÓÓÓËÊÊòóó'Ožl#Ñöîl\¥RÉçó-kø|þŠ+>øà•JÕ¸¤B¡X±bÅ¥K—jjjf̘ñÌ3ÏX.è[6ÕÒ±nãk£X`` »ÀãñzõêŶÎjùæ'dÛts nç¸Wýû÷5j”e ³`oÀ€>>>Û·oŠŠjüÃ0~~~Eedd4Nlãpš¾+Á2C«¤¤dÊ”)‡JJJ¢(jÁ‚………¶·–œœüæ›oªÕêGy$**J©TîÞ½;!!Á2s¥¥é_ðъ)S¦L™2E«Õ®^½z„ 3ŸÚÚZ½^Ïî«´´´¥ -1´´#.—[___QQÑøisÄZ_±’’’d2Ù¾ýöÛÆÓd[ªëëë[WWWSSÃ&aùùù‰Ä’µº»ÆÚ~Ä¥R©··w[b°qmïÎöܾ;w&%%5iÔĉ׬Y³jÕ*«Uœœœ,Xð÷¿ÿ=##£_¿~–õ-kglãýÚ>± Ø“ɤT*}||l”orB¦¥¥µ÷º'saîçŸ~zôèQ­V+•J-Z$•Jí´ ‡Ãá|ùå—6lxÿý÷ïܹc0233_~ùå .ôîÝ;%%eÖ¬Yì/õòòò½{÷ÚÞœ··wNNŽÕ¯T*‡Ã §(ª¨¨¨-Ï$JLLÌÏÏß·o_rr2‡ÃIJJZ»vmrrr«‡ÑR+²³³=ª×ëÅb±B¡hòvì°°°®]»–¢ÓéÖ¯_ßêN[ÚQãõ4M_»v-`£¯fΜùÁ\¼xñ¹çžkµ!!!C† yë­·JJJ–.]:mÚ´æ¿Ïlì®Õ&´ÊF 6b»vÇ0ŒÉdÒh4éééÓ§O?þ¼Õ;?ûì³µk×j4öciié‚ ÒÓÓÕjuUUÕòåˆi2°ÝÒ±¶qÆ6îLÛ'öW_}•m2™–/_îìì<|øð–Ê7?!môÏÎ;¿ûî»¶è&ÂÜ3v –Ãáp¹Ü9sæØ;h+!äÉ'Ÿ<|øðÇüÅ_ÆÞ½{?÷Üs „ìܹóïÿû!Cªªª¼¼¼üñ‰'ÚØÜÂ… gÍšµvíÚ1cÆ4ù]²téÒøøx…Bááá‘’’ÂÞœnƒ³³óàÁƒ+++ÙKÞÉÉÉ{÷î5jT«­j†ÕVhµÚE‹egg³S$÷ìÙÓd#{öì™9sæ?þ(‘HRRRÚò”±–ºk×®]죸T*UHHÛ36úêÅ_|ï½÷&L˜`¹4o»ÿþ÷¿ßxãÀÀ@@0a„æOW°½»¶4Á6Š¢ZŠÁöAlûî>ùä“O>ùD$ùúúŽ1âòåË!!!Í‹ 6,%%åçŸf?J$’ººº)S¦(•J‘HÔ¿ÿ}ûöõîÝ»I-«ÇÚÆÛ¤3mœØ3gÎ|á…rrrú÷ï¿ÿ~@ÐÒf­ž-õÏÿüÏÿ444L›6­ÕCv1a³ÙÜi»3‰äñÇï´=Bž~úégžy¦3÷ÐqV®\yðàÁÅ‹cÖ‘ÿüs‘Hdï º"¤°]N[ž‡ðÐÛ½{÷믿^YYI …ƒŽ7nœ½ãêXׯ_¿|ùrNNNNNÎï¿ÿ¾eË–#FØ;®.),t-*•jìØ±§OŸ&„ :tݺuì{ﻆaNž<ùòË/ggg5jÙ²eK—.ÅåÙÆZV(Xõæ›oR …žžžƒ^¸pa“Ÿ[ŠyyyYžúǾ¢¨ÆOIKKûë_ÿÚ«W/¡P¨P(¢££Ù$¦3Õ,X°àôéÓ...›6m:}útwË_ !E%&&^»ví£>âóùï¿ÿþçŸnï º¤°€Á`¨¬¬¼páªU«úõë·oß¾æeÊËËÿñ´´…C‡ 6ìÀJ¥Ò`0TTT\¹rå›o¾IOOïÈÀ»œ#GŽ|óÍ7àܹs3gÎìÎC|>É’%ì;Õ—.]ÚêóÝ»!dĈì‚ÎÎÎñññüñÇße‰$$$döìÙ¹¹¹M¾=sæŒe‡‡ÇØåÌÌÌÇ{ÌÃÃC*•†……-^¼¸ùöcccÛò®„åêÕ«nnnO<ñDjjjXXX§íúâÅ‹2™¬ùú¨¨¨Î쫚ĖššjÇxîG»Î¨û9ý:ùÔ€²`Á‚_~ùeÍš5‘‘‘„†††§žzÊêÅW­ZÕÒcÑW¯^MÓ4ŸÏ_·n]ZZÚï¿ÿþÅ_$&&¶åõŠúúú™3g2 óá‡væ¯×®,99yÆŒZ­vúôéùÌé.î¿?‹/6qqqãǯ­­}à{bwQQQ±k×.­V;pàÀÆ·µÊåò 4¯EÓôرcýüü233ٺ͋±/xà1·dË–-±±±555©©© °šU· Ã0&“éÄŽ¥“O]è ãÇŸ7oÞÅ‹ÇOÑét}ôQ“b\.·¢¢bãÆV7ÂÞt4wîܸ¸¸””öfü)S¦ttü]dž ØldþüùöŽ¥ Y³fM¯^½Îž=kywü7…¥(ŠÇã¹»»¿ýöÛ*•*''§¤¤dòäÉ …Â××wîܹZ­–²{÷nöïKBÈ«¯¾*Ø?%·nÝO©¯¯å•Wzõê¥P(ž}öÙªª*ËžØ]H¥ÒèèèmÛ¶ÅÆÆ.\¸ÐòíË/¿œ››ûÓO?5‰¯¸¸X©T¾ñÆÞÞÞ‰$**jöìÙÍ›±jÕ*6!^»v­¿¿¿““SÏž=­¾¤ª¶¶ö•W^ñóósqq‰‰‰¹uë!Äjc !aaaï¿ÿþÈ‘#ÃÃà týúuBÈŒ3¶nݺwïÞ€€€€€€¡C‡~òÉ'lù‚‚‚””WW×ÈÈÈþóŸ–áRS§N±Ëiii–õaaaK–,IHH KKKk©÷ }ôQ—ððð´´´æš3gNVVÖœ9sf̘a£Eµ•Õ>´qd[Š’———””$‘H,½×–MÙèɰ°°Õ«W6L,>¼¤¤äã?V( …âË/¿$„¬_¿>..β“'OÊd2¶ùVÛÕ¸o7lØ`u„Û",,lÑ¢E‰‰‰LHHÈÊÊj{¯¶Ô"Ë©KZ8ßÀ±ðx¼Ï>ûŒ]þý÷ßišnüí³Ï>KY½zµÕØÀÀ@BHNNÎ_þò—¯¾úêÒ¥KÝpÈíܹs„·Þzë¡|&Ý=suu5kù³€4™ Ë0ÌÎ;APPÐĉE"Q^^Þ… ÒÒÒØ!ÒQ£Feff²·øÏþãïïòäIv™}ëýÔ©S+**ÒÓÓ $ÉÌ™3­î•¢¨©S§ž|¸¡¡!##ƒ ©‰gžyF©Tž;w®¶¶vëÖ­NNN„«eŸOùõ×__y啨ØX…B±páBN×9‘w—/_&„àòTslŸàÁÌÿ‡a˜¤¤$©Têåå%•JýýýüñGöæÇªª*ö^¿ÿþ»D"¡iša˜ˆˆˆÝ»wúøø¬Zµjþüù ÃôèÑãØ±cyyyE•——³µªªª(Šb_×–””ôÞ{ï5~-;7¹¶¶–ývÅŠƒ!88˜}ý£\.ß¿?[²¬¬ìÝwߎŽfßÿã?6ÉXLLÌÎ;oÞ¼)‘HöîÝ«R©¬¾‹Œ}¥GYYYã•6ºiÓ&výµkלœœØå3f¼ýöÛìòÏ?ÿÊ0Ì78N}}=»~ûöí®®®ì²\.?yò$»|öìYËúÐÐPËËÙZê=ö–Õêêjvý·ß~k©ÞXddäÎ;[mQcV£²Ú‡6ŽlK14iÝ•+WØÞk˦lôdhh¨å¡ß}÷\.7›Íìǰ°°0 3uêÔyóæ1 £R©œœœ.\¸ÐR»²³³9N]]ûqÛ¶m–±gT“†††®[·Ž]¦iÚËËëÈ‘#M [íU-j\·¥ó ˆÎÁ¬Édê„}u¾eË–¼`öOsçÎe™6~7&MÓb±˜]Ïþwg)váÂö’‘‡‡Ç… Ø•/¾ø¢¥î•+Wž}öYWWׯ¿©Ù¹¡ÝAii)!ÄÕÕµùï,èRÓ^0ûßQØY³f¥§§—••åççOžlã‘mË=³mÙ”žl‹¤¤$™LvàÀo¿ýÖ2+×j»šì(??¿Õ[ÞÍm4ïÞ½kÉÑ-¬öê}¶ˆÙl~çwØåG}´ùŒB¡pÑ¢E„;v4ùÊò¬.—³|ùröpNW__ß±qw UUU‡¶zÿBJJJ~ûí7Ë£…»9ë9GHHÈ!CÞzë­†††’’’¥K—N›6M¶óóó÷íÛ—œœÌáp’’’Ö®]ËÎ,ìÝ»wJJʬY³Ø4«¼¼|ïÞ½–m2 c2™4MzzúôéÓÏŸ?¿råÊæ»þì³ÏÖ®]k9<¥¥¥ ,HOOW«ÕUUUË—/g†ý‘n.;;ûèÑ£z½^,+ vFQc#¤iúÚµk¥¥¥6Û.¡¡¡QQQ .ÔëõEEE«W¯¶|ËNœÐjµëׯ·Z½¥Þ 8pàÚµk !:®¥êÞÞÞ–Çŵ±EV£²Ú‡¶¬ÕZÒ–MÙèÉ6š9sæ|pñâÅçž{ÎF»ÂÂÂbbbØ)•JË6|ýõ×YYYF£qÙ²e®®®Ã‡oRÀj¯Þg‹–-[Õ®*à(²²²^xáö9ö=zô7nû:¢{3fÌŠ¢–,YroÕ=<<(в<ÐÚåÚµkûöí[»vmLLÌþýû !"‘héÒ¥V Ïœ9Ó××·ù­Z/¼ðB\\ÜêÕ«9ræÌ™µk×^¹r…¢P(šL-ë),EQÿþ÷¿U*U```lllll¬å·»³³óàÁƒ½½½Ùñ§äääúúúQ£F±ßîܹÓËËkÈ!ì#f?êõ“O>áóùr¹|òäÉ<ïòåËV'k6,%%Åò˜D"©««›2eЧ§gppð¡C‡öíÛ×»wo«akµÚE‹) ¹\þÝwßíÙ³§y™]»vyzzÆÄÄÈd²—^z©¡¡ÁFcÛ…¢¨½{÷Þ¼yS¡PŒ3æ¹çžc§XBV­ZuþüùŒ=zäÈ‘-m¡¥ÞÛ³gÏþóŸèèèÑ£G=ÚjÝ… îØ±C&“=ýôÓml‘Õ¨ZêCGÖj 6:ªÕMÙèÉ6zñų²²üqËlŠ–ÚµgÏžÜÜ\…B1vìØ–î>lìoûÛ´iÓärù±cÇöïß/š°Ú«÷Ù¢»wï&&&¶½<8ŠC‡ÅÄÄüðÃ555ƒ êÕ«×±cÇ:î‰94MÆÚ8|öÙg?þø¼yó®^½JqrrÚ½{wDD„ÕÂB¡ÐêÓ†9þü‚ yä‘aÆ͛7=d .Ä…õÆÂÃÃ-/E“J¥ °:+£ÓÂàóùñññëׯoüSÆàóù7oÞd×$$$XþÎ,))™6m𝝝@ ððð:tèæÍ›;¿ìÌÃ…æØ‡Ù;ЇÁ=ô¤ÉdR(‡jW­ .X½UÎ"44ôçŸn×6­jo‹úöí[ZZzÿûíæºÚí\z½¾G„ÈÈÈââbveuu5{bEEÅk¯½$‘H"##·oßn©Èέ\¶lY||¼H$0`ÀÙ³gÿ—½{‹)ýþœšRÓtSM©¤ûL ©QºNÖòu¯uÉnQh‰olRîDä¶b­]‘]›Vîä.Tb•’.¤t£‹¤t¯óûã|¿ç7ß¹5]4S>ï?¼ÎÌœó<Ÿç9OútæœçÁq|èСœÿ·1‚Ü9,,lôèÑ åöíÛ8Ž/X°@OOO^^^VVÖÌÌì×_å,™|”Vxœ‹ùœBˆÈcˆ)#ß¾}Ëw7âüâ8ÞÔÔ4xð`âMòq®Ç¯Y³fôèÑÚÚÚ222JJJŽŽŽþùg7Ú×Çܸq!4nÜ8ợ]__Ò¤Iäß äã¶½ ­­­¹¹™CSSÓÊÊŠ¼bâääT__Ï'BhÆŒÄ;!âwâ{šÉ;ÍÈåË—³³³©Tê©S§¨Tª¶¶öâÅ‹·oßþÃ?û„„„¬_¿>99ÙÎÎ.;;»®®.((èÎ;………ãÆ å,Ð××—sÚãû÷ïËÉɵ··744]»víÆl6û‹µ€/¨¨¨¨´´!¤¤¤ÔÔÔäè蘛›kjj:gΜøøø¬¬¬'Ní¤¤¤477³ÕÔÔ¤§§cV]]­¬¬lmmMüõ˜íàà0þüÈÈHOOÏÖÖV®½±cÇ’’¤¤¤–-[vîܹ۷oÿý÷ßœ·AÏ™3'&&&00ÌzBrrr:::ÅÅÅžžžS¦La±Xl6[”I‡ RØž4}úôéÓ§‹;Šþ ;=)âôa¼X,–𥕉 w»ÆàB^YÏËËãš”ƒ˜³¢¾¾žsþµW¯^577“·__ž’øÔÕÕ µðÅùD{{û¦M›¢££ËÊÊÈyšÞ¿ßýÐË~ùår©^ii退€+W®äææR(”û÷ïkjjN™2eÚ´i'OžÜ³g“ÉÔÖÖ.--MMM½ÿ¾‰‰É›7oîÝ»G\ìpqq‘––¾páB‡=rýAÈÅÔÔôöíÛ\?P–––RRR'NœàºÓ=66vñâÅéééÄýÓ²²²›7o^³fMvQÿ),ˆ––Ö»wïÖ®]kmmML9üñãÇW¯^ßA+((ÄÅÅ‘kl655q®·Ils}Õ@¼É;(9Í>Bèï¿ÿÞ¹s§²²ò©S§tttBBBˆÅ8¾H#ø’ôõõ‡ª  ```àååÅd2÷ïßRWW'þD´°°@á8^\\L§Ó]]]Oœ8qÿþýÄÄÄ©S§¦¤¤·Ð×hEùëQø-jÄ´<¼·~…††ÆÆÆs.c>zôèôôôüüüG:uêêÕ«ÁÁÁß}÷(“”),ˆÅ€Ž;6}úôôôtcccKKË–––ÌÌL??¿ÐÐPSSÓÜÜÜíÛ·7îÓ§OÏž=SPP˜4i’ð2‰ß»'Ož¬««sppøî»ïx÷!ñnhhHMM…õÖAß5iÒ$®uz‰?ÿ*++ËËËét:¹Ø¸®®.BˆHa£££ß¾}Ëf³åääŽ;Fì@¤°¢üõÈù!§öööC‡ݹs!Äû›žžž¿¿ÿ®]»8ç >~üø¬Y³ ííí‰Ù–>|ø)¬ˆàq.‰'>yòdÞ¼y***?.,,3fÌôéÓåää—-[VRRzüøñ––ww÷ \¹r¥Íû÷ï8@<ÙÍËÝÝýÇ”’’ò÷÷OMM0aBO7 ±ùöÛo[[[}||,X€š3g±*'‘§ |:;;³Ù쪪ªªªªAƒ™››‡›šš~þüyûöíÉÉÉ ;wî}šØf2™ñññ];¶›¸Šêl$]«…ÅbõTü„'Ožp~¿ J ¢èfœ=xš¸jow¬‹‹ †aœw ]¸pÃ0GGGáfffNš4I]]]AAÉdrNâxóæM¦  àèèH¬e@V'|by" èTª©©é¢E‹Èõx„ñD|¡Á¾ ‹èèèâââæææwïÞ]ºt‰˜s‡N§8pàÕ«WåååwïÞ%g¨¬¬Äq|òäÉ!&“I<ÒN܇`llœ’’ÒØØˆã81Á$çÎiié_~ù…X.îÔ©S.\²3}‹œœÜƒ-ZÔÔÔtêÔ) ÐÐШ¨(âS]]]â¾s&“©¡¡áèèHä¦äÞ]ûëñýû÷Äcavvvû÷ï¿sçß+µ***k×®å|'44ÔÖÖ¶¼¼üÞ½{ÒÒÒÓ¦M»víšœœ\÷ûá+7ü?ÇÛÚÚˆ ;´zõê‘#G~麯—ãìTòõ%f2™G%¿Ù‰ŒŒ433~H{{ûĉ'Ož|ôèQ%%¥ÜÜ\b¾„P\\ܼyó6oÞ|êÔ)iié3gÎÌœ9ó÷ß}â›Í›7755åääìÛ·oäÈ‘÷îÝã»Ò^™™™‚>ÒÔÔò¸ç’ÊÊÊä}5$â¯G¾Çr­/< ¾;¬\¹råÊ•ä˵k×r%µ S¤Bûöí2dFÓÖÖÞ¹s'ñAYY™»»;N×ÕÕ]±bï‚ÅþþþYYYþþþúúúÄJôùùùl6›J¥Ž5м!´wï^ƒ¡¨¨h``@,*Ë{,'Þý êêêä„ÉÉÉÄ5<¾EñDP‹˜Læºuë™Lfrr2ßÚyk úô)Bè矶³³#ƒ|øð¡²²r}}ý§OŸüüüL§ÓçÎ[UUÅÛûEEE&LPRR²°°HNNÞ¼1ê(Ndœ‚N4‰÷SÞEìCAmÔ^¾3™Ì7Ž3ÆÂ‚kDq¥ÜÝÝ“’’ˆYWÊÊÊ=<<ˆ"""lmmÉ=UTTJKK‹‹‹—/_®¥¥E¥R----Z„jkk[±bÅòå˃‚‚´µµ555—/_¾fÍš•+W655ñ­†a EAAÁÊÊŠXæ ((HHs:uê_¾|IL‘íàà@|_&dÞ“.ʸÄ/++KII)''ÇñÊÊJrá;;;OOÏÚÚÚÒÒR›¥K—ò®‹0bĈ˜˜b›Á`0Œ´´´úúúE‹3†ÜíÌ™3oÞ¼iooOMMUSS‹ç:– ßýqWSS#žœÅq<))‰\H‰«(A‘jƒÁ°°° ¾AR;W-ÖÖÖÄËòòr¢q÷õõ]¸p!ñeÜÌ™3+++ëëë.\8mÚ4Þ–ÚÚÚz{{þüùõë׿ææd‹DŒAÐnœÈ8h‚ O¹j±µ]P{ùÌ`0X,Vuu5Žã¡¡¡œ#ŠS‡Àf³ÃÂÂ/^Šãø¶mÛ|||víÚåàà€ãø‡äää233‰½½½—,Y‚ãx[[›©©)›Í>}útaa!YZZZB(==³ŠW¯^!„>|HTG,»"ï¿ÿþ»¬¬l[[›æˆxê †žžÞóç域 ˆ5‡øîÏ÷¤‹2nû(I[«ï‚Õ¹À—#âê\_-X‹ÊÍÍ¥R©qqqµµµä»Äü—UUUÄËëׯS©Ôööv®ƒ¹RX²%Ïž=£Ñh|ë ð÷÷Ç…¦°|÷Ç;“ÂòF"¤Eœû ©]P ‹ãøÔ©SCBBpohhPVV¾ÿ~~~>†aåååÄUUU†ÕÕÕqža؇ˆ—ÇŽã›Ò ‰AÐnœÈ8ùžh’ O9k±µ]Äör¦°GŽ!Þ|þü¹ Õa')ljjª¡¡a[[›‘‘Qrr2™Ââ8>oÞ¼•+Wâ8^[[K£ÑÈôýýû÷kÖ¬±²²¢P(¦¦¦ýõŽã7oÞDUTTpVQ__"î)ìB KÜJûñãG!ÍñÔ3Œ°°0b»¥¥eàÀ7oÞ´?ïIeÜö]ÂöHaÁ—)¬pÂr’211‰ŠŠŠˆˆÐÔÔd³Ù‰‰‰¡ââbeeerÁ_CCÃúúúgŒ×ÑÑ!6h4Z]]ù~||¼“““žžÞ!C¢¢¢***„—ÓÙýE‰Dx‹´µµ»S»——׉'ÚÛÛÏŸ?¯®®îääTPP€aبQ£ôõõõõõ­¬¬”••KJJ8*..VSSSUU%^r®É!b •ï‰ñS2`QúPPÛ…´WuuubC^^žsDu¡X,FÛ¸q£¼¼<ç!__ßèèè–––ØØXCCCrùG:öôéÓêêê… Ι3'++‹‰¸'D¼$ž§é‚ââbEEEÑ›#d7r6 …2xð`bÔñÝŸ÷¤‹2nàËQWW7nœŒŒŒ¸‘Pªªªß~û-×Â`_-)„‡‡ÇÝ»w+++ÝÜÜf̘ÒÕÕ­©©!³“‚‚*•J&ÿ°TÇ”••yxxlݺµ°°°°°ÐÇÇÇq!Ç Ú!D£Ñ‰mλªE Cx‹ÈéÁ…Ô.¤–I“&566Þ¾}û?þøþûïBzzz†eddüWuu5×<:::?~$o $W›1!» Â{¢;ü”³FûPPÛµ·;:Õ >>>Û¶mã½÷šÍf«¨¨\ºt騱c¼Ÿ"„h4Z`` …BÉÈȰ°°ÐÑÑ‰ŽŽæÜ!::Z[[»ËO¡ÅÄİÙl))©9õ………ÄFkkkqq±ŽŽŽý¹Nº(ã¾]]Ý7n$&&ò®ÐJJJž={–œœ¬¦¦&îX$‚TvvöíÛ·›ššäååét:ñ§©©éèÑ£êêêÊÊÊÖ¯_ïååŻ⼖–çÃ}|ÕÖÖJIIYXX`VRRBN $èXAû#„X,ñ•kCCCDDD§Â±EBjR‹ŒŒÌܹsÃÃÃoÞ¼I¤°FFFãÇ÷õõ%µòòò¸¸8®£˜LæÈ‘#÷íÛ‡jll$[$b Bvã‹ï‰îðSÎEìCAmÔÞîèT'x{{'$$ðMR}||6oÞüäÉOOOâwïÞ¦¥¥}þü¹ªªŠ¸–ÅbIKKïß¿?"""<<¼¬¬¬¼¼<""bÇŽû÷ï'çahkkkäÀ[Žã­­­õõõiiiÞÞÞ?&±ê‘SøðáìììÖÖÖÐÐPEEE'''Aûóžt!ã6&&æøñãžèuuõ!C†ÔÖÖæææŠ;‰C<ëlmmÍû›÷ë$ÕÐÐL§ÓÕÔÔŽ?‹Â0ììÙ³µµµ,‹ÅbíÚµ‹÷à   “'Oª¨¨Ìž=[P¦¦¦ëׯ···wtt\ºtéøñã…+h„PxxøãLJ æææFÎâ&b"¶HHíÂkñòòºqㆃƒqŸ B(&&FSSsôèÑŠŠŠööö=â=*66öÖ­[VVVnnnäšu"Æ d7¾øžè?å¬QÄ>Òv¾ííŽNuFsss#¾¯çòÃ?deeM:•¼M‚J¥ÖÔÔxxxhhh˜˜˜$$$\¸pX:eæÌ™—.]º|ù²±±±¦¦fPPÐ¥K—fÍšE–¶cÇy¼·@lß¾]FFFMMÍÝÝB¡üóÏ?ÄŒZ=rê}||¾ÿþ{55µ„„„‹/ÊÊÊ ÚŸïItî._¾ 3Îzñÿá“'OĈÄ!RX+++q"1zä>\ú´ÖÖV:žÐÙ‹ŠŠôôôV­Zõ%¢= çê)ð8ø¢vïÞ6lœNÄ’¹¡óçÏ‹;—ǹĖ; 1"##UUU»paXWW÷æÍ›4­¨¨èK_›ü‘Á`dddlÙ²EܱHeË–•——»¹¹ýë_ÿw,’Vç_;UUU…S§Nuíî"⢀—ŠŠrrrÚ±cÇôéÓaåB„Ðùóçÿúë/%%¥ÈÈH¸–WaÁ×®ººº¸¸ØÙÙYÜ@!;;»€€€¶¶6GGÇ;w¶µµ‰;"±©¯¯ÿ÷¿ÿML´k×®!C†ˆ;" ),$ËÖ­[/^ÜÔÔ´fÍš¡C‡^»víkKd[ZZâããMLLöïß/%%µoß>bs@‚ à‹pttw_Dqq±¸CýŸœœÜáÇgÍšåãã“““3qâD ÃÌÌÌœÉ û«¢¢¢ŒŒŒüü|âåˆ#Ž?nii)Þ¨$P? .ÉÉÉâá ÊËË»uë–«««¸ý™››[vvvpppbbbZZZVV–¢¢bJJЏãú²ŒŒŒòóó)Š‹‹Ë–-[¤¥¥Å”$‚zØÃ‡ñŽVËëAiii‡>|øp¯Õˆ*((X¸p¡¾¾þ–-[àVrðåÈÉÉkâ´µµ¥¥¥•””ôò 0{öìY¹reo>D5xð`###sssxrK8Ha ‡ÙØØôfuÍÍÍJJJ¶¶¶½Y©­­í¬Y³Nž`R-‰),ñÐÓÓûí·ß?~\XXhjjº}ûöºº:qÀÿ€«° RXâd``pìØ±deeïÞ½»¾¾^ÜAðÂJ,HaˆŸ‰‰IttôíÛ·SSS÷ïßߨØ(î €VrA @R˜››Ÿ9sæÚµkwïÞ5119tèPss³¸ƒ_5˜VbA @² >üܹsñññW®\155ŒŒliiwPà+Wa%¤°$‘µµõ¥K—NŸ>kfföÇ´µµ‰;(ðÕVbA @r=úúõëQQQÇ:tè©S§`†#Л`R-‰),IçäätçÎC‡:thøðágÏž… c wÀUX‰),€¾aìØ±<سgÏ®]»FŽyþüyÈ-À—)¬Ä‚@_2a„äää­[·nÞ¼ÙÆÆæêÕ«âŽôgÂJ,Haô1†ýë_ÿzúôipppPP½½ýÍ›7ÅèŸ`R-‰),€> ð3f¤¥¥-_¾ÜßߟÍfß»wOÜAþ®ÂJ,HaôaRRR³gÏÎÌÌôñññññ7n\RR’¸ƒý¤° RX}ž´´ôüùó_¾|9gΜ¹sç~ûí·Ož<wP ?€VbA  Ÿ P( ,ÈÉÉ™2eÊŒ3¦Nš––&î @ßóÂJ,Haô+²²²K–,ÉËËsss›4i’»»û‹/Äè«à*¬Ä‚@?4`ÀÿW¯^=ÚÍÍmîܹ999â ô=ÂJ,Haô[òòò«V­ÊËË>|¸³³³——×ëׯÅèK`R-‰),€~ŽF£­Y³&//ÏÈÈÈÎÎÎ××·°°PÜA¾®ÂJ,Ha|”””Ö¯_Ÿ““£¥¥Åb±~üñÇ’’q$¤° RX_UUÕ­[·fgg+))1¢µµU܉)¬Ä‚ÀWGMMmÇŽYYYÄË5kÖTTTˆ7$ ™`R-‰),€¯N§P(¡ÆÆF33³µk×~øðAÜAÉWa%¤°¾v?ÿüó³gϪªª ƦM›jjjÄÂJ,Ha4xðàÇ?~üøíÛ·&&&Û¶m«­­wP@ü`R-‰),ðÇŽ{øðavv¶‰‰É®]»êëëÅ'¸ +± …þ‡‰‰É‰'îܹóäÉccãŸþ¹±±QÜAñ€VbA ðaffvæÌ™ëׯ߿ßÄÄäСCMMMâ ô6Ha%¤°€@Æ ûûï¿ÏŸ?õêUƒqäÈ‘––qzLª%± …:`eeuñâÅ3gΜ={–Éd?~ÖDøJÀUX‰), [[ÛëׯÿñÇþùçСCO:×çú=Ha%¤°@'8::Þ¾}ûðáÿþúë°aÃbcc!ÅéÇ`R-‰),ÐicÆŒILLÜ»wïž={FŽyþüyHtú%¸ +± …ºh„ ÉÉÉ¡¡¡[¶l±±±¹r劸#= RX‰),Ð-“'O~òäIppðš5kìííoܸ!îˆ@VbA t†a3fÌHKK[±bÅŠ+Ølö½{÷Äè0©–Ä‚èRRRß}÷]FF†¯¯¯¯¯¯››Û£GÄè¸ +± …z’´´´§§gVVÖܹs==='Nœ˜šš*î @A +± …z…BY°`Avvö´iÓfÍš5uêÔ´´4q: &Õ’XÂ_Ь¬ìâÅ‹sssÇ7yòäY³feffŠ;(Ð pVbA |Y X¶lY^^ž½½ý¸qãæÎ›““#î €H …•X½A^^~åÊ•¯^½1b„³³ó?üðúõkq:)¬Ä‚è= AAAyyyÆÆÆvvv>>>………â “jI,Ha€Þ¦¤¤´~ýúÜÜ\mmm‹õã?‹;(À\…•XÿIa]\\0 ;wîùÁ… 0 stt~<‹Å:}ú4±miiIns}Ôá±¢ ‚Ä0LQQÑÞÞþîÝ»¢Û5dT*ÕÔÔtÑ¢Eyyy\ŸrÎù§®®~éÒ%b;33sÒ¤Iêêê L&3$$„·üÎö«Ÿ\}Åd2ãããÅOg ‚ˆ8Bú\oÐÿ¨¨¨lÙ²%;;[YYÙÒÒrÅŠïÞ½wPà@ +±þÿ*,“Éïn_¢‹@?#|ú55µ°°°¬¬, …baaXQQ!î ÀÀ¤ZëÿSXww÷¤¤¤ÒÒR„PYYYbb¢‡‡ù©ººúƒˆíääd®‚üýý³²²üýýõõõ.\ˆ '~×2™Ìàà`ggç‘#G:::feeñÆñéÓ'??¿ÁƒÓéô¹sçVUUñ Ã0 …2pàÀU«VÕÖÖæä䔕•¹»»Óét]]Ý+V444 „Μ93bÄâüQVVöóçÏ¡¨¨({{{!Õ1™ÌuëÖ9::2™Ìääd²F++«?ÿü“Åb‘ñ,^¼8//ïï¿ÿ抳´´´¸¸xùòåZZZT*ÕÒÒrÑ¢E¼Í!»ˆ¨zãÆcÆŒ±°°5jÔ‹/ˆ÷÷íÛ7dȦ­­½sçNÞ~Þ»w/ƒÁPTT400رcY¸ ?~üèçç§§§§¤¤dmmýêÕ+!ÂU;oø–ÖÙ8 i¼‘t8fxû !”ŸŸÏf³©T*g¢ ?¾]!¤¥»wïvpp——wrr*++Û¶mN§Óé½R$tò­]ô‚zùò¥¢¢¢ƒƒùƒ)hÿ.œ€èètúž={222šššÌÌÌBBB>|ø î \…•\ÿŸÂR©Tww÷¨¨(„PTTÔ¬Y³h4šè8pÀÜÜüÀœWs .\8þü³gϼ½½'OžÜÜÜ̵üyó***ÒÒÒ ©Tªºp‰‰‘••544œ9s¦œœ\~~~jjjrr2qMtìØ±™™™•••¡[·n 2$11‘Øvuu^ÝùóçÏŸ?Ÿ““Ã{†aóæÍKLL$ïìVTTܰaCpp0qÉ–¤­­mjjêççwæÌ™·oߊ؇W®\9wî\ffæ´iÓüýýB/_¾Ü´iÓ7êêê222\]]yûYWW÷úõëŸ>}ŠÝ½{÷ùóç…ˆš3gNqqqJJÊÇ£¢¢ˆ³Ì·Cxkç™oi ©C|#épÌð“¿ÿþ{DDDUU•••@‡E ê !-=vìØ‘#GÊËË©Tª³³ssssAAÁéÓ§úé'⎷Ny×ä[{§FÈáÇ=ZYYÉf³ÉL¾ûwí:kРAÏž=ûðáƒÁظqcMM¸ƒúªA +¹pÇqœÍf‡……¥¦¦¶µµ%''ïÚµËÁÁØAMM-11‘ØNJJRVV&¶­­­cbbˆí#FÛœ1ŒŸþ™x³½½]SSóæÍ›œ;äççcV^^NìSUU…aX]]þ¿Øl¶‚‚‚¦¦¦‚‚Â!Cþúë¯ììl„PUU±ÃõëשTj{{;ŽãÇ?sæLQQ‘ŽŽNxxøO?ý„ãø Aƒîܹ#¤:ƒqðàAÎ×®]ËÕ+WB?~$;­¹¹ÙÄÄä—_~!zéâŋĞïß¿_³f••…B155ý믿pœ½Ç`0Ž9Bl?þœF£á8ž››K¥RãââjkkÉ£¸ú™S@@€¿¿¿‰ \Þ¿Ïy” á[;'¾¥u6$.|Go$"Ž®¾â<¿Ïž=#¥¨»‚·¥ÄÀqüøñãjjjmmmÄK&“yéÒ%ÑǼ(¨vÑGHXX±ÝÒÒ2pà@â“ïþ]>’céÒ¥!ò¼ô'÷ïßwvvw}Õ€BMMMâ„7oÞ,X°@CC#44ôÓ§Oâç+5qâÄ«W¯Š; ‰³lÙ2„gÊÔóçÏG8q¢SGýÏŒ,‹F£mܸQ^^ÞÖÖ¶e---bÃ0--­’’ÎO 0 5j”¾¾¾¾¾¾•••²²2×>__ß´´´÷ï߸»»+++8øÔÐа¾¾¾ºº!äêêzûöí›7oººººººÞ¼yóåË—?~´³³^¶¶¶†ËÈÈ(**’ïÈÈÈ„……mÞ¼¹¶¶–sO:öôéÓêêê… Ι3‡ïœÔÕÕ‰ yyùºº:„‰‰ITTTDD„¦¦&›Í&®%s‰wrrÒÓÓ2dHTTçT¼())ÑétÎuH‡µó-­³!‰‚7ÑÇ bƒF£‘}ÒaQ‚ºBHKɤ   ¥¥%%%E¾¬­­írüœ#PH휄ìf``@lP(”ÁƒðÝ¿O@DúúúG}ôèQNNމ‰Ixx8qSèM0©–Ä¢p½öññY±bÅÞ½{¹Þ§ÑhÄ6ñ=/ò—4/röæ–––·oß’iAOOðŒŒ ÎÔ/" _êêêÖÔÔTWW«ªª"„ ¨T*±íêêúïÿûóçÏãÆ³´´,..>s挣£ã€„W‡a˜bbbØl6WKgΜ¹gÏžððp¾‡Ðh´ÀÀÀ 6ddd˜›› o /†††Ý»wϘ1£¢¢‚³ö²²2„„6›aX```QQ‘Ò† òéÓ§ŠŠ òM!Â[{‡¥u6$.‚FW$ÉÉÉ¢Œ!c’$âðãíŠî´Tô1Ï…Bj}„³Q¶¶¶ëèèÙ¿k§ÐMÆÆÆþùçË—/7oÞlbb²zõêÅ‹ËËË‹;®¯ÜH ±¸Á{{{'$$ϾX,ñ fCCCDDß²´´´­˜÷Ûo¿eeeµ´´lÚ´IYYÙÉɉóS##£ñãÇûúú“‰”——ÇÅʼn½©©éèÑ£êêêÊÊÊÖ¯_ïååEä ÎÎÎ.\puu•’’b³Ùûöí#nàëTu8Ž·¶¶Ö××§¥¥y{{?~ü˜ë®]»öíÛW__O¼|÷î]```ZZÚçÏŸ«ªªBCCqg±X¢4ŠSvvöíÛ·›ššäååétºŒŒ úß~®­­•’’²°°À0¬¤¤¤Ã©”8ÛÞÞÞþüùówïÞ ê¾µwXZgCâÂw¤ñF"âI2&ù¶BPQ|»¢;-} Bj}„>|8;;»µµ544TQQÑÉÉIÐþ:›6m²´´½7233;}úôõë׉»×šššÄÔWRX‰ÅÂÒh4777ÞË*ááá?6l˜››Û˜1cø–tòäI•Ù³gs}´dÉ///55µ;wî\¼xQVV–k‡˜˜MMÍÑ£Gs¾rN¶*†agÏž­­­500`±X,k×®]ÄGŠŠŠ666ZZZÄ_WW×OŸ>;¶³Õmß¾]FFFMMÍÝÝB¡üóÏ?|§Árpp?~<1BˆJ¥ÖÔÔxxxhhh˜˜˜$$$\¸pÁÈÈH”Fqjhh¦ÓéjjjÇEÿÛϦ¦¦ëׯ···wtt\ºtéøñã;,óôéÓÖÖÖ*** , ¾LçÛ!|kï°´.„ĉïHã‰('QȘäÔaQ|èfKE„‚F ÚE!>>>ßÿ½ššZBBñƒ)hÿN‚·oß:;;wª7¢6lX\\Ü… ®]»fjjúûï¿·´´ˆ;¨~&Õ’\=r®p ãܹs½P@˜™™½{÷NÜQpƒÇ¹_’ü8—p)))&L044ŒŠŠjiiw8ýÖÔ©SÏŸ?/î($ŽÄ=ÎÝ—••¥©©)î(èçlll®]»ö矞8qbèС'OžlkkwPýÜH ± …ú*‡[·n>|øðáÃÇ…Çç{¤°«7RØìììiÓ¦õBEÀWh̘1‰‰‰ûöíÛ³gÏÈ‘#ããã!ëê)0©–Ä‚«°@0~üøäääíÛ·oݺuÔ¨Q—/_wDý\…•XÂýǤI“žŽ¬¬,%%¥œœÇ+++SSSy—F°¶¶Ž‰‰Áq|ĈĆ}:,Á`XXXTVV/'Ož>>äÙòðð¸{÷nee¥››ÛŒ3„$%Ò“aˆa±¡§§‡aXFFFÁUWW›šš ŠVGGçãÇä}œïÞ½#6¼¼¼ˆlxœEWW·¦¦†L ¨T*ùëS86›­¢¢réÒ¥cÇŽñÞòÛe‚Z*hŸmÛ¶ñÐax4-00B¡dddXXXèèèDGGsî­­­=räÈcÔÛBÆç²B¨°°Øhmm-..ÖÑÑ}ˆŠÒ™C† ùôéWš%<$áD<–+Tч"o‡ˆ>f:ü">%.¯"„ZZZÞ¾}Kþ¡Å¥³]ÇyÒ h,z‚‚BPPP^^ž©©©½½½OAA¸ƒ’,ÂJ,)„Pmm­”””……†a%%%ä$8ÙÙÙ·oßnjj’——§Óé222B ÒÒÒÊÉÉ^Y§ 422?~¼¯¯/ñ+­¼¼<..NH´L&säÈ‘ûöíC566FDDð-ÖÔÔtôèÑuuueeeëׯ÷òò"ÍwÈÇÇgóæÍOž<ñôôDÅÄÄ?~\Äc;ÛRA¼½½ø&©\á!„Þ½{˜––öùó窪*â>Z‹%--½ÿþˆˆˆððð²²²òòòˆˆˆ;vìß¿Ÿ¸\jkkkäÀY‘ ÞtvÐÿŽ!»!„>œÝÚÚª¨¨èää$ú¥39÷iooþüù»w$œ(Çò†*úPäíÎŽÔÑ0ûí·ß²²²ZZZ6mÚ¤¬¬ìääÔa!¢tçI€ˆ?¹€/GQQqݺu¹¹¹:::£Fòóó+..wP’&Õ’XR!SSÓõë×ÛÛÛ;::.]ºtüøñÄg ÁÁÁt:]MMíøñã±±±B :yò¤ŠŠÊìÙ³íÓ©B111ššš£GVTT´··ôè‘hB±±±·nݲ²²rsssssã[&†agÏž­­­500`±X,k×®]ÂÃàôÃ?deeM:•øþ÷òåË=2g'ß– B£ÑÜÜÜ; !D¥Rkjj<<<444LLL.\¸`dd„š9sæ¥K—._¾lll¬©©téÒ¥Y³f‘¥íرCž×è|{[ÈÙá!BvCùøø|ÿý÷jjj /^”••íÔ¥3OŸ>­¡¡amm­¢¢²`Á‚ºº:á! 'ʱ¼¡Š>y;DÄfrrÈ’%K¼¼¼ÔÔÔîܹCVÁW§ºŽë¿Aˆò“ øÒTTT6oÞœ­¢¢bii¹bÅŠ²²2q%~pVrõÈ}¸_ÖÖV:ž î@øërxEEEzzz«V­úQ Ç`0Î;'î(¾8xœ ðõÕ>Î%Üû÷ïW­Z¥¦¦¶jÕ*áOpö{ÞÞÞQQQâŽBâHÂã\ñ&Ð}Ndd¤ªªªÄ^(êrxººº7oÞÝØØ¸—C|A €èëëGFF>zô(77×ÄÄ$<<üóçÏâê‹ P(;wî¤Ñh¼ÉÈÈlÛ¶­÷C|A ‘ÿùçŸwïÞ}ö왉‰É¾}ûÄTÏ›;w®²²2×›ÒÒÒãÇg0b ð‚Àd2cbb?ÞØØxÆ Ÿ?¾uë–¬¬lQQŽãjjj‰‰‰ÄþIIIÊÊÊ͵µ5YWÕäG ÃÜÜüÇ8ŽGFF«§ûLž>^H8ŽóÍ7“'O.--mkkKOO/++-ßÚ¹,\¸\7KЩa0•••ÂrR¸JàêƒÁ`0ÒÒÒêëë-ZD¶TÐ)×G‚J°µµõööþüùóëׯÍÍÍÉ8…ÄÏ÷\)ªû§õÇrrr™™™ÄÞÞÞK–,ám2°:à VçêqwîÜqrr233;sæL[[›¸Ãé–¿þú‹F£ÉÉÉ¥§§‹;É"¡«såää$%%]ºt‰F£Ñh´­[·NŸ>ýÀ¼æ/[¶ÌÜÜ!4wîÜU«VmܸQJJjìØ±†††éé麺ºÝL¯-ZD܉²`Á‚µk×&&&ººº’Ÿ¾yóæòåËïß¿'Ö WWWÿüù³‚‚‚2/^L\·›2e qáB¡´¶¶fffjkk«©©ñ]}ÄÃÃØ`±Xßÿý­[·¦N*¨Àüüük×®½ÿžN§#„†.$ZQj' ?5K–,éæÒ)ÂKð÷÷1bBÈÏÏÏÉÉIH£ˆS ¤4ò#A%?~üøêÕ«T*ÕÐÐð§Ÿ~ è0~ÞsÊÉÉTT÷O+BhæÌ™ÇŽÛ³gO]]]llì;w:Œú1—û÷ï߸qcÆ Û¶mÛ´iÓ´iÓ­¹S\\üèÑ#òã^ÖÒÒR^^^YYYZZZWWWSSSUUÕÜÜÜÐÐPWW×ÞÞÞÚÚŠa˜††Æ¯¿þ*##C¡PäåååååeeeÕÕÕ•••ttt444444¤¥¥ÅÒŠ¯Ÿ¶¸¸XYYyàÀÄKCCÃúúúêêjò’¶¶6±¡   ¥¥%%%E¾ì‘yµ´´ˆ ô´´JJJ8?-((À0lÔ¨Qä;ÊÊÊÄÄËBÊ$¾@ÉËË×ÕÕ!„LLL¢¢¢"""æÏŸÏb±BCC‰üŒS||üž={ 1 ûôéÓ7ß|#¤À‚‚%%%"Ñ%Úk' ?5äéè2á%èèè4l©S ¤4ò#A%«©©‘·Ò›˜˜ˆ?ï¹@ )ªû§!äëëëáá±cÇŽØØXCCC‹%J¨Ð¿7nܸq—/_Þ¸qchhè–-[&MšÄ»ÛêÕ«Ï;gmmmddôå‚Áq|Xø>†ikkkkkkhh˜››[XXhkk3 ==½žhàã?),™}"„tuukjjª««‰ßúT*•ó¹<ÑÑh´ÆÆFb»²²’ï>œUsyýú5±ÑÒÒòöí[2…"èééa–‘‘¡¨¨Ø…Ø8yxxxxx444ìÞ½{ÆŒœQ•••yxx$$$°Ùl Ã‹ŠŠ„”6dÈOŸ>UTTp.ï!$ZÞÚ•,üÔˆ¸®¬“ÂY‚ó"J£„ÇC~$¨„ööö?655ßñ½{÷N”øùÒÑÑá[TœV„›ÍVQQ¹téÒ±cÇÈû† „&Mšôí·ßž?>$$dëÖ­[¶l?~<ùi^^^|||KKËäÉ“ÓÓÓeee{ªÞæææ¼|ù2%%%99ùÕ«W8Žóî&##C\@ÕÕÕ¥R©ÊÊÊêêê²²²òòò4MJJJZZšB¡à8ÞÖÖÖÚÚÚÒÒB\ mhh¨©©©¬¬¬­­­¨¨())©®®.))!®µ]¹r…¬BAAÁÜÜ|øðá,kذa¶¶¶ Ÿ«‡  þÓZZZ999Ķ©©éèÑ£>>›7oÎÉÉ9þ|LLLSS“———èý†aÓ¦M›2eÊÙ³g¸eË–1cÆ „Ö¬YÓÒÒÒÖÖööíÛÿû߇êNE/_¾LJJzøðazz:ù7ƒžž“É$þ500ÐÐÐ066ÖÒÒêZzà Çñ’’’üüüwïÞ½yó&777???''§¬¬,55555õèÑ£D$,kÔ¨QŽŽŽÎÎÎ\׿@§üçJ[PPÐÉ“'UTTfÏžaØÙ³gkkk X,‹ÅÚµkW×Jüøñ°aÃÜÜ܈ñÊ‹³j®–,Yâå奦¦vç΋/òþ}£©©9zôhEEE{{ûGu!Ȇ††àà`:®¦¦vüøñØØX®¨LMMׯ_oooïèè¸téRο 9}ú´†††µµµŠŠÊ‚ ˆo¢ùFË·vAzäÔˆrRÐó©û§@P ±±±·nݲ²²rsssssëlüœøÕS§!ôÃ?deeM:uàÀ—/_㺠™¤¤¤<<<ž?¾dÉ’%K–¸ººž:uêêÕ«Ä \õõõüñÇ¥K—:[lccã‘#G,X0pà@ssó… ;vìéÓ§ ÅÎÎnÙ²eGŽIII©««+,,¼~ýú‘#GV­Z5cÆ ''§AƒõTþŠÂ0LWW×ÙÙÙÃÃ#((èèÑ£wîÜ)--­©©ILLüå—_üüüFމaXjjê¡C‡æÎ«««Ëd2—.]ÕŸ¦Ôí==ò(Ù—À`0Î;'î(èXkk+NOHHw @˜‘ð3ô¾–––¨¨¨r=ÿ¤¤¤DLgÔ¡òòò={öL™2…3ÕÔÔtwwß¿ÿ³gÏÚÛÛ¿t+º†˜gçÎnnnœÍ—––ž9sæáÇ?~ü(îE"¡3:%22RUU•óR1A(еµucc#×ܱõõõÓ¦MKIIôhUUÕÉ“'OŸ>””D¼#--=vìXWW׉'6¬¯ª~!Ä,kõêÕD:{ãÆ«W¯&%%ÅÅÅÅÅÅùùù±Ùìùóç{xxp­p ¸@ @·¨ªª*((œ:uJòÿë ñÓO?555q½ÙÚÚš½nÝ:®u°ÚÚÚ®]»väȑ˗/7P©Ô©S§zxxüë_ÿê»SYIIIÙÚÚÚÚÚ®[·®¥¥åï¿ÿ>yòäõë×ïÞ½{÷îÝeË–Íš5Ë×××ÑÑ~¿ð%¹)lvv¶¸C cÕÕÕâú’þùçÁƒ|—ïúüùsDDÄ„ \\\B?~ŒŒŒ½±±QÜAõHa Oâ½ —`AŸðáÛ¤¤$]]ݬ¬¬•+WŠ;¢>LJJjãÆ.\‘‘9þ<›Í®¯¯wP½RXè“x/ÄÂ%X ùrssÍÌÌ^½zeee•ššú5?P߃&Ožœ‘‘¡¯¯ÿøñcKKËòòrqGÔ …€¾ŠóB,\‚’ïõë×cÆŒ)//;vì½{÷´´´ÄQÿÁ`0=zdaa‘——çêêZUU%8Ha ¯â¼ —`„«©©qss+--µ¶¶¾|ù2¬/Õã t÷î]ƒÌÌÌ &pÍ»×ÿ@ }XHH†a²²²p H2ǧL™RPP`mmýðáCAS‰ÈÂÂû/…aÆÓÊö22 uuu{{ûˆˆb]\Îdddrss‰w1 #þÚ,++óòòÒÕÕ•••UWW·³³‹ŒŒìfHjjjiiiúúúOŸ>ýᇺYš„ƒ¥  Ï(((¨¨¨(//ÿþýçÏŸëëëkkk‡þäÉ …²uëVeeeEEE:®§§§¯¯³I°~ýúû÷ïkkk_¾|yÀ€=R¦¾¾þСC‹ŠŠž?¾|ùòööö+VôHÉjoookk#¶555utt ’’’’’’Ξ={ýúuyyyrçÖÖÖààุ8®B¾ûî»ÄÄDuuu—ššš/^ܽ{×Çǧ›±)))]¹rÅÆÆæôéÓãÆ[°`A7 ”\8|–.]Šúå—_Ĉ¨ÚÛÛSRR¢¢¢V®\9aÂccc úðŸüÀY,Ö´iÓvìØqçÎææfq·L²éTSS“¸éÏ’““BÒÒÒ‰‰‰=RàСCBK—.%^«!8;;ã8^^^¾dÉyyy33³íÛ·'÷àÁƒ!dz³³BÊÊÊmmmmmmªªª¡””Ç+**–.]jhhH¥RGŒMVª¦¦† =z4…B¹}û6gmmmä•à-[¶pÆIüùèÑ#ÇBk×®mhh ~¢322ˆ›ššrss{¤pŽŽF)((”––öT™œ–-[†:xð`”6þ|„Љ':u\…IÑÞÞžœœ|ñâÅ”””p~#I0448p N4h•JUPPPTTÄ0 Çq Ã?þüéÓ§?–———––¾~ýúÇ>|xòäI||êk‹µbÅŠsçÎݾ}›Íf_¹r¥ÿþ>>>S¦L‰‰‰ùúë¯ÍÍÍ +**rss¯\¹2lذòòòË—/S—B=<€w$—Ë©ä*•J9Žb§ÆÂjjj2äÓO?577ŒŒ$„ôë×z´ÑÊÊŠªááÇ"‘èƒ>8zôè•+WÒÓÓ'OžœM]Ž%„P×hX)•JOž<Þ·oߎNNNyyywïÞÍÌÌŒMNN÷óó2dÈ»¾5„BtuuW¬X±qãF©Tšœœ¬6{DX\ºtéË/¿LKK£¾µ¶¶ž={¶ŸŸŸ‰‰‰Rûe0666666---¿üòˉ'NŸ>MeÙÏ?ÿ|éÒ¥K—.¥F¼£ŸþùîÝ»ÆÆÆŸ|ò‰ÂŸ4i5µu3¡¦¦¦ªªJ$PÛŒŒ!T„=vìØƒÜÝÝy<ÞáÇ©¨K®©©Çb±¨577w|MyÝßx2™ì›o¾¹xñ"!dêÔ©/ýÔØØxÉ’%;vìè|#%::zÆŒb±X,5ÊÔÔ”R[[«¨KY¾|ùŽ;Ο?_^^®Àf{<© Э \\\<==ÓÒÒúôé\XX˜ŸŸ¦ìüú‡3qâÄèèèÊÊÊèèh''§ÚÚÚˆˆˆÁƒoÞ¼¹W-¶JC 윕gâĉC‡mkksss[¸p!õ0þ¬Y³D"ù+§BÜÜÜÜÝÝŸŸommÝÞÞÞ12Xm Â(WxxøÒ¥KÛÛÛwìØ‘••EÝÊìá˜LæŠ+nܸall|ãÆ ggçŽ2Þн{÷!ÔSJ@£¡C‡BÊËËé.DÁa”hÆ Û¶mc±Xqqq+W®|»¶èbffVRRâîî^QQáááQ[[KwE J¨©âôôôè.¤·£&©««£»C„P–øøø/¿ü’Á`ÄÅŽ:ÏŽJàñxçÏŸ=zôãÇÇŒÓØØHwE 2¨u:ºg.è›Í&„(džé@)þøã€€¹\9yòdºËy{\.÷ìÙ³‰$//¯ó²™]ÓÖÖ&„<{öŒîBz;êŸà-ÖöëáÔíõôáááOŸ>õöö¦f‹Ti:::'Ožd±X»wï.--¥»P Ô‚÷ïß§»ÞŽ”¬~‹H#Â(^EEELL “É|iõ waeeÅ`0 †††F¿~ýFÕÚÚúê ƒÏç[YYu¬ ÿîÞ{ï½Ï>ûL&“íܹSQm‚z£&ÕÒÒ2 ÀÞÞ¾   $$¤cøw·bÅ BHLLL[[›¢Ú5fooÏápnÞ¼Ù þãyÑkååå=}úÔÄÄ„Z¢L Â(^ZZù»¥ÒßÝŒ3®_¿^]]½gÏBHzzúK—E===<˜––F }+**RT׉ÄÊʪ¾¾>''GQm‚ãñxò¿ÖèRª.΋€€€Áƒ .—kiiùí·ßB¬¬¬ÎŸ?OÙ¼y3ƒÁ°µµ}Ýž•••yxx;;»¬¬¬.Ú§|ýõׯ ãñx:::666Ôr»555!!!¦¦¦ššš¶¶¶ÔFå‰'„L˜0A©½Ð@ñ¨YTíìì”Ô>“É 3f ùëWT‡K—.7N&“z{{+°_êaŽXxC~~~„ƒvOw{^ܺuËÓÓ3<<|Þ¼y%%%‹/¾|ùòœ9s¨;$Ë–-›={öëöìÜ~xx¸H$’H$ÿûßÿÆ_SSÓÅQ999+W®¬¯¯_³fMppð AƒÊÊÊZZZ\]]÷íÛg``ZSSãïïäÈ%½!mmmTãݶÆowbÓ]€úóÏ? !ÔŠ²Ê#‘HÒÒÒ*++;o,((èX†gРAr¹\=êééžÞØIDAT1 õ{´”ÄÏÏoåÊ•¿þúkvv¶££c÷túÒyqåÊ'“Éÿý÷”””ŸþY*•^¼xñþýû^^^R©´‹=ÝÝÝ;Z ‹ˆˆhnn666®ªª:uêTPPÐ뎢æàóùC† ‘H$ëÖ­ãóù§OŸ...±±±ÀÐÐ000pË–-óæÍSÆ[qüøñßÿÝÒÒ²ó«PøP/d2YDD„‘‘‘†††––VJJ !䥿ú(o²§µµ5!„Ëå6ŒòàÁƒ.Žòôôœ7oÞƒæÎëä䤯¯¿oß>j­æ†††Áƒ …ÂÀÀ@BuuVáïU!$44TµUyCˆ°Š'‹É_kÄ+ƒL&Û»wïÅ‹ÉkFÜöïßßÜÜœ(zUIê 2Dm‚z[³f¾¾~FFÆO?ý¤ì¾^=/âãã·oßþâÅ‹ØØØôôtWWWBuk‚ZsA&“QÇv±g‡ÂÂBBHKKKYY!dРA]Åd2£££Ÿ={–››»~ýúÆÆÆuëÖQ3[ijjRk) ÊXbëÖ­eee‰dîܹ o¼'À@ÅóððHKKKLLTø¢§Nºzõê½{÷¨§¼]\\BCC;ï@…­ªª¢ž¡qssST×=º~ý:—ËuvvVT› öø|þW_}°téRwwweôòºó¢cöŒÆÆÆÜÜÜìììŽC¨±°111/^¼pqqéH«¯îÙaëÖ­ÅÅÅÅÅÅ•••}úô™1cÆ… ^wTfffHHˆ‡‡‡H$¢²¯H$š8q¢D"¹}ûö–-[¼¼¼ž={vãÆ MMÍI“&)ö ÉËË“J¥ ãÀj;òGÐ Pw3÷íÛ×=Ýݾ}›Édr¹ÜêêjEµ9|øpês›Åbéëë;;;GFF¶´´¼º!„Ç㙚š®Zµª©©IQ„‡‡BfΜ©¨{jÕÍææfº Qg2™ÌÃÃ2jÔ¨¶¶6Å6ÞõyÑÖÖöŸÿüGWWWKKkÖ¬Y}ô!„Z6¯´´ÔÁÁúÐÅžr¹œ×¾sçNWWW7bĈŒŒŒl̘1B¡PCCCWW×ËËëÆr¹¼²²’š‘€Ëå …Bww÷cÇŽ)ö=ihhH$„Å‹+¶å!!!„½{÷*¤µ9sæBŽ=ú¯ŽB„€^¡›#¬\.÷ññ!„,X° ÛzTª;wîðù|BÈõë×é®E‘a»G]]uýuáÂ…t×¢æd25…ÖðáÃ;ÿ‰«X=!ªéµeºíܹ“Çã}ÿý÷§OŸ¦»–wÕÒÒ2{öìÆÆÆyóæ½ÿþût—ª§OŸ>§OŸæñxܸq#Ýå¨-¹\>þüääd¡P˜˜˜¨¡¡AwEJ„  Æ Û¶m›\.÷õõUéµd2™ŸŸ_VV–¡¡á®]»è.T•££ãñãÇÙlvDDĆ è.G µ··ÏŸ?ÿÈ‘#ZZZIIIjÿØ%",€²,[¶lúôémmmžžžûtHÏ'“ÉæÌ™sæÌ--­ôôt===º+æããsüøq&“¹iÓ¦€€€ŽÙàݵ´´Lž<ùÈ‘#'99yäÈ‘tW¤tˆ°JôÓO?Íš5«¡¡ÁÍÍMÙ+I*\uuµ‹‹Kll¬¶¶vJJ 5SÀ»˜6mÚùóç¹\îáǧL™‚9†¢¢¢ÂÂÂ"))©oß¾ÙÙÙ£G¦»¢î€  Dl6ûèѣ˗/oiiñ÷÷Ÿ9s&µ(eÏwæÌkk묬¬¤§§»¸¸Ð]¨‰±cǦ¦¦êëë'&&J$jÂ)xk666wïÞ‹Å™™™¶¶¶tWÔMa”‹ÅbíÞ½;66–Ëå?~ÜÒÒòÀííít×õZ÷îÝóññ™:ujeeå˜1cJKKmllè. ÔŠ››Ûµk×,,,îÝ»ggg·{÷n *x ÍÍÍaaaîîî555£FÊÉɱ°° »¨îƒ ÐfÍšU^^îêêZ]]dmmýã?ö´ ûøñãùóç‹ÅâÄÄD--­½{÷þòË/ZZZt×jÈÄÄ$???,,¬©©é¿ÿý¯««+µ0,¼¡¬¬¬#F|õÕW„©Tš‘‘AM^Û{ Âtƒ+W®ÄÅʼnÅ⢢¢O>ùÄÌÌl×®]uuut—FÒÓÓ}}}Í`0,XPZZ¬–K«CÁf³·mÛ–““c``™™iaaÜÐÐ@w]=]mm­¿¿¿³³sQQ5cíÚµ½ðTE„èVÓ¦M+**:tèD"¹sçÎ矮««;yòä“'O655us1ååå›6m277wss;yò$‹Åš;wîo¿ývèСts1Ð;9²¸¸8((ˆÁ`|óÍ7úúú›6mêi7(zˆ¦¦¦U«V 0 &&†Ãá¬_¿>??ßÌÌŒîºè ÐÝ8΂ ½½½™LfBB‚¯¯¯®®î¤I“¢¢¢®^½ª¼ÞÛÚÚRRR–/_nbb"‹7lØPRRb``°nݺòòò#GŽôªátÐôéÓgÿþýÙÙÙ...MMM6lÐÓÓÛ¾};‚l‡æææˆˆ==½;v´¶¶úøølܸ‘Z^®wbÓ]@/Åb±¼½½½½½?~|âĉcÇŽ]»víܹsçÎ#„p8œéÓ§‹Åbkkk{{{±XüÖ7 >|xçÎ[·nåååeggÿöÛor¹œú‘®®î´iÓ|}}ÇŒÃfã7ÐÉÞÞ>###11144´¤¤dõêÕ›7o åñxtWG›çÏŸoÛ¶m÷îÝ„‘#GîÚµ«—L›Õ5|`ÐÌÀÀ`Ù²eË–-{úôéÙ³g“’’®^½zÿþýü±cƒ1pà@333}}}‘Hd`` 455µµµ;¢mSSS}}ý³gÏž>}ZUUUQQñøñã‚‚‚—.e1™ÌqãÆ988Œ7ÎÉɉÉÄí8èA>úè#ooïøøøÕ«W—••­_¿^*•………Ò]]·ÊÌÌüá‡×TƒÁ011Áo2è…†¾gÏžÈÈÈÓ§O:t(55•2¾páBWW×I“&¹¹¹ÙÛÛÓ]æ[ºzõê… ’’’rrr¨õ¸\®Ï§Ÿ~:a„^8UÖ›C„€žŽÉdR£ ª««ããããââ.]º”–––––FÑÖÖž?¾ÍèÑ£% ÝÅvE.—ߺu+%%åÚµkIIIóàòùüqãÆMŸ>ÝÇǧOŸ>ô©a@e…ÂÀÀÀÀÀÀúúú¤¤¤3gÎÄÇÇ?þ<**ªcGGÇ‘#GŽ1bĈFFFôL¹{÷n~~~nnnnnnNNNçÕLÁÇ|øðáK—.%„<|ø033óÚµk¥¥¥ÉÉÉÍÍÍ™™™™™™÷×ÒÒ:t¨©©©ŽŽŽP(422:::ýúõãp8|>_KK‹Éd²X, ™LÖÞÞÞÖÖÖÚÚÚØØøâÅ‹ÆÆÆºººšššçÏŸWWW?zô¨¶¶öÑ£Gåååõõõ¯–7pà@j>‘#G:;; …Ânz_Ô",¨##£Ž«³„ÂÂÂŠŠŠ’’’›7oR)³´´ôÅ‹7oÞ¼yó¦Â{g³ÙæææVVV†††fff¶¶¶vvv,Ká",¨-KKKKK˱cÇvl‘ËåÔ¥Óòòò?ÿü³ººúñãÇ/^¼¨««{òäIKK u©•ºøÚÚÚJ]Že³Ù|>ŸÏçs8œ~ýúéèè###¡P¨££cjj:pà@}}}_l¯‚ ½ƒÁ‰D"‘hĈt×o ´€ŠA„ƒ *T ",¨DXP1ˆ° ba@Š€ŠA„ƒf ·ÓÓÓ£»UÒÒÒBw ˆ°ÐëÕ××Ó]ü;ˆ°Ð{ÕÖÖÒ]€ªâp84öŽ ½—@  »xxœ T ",¨DXP1ˆ° ba@Š€ŠA„ƒ *T ",¨DXP1ˆ° ba@Š€ŠA„ƒ *T ",¨DXP1ˆ° bØtÐ}d2Y{{;ÝUÀÿ“Ëåoq",ô"K–,Y²d ÝUÀ»B„€^Åb±ÙøÄè¡ Æ¿Úÿÿ¤¢C<Ðf¸IEND®B`‚designate-2.0.0/doc/source/images/Designate-MultiZone.png0000664000567000056710000010760512701406241024472 0ustar jenkinsjenkins00000000000000‰PNG  IHDR€à5ÑÜätiCCPICC Profile­‘1KÃ@Çÿ‰•*Ú¡H‡E‰uh‹SÚ‚JUP·ô[¡i$Eý.:ˆ“ ~]ÅAÁAÄÏ ºH‰ï’¡SqñàîýÞ»?ï¾%D;Àéønm½Èv÷öYü*f‘@y‹{¬V7I2f Þ¡È«7]æ#žiØ”)ð†Çb™CãÂõ‰/‰õ#_H~"N»ôAâOÉ͈¿%×CVe)iw»VÔ qªñ’äfÄyɼe5HS!Ö¢?Ó•2ËÝ ½<œvê —ìVÂîìl‘MÑžCe0ä` ¦oS½@©+NÜÃfËg&uÖf¥®#z¾íjl£Ã—5–5V ©“3“è×ÂY(³¯£X÷(̧£Xý¸2Ï£ØÂ\î^„åZQ>:•Aì/ß;X͆z%Q&¿‚ ¿ÄÏáYüÜÁð–Þ§™=¶p bâßtÐU@IDATxì ¸Źþ?öMöMA(*FP£ñº%÷ºkŒ ‰ Æz£ÿÊcÐàš¨Ä$‚÷ªq¨QLDã#*DE#ˆ¢ˆÙwæßo™¯Ó3gfÎ,Ý=UÝo=OŸÞª«¾úÕwfÞ©­d¼ $@$@$@$@©!Ð05%eAI€H€H€H€  @: ¤Œ`Ê*œÅ%    @ú ¤Œ`Ê*œÅ%    @ú ¤Œ`Ê*œÅ%    @ú ¤Œ`Ê*œÅ%    @ú ¤Œ`Ê*œÅ%    @ú ¤Œ`Ê*œÅ%    @ú ¤Œ`Ê*œÅ%    @ú ¤Œ`Ê*œÅ%    @ú ¤Œ`Ê*œÅ%    @ú ¤Œ`Ê*œÅ%    @ú ¤Œ`Ê*œÅ%    @ú ¤Œ`Ê*œÅ%    @ú ¤Œ@㔕—Å%¨@&“ñŸ ëÅíÛ·ËÚµkeÆ ‚ûØpMãêµÜ}ƒ ¤eË–fkÕª•à\Cð¸Ðµ|q4n{-¦{Žë(÷úõëý ç°3¸!^ð\Ë=8ì°Ãe±Ðç‘. ÔG€°>B¼O)" b{ˆ¹üã²xñbY¾|¹¬X±B>ÿüs³}ñÅòÏþSV¯^mâ©ðSá’+x€0WìèyÆ eÍš5¾XjÞ¼¹ƒmÚ´‘víÚIûöí¥C‡fÃq×®]e§v’îÝ»ËÎ;ï,ݺu“Æûék^Á=ŽË A[·n•eË–É'Ÿ|âoà€ò¯\¹R¾üòK³}õÕW†„߯}QÛºuk_#]Ý`ë×”˜¶hÑBð<Ä x€C—.]¤S§NÒ¹sg³G¯^½d—]vÉÊiR‚ @@ïƒçß?ëƒwxL$hú¯q7wî\ùûßÿ.óæÍ3¢ïÃ?”uëÖQ±ë®»ÑÁñMUðA ä¶ÞU O[Î?D– ,ìW­Zå‹0²?þX>ûì3#ûôé#»ï¾»ì¶ÛnfÛÿýP‚ *&†”Dí믿.ï½÷ž¼ûî»f¿hÑ"#þ ² 8ƒ¢âT…)ö;v4 ´5³Òòës° , Ž!ÁC¸ŠqìQ|ðÙP½{÷6[¿~ýÛ€LýÕÇAóåžH (ÓQÏ,% K—.•'žxBž|òIùÛßþfZ« öÝw_8p / z\hmD™.\˜%Ü^~ùe#T¿ýíoË AƒäÈ#ˆDBMàðÊ+¯ÈìÙ³M ç`âì±Ç‚­oß¾Ò£GóŒ , !ޱ͙3LjzìѪ Gq„~øá¦ÅP9ű e¤$@á  ‡#S!« |ôÑGrûí·Ëý÷ßo„ÄÐQG%C† 1Çjã+4b¢PÞ#Y†.={ö”Fù¸BÜ|ŒHÀ1€ŽUÍ%r@ø]vÙeòøãË)§œ"£F’ýöÛ/±B§>6h¼ãŽ;dĈràÖ=‘÷!Œßxã ù¿ÿû?ùÃþ`ZFá#è:ÆXJmLdáY( Ÿ ‚$,/½ô’œxâ‰2zôh¹è¢‹Ì$‚d•¥©–Æ^sÍ52mÚ4yúé§M÷wÓ¦MM‹ 'ŽTK—Ï“€Ý(í®ZGÀd LRøË_þbÆ|U”J ‡zHN:é$3f“~š5kæw § J)#@˜² gqÝ&€î;ÝoÙ²Å_{3F±¶±cÇÊ!‡"×]wÛ¦õ±À˜PÌä>çœs¤mÛ¶fIœcV3öhD¶ ê±îc3–‘ TM€°j„L€¢! "ë˽öÚkf‰ æÇŒWÝÐÒ‡Ö¬Ü0óóÅ_”ï|ç;ÑÇTGàÑG•Ë/¿Ü´üé Ýc]C´(cF4Ö^ÄKâ`™,·ƒ{:vPÅ îŠ"„ LHE²É чuíÐ%‡¥I^}õU³î–gÁ-¾t¿ño˜/`| cAd~Ñ&£îm.üòÓO?õx`rÖaĺ‰Ø áŸXrçøã7~„ôQ›k—¶¥•`Zkžå¶Š–$Á-Ó§O7-}'œp‚tÐAæ u¯½örf:« Ò˜X`Æ·ß~ÛüX™5k–ùñÒ¿c\!Ö“„TA‹QÌ„H ^€õ"bˆŽÞtqýõ×Ë­·ÞjÖåÃR-X£ݺ6ÌmÒ¤‰YP8n»·æ×¢aQc{ lÚ´É,2þÀÈÌ™3Í’;ãÆ3Bë Ú[o´,}¦¯È,1 ØAàæ›o6ošÀ+Îð ¶»ï¾[Ž9æëÄ^7†÷ÐbŒa¡0tèPÓ®>ÝÐ 4cÆ ÿ‘ãŽ;ÎÜ›?¾­Øâáä®o¼‚6 ¯{ï½×ˆÂbÏó^màÇ üþüæ›ošIJX{òÆo4oÁ»•ÑjÈ@$P[€µåÏÜSH3w±1Ö^Ãø©©S§c+ ¼ADCPÐé5ì!Òr¾üñ¦)S¦dÝBùë ×^{­™`€‰ ¹á¹çž“ÓO?]~÷»ßåÞâ¹e Üáߘ”tÛm·™.a¼Ó>°mÛ66»efÓH ÀTT3 iÁƒ fóâex —Í]¯ãÇ÷M„ +К‰™£«W¯–[n¹ÅDÅ’4˜Eª]ÉÅÄŸæ‰E¬ßÿ}# >ÿüsÓ­ˆÙ§av/Y²DÐ2Å øùܹsMýzê©‚%‹PŸl Œ†7S%RP–B‰qH $xý¾ñj6¬¯f{ÀläÜ€åe tÑB˜a¬Þ˜1c E+xݾ*þÐòˆÖ#,LŒW”aëܹ³+‰.ósÏ=·`:…n@ˆÅ(â!Ï^½záZè¹R¯CDB4ò˽¼¯ÏÔ'@‘Nnœ|å ¦mÓ1üýoû›™IŒ1¯ø¡€òPÚTK´%M(ÓTÛ,kM `p ‘¦áÙgŸÕCÓÚãŸ9@÷.ZÑM^,h^x·/ÆÇâ×paáÂ…‚1‰ºV"Æb™؈ÖDtcã™ pEŒCijØpŒk Àð î]qÅf¢ Ò6l˜`ìä%—\bòÄ5<›+ƒÏ e4Ø]®eÀxGø lGœ|°`yÔ.[÷ðû;ï¼S~ûÛß Z‹ñ?¨k^Új7í"DðþñH€b àÍøÍì°ÃoìS ¹UŸ…7þ¯ÉxÉ$æuëšs\óaVž`3÷°Ç†g›7ÔÄÕ8ÞØÀ¬gƒ'^—¯yy—nºé&óLÐ&#oÜC8ãŒ3Ì9Ò‡=¸7qâÄ,;Õö &˜g¼wäšxˆ‹òËä‰aÇkÅòã ®ãáÒÑkÈ_ƒòÀ½`^“&M2Q´ H›ÆÇý|åÑç4}[÷ðOÌfïSôã@4#x­]æâ!¨}HKŸÓ´p ÇÁ8xÁ7jî©ÍùÊc"Züeƒüë_ÿjêÀ›âÌÿ„ÅXi ”M€]ÀÞ§- ÄAc 0+ò­·ÞŠ#»ªò@7§'@L˜­ÜË#‡M¯av.ºUsºõ0¸ºWëëÆÍ}¾cÇŽæÒÃ?œ{«ªóóÏ?ß< )è²}ùå—¥[·nYizÂÄ?×n^¯eN à_?øàƒ×–-[æ_ïÝ»·£ˆ ÿˆà‰4ÿÝ·à‡n`ðÑ€n]ؤqp=xßyÒ¾}{}РAfŒe)åÑômÛ£›õŒåb´û×ûæ²ÍLÚC‰'@˜ø*fm!€/<,ˆëußÉæÍ›m1+¯W]u•¹ŽY¸˜ŒÜ`?Â/~ñ ³þˆÑ Áë¥ãÍX3NEX¡gs'DЇëóçµ`Q†óÃ;Lîø×ø@œ#g'ký›iŒåL* Á|¼VRc„!¶ ˜YÏ*"‘~¾EÁK)O%¶Eý ~ |÷»ßÌ[};0 @¼(ãåÍÜRL_rgžy¦y—/^ó†¥0l hÙÓõ÷ð–´â·_ýêWÆl,ôûÁ„Z´¶A$#`¹LŠX¹r¥Ÿ&]`5&Y`"& 装/0q¢C‡òÈ#øeÃd,Yƒ°hÑ"³G~È-†ÁÉ%È[g)÷òZD+ mÛ¶5ÂfÙ}öÙÇlH·>q[¬<•ÚõsxÇõá‡.}úô1b 1)o¡Œš>Ó'º(ë2ሌ¾ìî¹çi×®ì»ï¾‚õçl 7Üpƒ1É›TàwamÄR,ÞD s o3)5¨Ð voæ{ùk+#„›ÎÂE ãÀÍ[& Њ†€¸˜U qxöÙg›k*O>ùd3Ë÷‚ .0 ã&ºãTì!OÌF~¸§BÔ·g fñ"o°éÛ·¯9Îý“¯|Ák8ÆÒ6ÊPÒGù°Èu°;ZȨ̈Xy‚ñl9Æò/àŒ®l,íƒN ‰Ph‹´ƒRE ìQƒ|€H b˜‰YÔÿóŸÿ<ã}!f†žñ†®8Í0Ä}ïÐl:I"_ú¸§ñðŒNJÀq¡à ,óŒ×ÕY(JÖuL¸Ðg4/ìur‰N°ÀC:÷1Ñ3bq¬“P°ÏMÃë6ù!µ_Ÿ÷Dš¹ç‰õ¬çpúôéæþ(/<¯¡Ø5<d„IA»`;òD'ÜÓ2húØ+O0^­½ÓÌ÷¾÷½Œ'ø2?þñ3Þ’™¿ÿýï™?üÐüàÁ•YñµfÉüI l  ÷!Ã@$ï Ï ò÷„€Y­høÃLKÖi§fÆ©å÷“yÖeƒ–>mAÃø¹Bãò4^pü\nat¾|qŠÝC·0Æ6æ{.7rÏÑÝ _(V¶Bi³¹Ð3Q_«ûï¿_°ˆ8º³ÿë¿þK~ðƒH×®]Å[É0G´v¢Ìhg ˆŸ`üÌ™cÊ à7f?â‹¢_þ^‹š`æëOk @¢53N1Î _¤Ø–.]j„ ×U&o¿ý¶y£Ä7¿ùM3cÓ0Q`—]v1_²=zôàzkk89†¡Öë¶5“~0›~´`æ2~°têÔÉŒ‰Ük¯½LKöŽ;îhÆ÷¡%[DÎuÜÔ$Ç?X7 PºYo´:!´5P»…ñE 1Q¨ÂKgàõqï¾û®`&åòåËÍæ-8,k×®5_¨øRÅ—«Î¬DëÊ•W^)Ç|BH±Qxì±Çä˜cŽ‘ÝwßÝø üP7ø%ºo1ºsѲ·Ûn» ~œ`R|]ºØTè©_êut÷²Õ/êšdú$P ÀÒ81 DJ@… v C¢‹_¼ØpÜpqÑbˆådЬ-ˆøÒþãÿhì1cF¤v3ñäÀ8=,só“ŸüÄtÕ»k1c"â › 9ì!ü‚›Š=\Óûú—{IŽ¿°$îø÷›ÛÝ/ K@ÎÀcðK5(Uìa¯›vc ñuÃ9–ÁøÁx@N9åg¹Ððè Àon½õV3që?¢eâ­xê“ðOÝTÌé=ìu ŠCë3Ø3 ØE€Юú 5)' _˜À€/P„ °Ëw¬×°G€D—f`zKpˆ÷.[ùÿïÿ™uðLþ!À:”—]v™ ûo_ÁØ=,Rî^ 'P‘‡èê›Á}Pä5þ¿²áŽHÀBœZha¥Ð$ý¢Å+¾ˆµkMÇUá 챡‹N7´Þà |Ï=÷4“Ið†‹ž={ÊÈ‘#(„@Lc@W:fZ£«Ó[.L™1¶ôÏþ³œp æí#Ÿ~ú©Yœo§ÁÀ6mÚ‚/©_a¯þœÐ¡~©bQý6µ€Ypp„Ç:RQ4“Ê!‘‡îbŒÄAÌÔ¼ï¾ûäñÇ—¯¾úÊt}ôÑrÔQGI/oVq„ZA±,É«¯¾jö7xð³Ï>+XC¯&Ã*†xK–à/I ðƒwÞyÇÔýÓO?m˜@èá *h!þÆ7¾aD~4`ƒÐ vÿ&ËC$ð5 @z $”º„ñå!„ "˜(‚m±·„Ç_ÿúW³fÞs‹ûh-„ÚÿýÍÌN¼æ¬[·nNÈ…ÀÅ’$ ,0ÇX²Kè@ða–*¶8Àˆ]´X¡µ Ëí`Ý:<‡¸XÀ¯œÃ;(¿.½Ó»wo¿;Þf ¨kÔ-f‹ã}Îo¼ñ†~`ƒVcÔñ AƒŒàÝyçýeZ‚-É8F\ðI¢¶¹þh ÄM€0nâÌb$ˆÖÀàŒb>ˆ&ì±ai ´¡»Ø{- [¢"-DXúk½a‚–ÁX1lx£DÞñŠãjED Zæ°¡¥rÅŠfûç?ÿ)Ø Ò`6,‡ƒû¸Ö±cGóþ^¬‹{Ñå ‡ëÁåI ntÆ*ªAgVƒÒ‚„x„Âø8°øâ‹/ÌûQv”y§v2\Њ†ôÁE—FlhI ƒÅªU«Lùðel(7ê KaØ 1‹{袅¨7LÂ2-~°ÂeÝt¹íÆÅ}Ë£›2+  ¬tfIqP!…M….1£{½Ž=Öüè£|¡Ü Ht ì!*µ5I'¤¨Â>xŒòë5ìõy1ˆlèŠÄ4*ŒIÃ^Å&Ęn_ˆ¯c%Ñz¥"/w¯­ˆ‹ ]åùʯ,P.]{{^gª*ÎÀKËg ²‚<ÀD¹ o=×½^]ÒG9 ðˆmˆOÝC„Bð¡U¼P~Ýò•×T âXãRø¡H =(ÓS×,) d‰?ºWq˜»×ûÁ=ޱA¼÷@/HCC0Nðš JØ…¡«8Á>wƒ€Ñk*f‚{Ü ÆÁ9ÒEPÛ´<°ǹ ôºÞÓøÁ½¦¥û`·;®!h¾Á½–1¸‡x„àS[ƒ÷ôöºiù‚û ƒà1žÑxÁtüC$€©©j”² ¨(Á^EKîG¯;Á瑃žc_nÈ$z®¢çz¬â'÷<÷½ë8Ú¦Çjw°ÌÁkÁëÊ÷õzî1òÒç±/7h9‚v¯i¹°nˆ£çzÜãA÷åÚÅø$@É @˜Œzd)H *TT¸ Q=ÎÝïéq¾=®•T”äÛ¯á8¸!}=×ãàÇOË©×r÷z?¸Ï=ƹnx>÷X¯÷8.5ÀN„|ûà5çnú\0žIŒH€Hà_(é $@%P„ÈÁc}8÷Zî¹Æ+¶WÁ¢qrÏq=÷Zî¹>[hø•ئéå>›{Žx¹×rÏ5­bûÜråžãÙàµàq±tyH€@€~@$*J•²TAbaI€O€oI|³€$@$@$@$M€0›ÏH€H€H€H ñ(_Å, d ÌæÁ3   H< ÀÄW1 H$@$@$@Ù(³yðŒH€H€H€O€0ñUÌ’@º à}ºXúE7ÐÐcìñÚ5 H À´Õ8ËK)#pØa‡-q}÷‹>Ì›$@$à( @G+Žf“ ”FàœsΑ֭[çŒëçž{nÞ{¼H$@I&À7$¹vY6 Ùºu«´k×NÖ­[W‡F«V­dåʕҤI“:÷xH€’L€-€I®]–H@7n,?øÁ¤Q£FY4pŽëYXxB$€)©h“ÒLଳΒæÍ›g!À9®3 @ ° 8µÎ2“@ tëÖM>ýôS¿ä;í´“,[¶Ì?ç ¤‰[ÓTÛ,+ ¤˜ÀèÑ£K `s H+¶¦µæYnH%K–È{ì!›6m2ðÝwß•ž={¦Œ‹K$@_` =H  öúöíkÊŠ=Å_*ª…$(@€°^&HÿøÇ‚¥_°g  4`pšk¿HÙ3™Œ`CÐ}‘è¼ENX½zµôèÑC–.]*mÚ´qÂfIåÀ+ô•‡å>Ïøé @˜Žz.«” 6¤è+‹#“ €]6lØ`ÖÀÄç96È%Ð8÷ÏÓM@[þØê—n?`éI€Ü%€–?¼ùk]bÆ;[Ý­Ë(-§Œ’®ƒiSø9Xi4™H€r¬ZµÊ\ÁoШÝÂ9Ñxšb€)®|*!°bÅ Ù²e‹´nÝÚl•¤ÁgH€¢%°víZÓ˜ûœhseê.àÀ—j+[Ù˜òqÇçw£hwŠîï¸ãŽü9ruãÆ¦lC‡-j1Þš8]ºt‘îÝ»›IÆ “5kÖ}.Ì›qä¥u½páÂ0M/)-­ ØP(ÌŸ?¿Ž/öïß_¦L™"[·n-ôXëð[øðܹsëÜã÷ lÞ¼Ùøƒëq¿D,AØ(Ã&ÊôRG »К‡PlV,„ DßsÏ=gâöë×Ïìï¾ûnY´h‘9ŽúÏÔ©Sq îõë×G]¤ŠÒ×ú >üæ›oÊØ±cåˆ#Ž^.zŒÑMš4)7Ý$°}ûv3™?êݬ¿8¬¦Œƒ2óH ^xÁtb†ncÆŒ)«|x#E9-5e%^AäRÀ;ï¼cR>ãŒ3L¹çÍ›'Ÿþ¹{ì±äXÙ#ú·¦M›V–@™O•Â¥Ì$C‰®vz衾/>óÌ3&mt´–”g)q‡H y80yuÊEH ]»vfi…Æ+û×Á—3ZÏÐú‚1t¹Â²E‹&ŸÜûzŽ9ØÏŽúî!JÇuêÔɶsçÎòÈ#¨IY{Ø€P_>ˆW_MxĈrâ‰'æåV_~õÝ×<¢Ø—’·ÆÉ׺WÈ&´Øª»ï[¶l™õˆ¦]*çRâ×~ŒMíË2È;©ÆÏ5íRË“›7ÏI€¾&À@z TI_H:ã°‚cäpûgŸ}Öˆ?ÜÇ—7®[¯¸â Ó‡{hå ¦¥ã¾î½÷^¹öÚk@Dœ|Pîø×X.<±`¸‡ëf̘aòÃ=låŽÝkÛ¶­IêÆo46¯\¹R“ÎÚc<™Ú€| L>øà?òÅýÙ³gûö`¼Û­·ÞjÎQ†`pB|”l‚-\8FZ.ÄEY5ÔgÆ«d›`;ʃ Ǹ¦“ePÞB¶!Øà9ƒò•´ ñá[ôGA)ùë3Øó>°kÔ‘Ú‹sä ðOøâ`òáDC¥~ŽçƒiÞK.¹D“åžH \Þøð xÔxý‡΃¯ x]† Øx]o¯Ïl8_°`ÙpŒíöÛo7=ÚÆë.õã#ÒÃ6aÂWÓGº×\sÿܤI“Ìý9sæø×ôyìqÿ¦›nòï!ÏàóÞØ°Œ'²îã9lˆ‹àµ8šsØP,LŸ>ÝOÏ#¯ÅÊyiÚãÆË`Ós”AˉëÁc¯‹¹NÜ÷ßß¿µœ`ÌÜ”7ìʽ_È1çÚ…ô … ã / \·Ür‹yLãÀ_¼®s¿,‹/6÷±W>ˆƒòiÞØ ¹åÖ4°GêËvâ¤Wªh^xVm…íôâ¡>pÇHAïWâçÁr£l¹i« Ü›W8e¼#øØãsr ð›>—HÊÏ)ó;€~qé`p¯Bá•W^ñ¿Ðƒ÷Uü eM§pÒë*ÊŽƒ_~_~ù¥1ùáž~‘«ðÄM½A€8 Ø#ày¤«_ܸŽsØV_€(Ó2hs¿Ü!5À&ă=ú¬ÚŠgUÐA #®Š^tú¬–IykZAу²¨ÀÒûÅìQ;ƒ{}Nó ÞÃqP˜ªí¸î5ö£ ˆƒ2Μ9·L@¹pOŸQQ¨? õ8°¡Pú„â7e[_þAž¥úòQÿS¿Á5Ô#~©Ÿ|ò‰o>X \A»+ñspËMy2Ô%N€u¹ðJ6v{ÿ) $P*ïKÈŸYçý+™ã}öÙÇ<>hÐ Á$‘`ðĈ`¬\nð¾<ýKÞ—¡Œ.3tm¡ûLCð¾'v¤}ûöæò Žƒ8p >"x 9Æ@Ĺ뮻Ìr-èF2dˆ¹WNw£&¼ë®»šqÁr¢[AÇ4ž|òɦ (ÇÈ‘#Í=]”ÖœxN=õTsˆg `ŽÏ;ï<³Ÿ8q¢YšdÚ´iæü´ÓN3ûÜ?>ú¨¹ä EÿÊÚ³gOs^Ž=~%h7¯× åÛŽÇ>ø`Á5,™ƒ1‹Gu”é¾à‚ åB@ƒ'ýÓ`W©±À'à“qÔu"˜£k¹Ôü‘|©>â Sßÿð ÎP¦·ÞzËÃG»uëfŽñ>ƒné WâçžØ”3Ò1< W¯^æœH€Ê'@X>3>‘b¹_Þ¹(rÇÆ}öÙg¹QÌy¾tðåÁèµ”˜ÍkݯõÄVx°Ò™›OˆõûN?ýt5jT^›Š]Ä8¯à|;^ ¤yD—†Ñû"°åÀ› Áby@4x]µ&ŠŠY*rÅžÍw¯Z{ò¥‰kX_ ¨PÀk¸ !‚l½ŠB^+™y<(úô^¡tƒ×s<Æã© ƒà®/ÿ`Z8®ÖGrÓ+t^©ŸCDb¬£×²i’ÆüPÒz.”¯“ ä'@˜Ÿ ¯’@^Åֆד~c¹|ùÚõºÊÌu];‚Q'X@HA  EZ7ÐÚæá2ÿà kÄá‹­EçŸ~™)ˆ,]ºÔLÀNè#Aj¯¿þºôíÛ×”{ˆšRUV¨ŽÊÚëZÍb¤"¼Z{´®Á_7Ø…:EÓà„ÔóøñãÍ=Ô&è  µtòäÉ2|øps®³t1qáºë®3{ü ¶üú ¨/á6ì{â‰'D[Eq­¾üGC>²÷Þ{›är¹ mØW­Ÿcù$ü¡e~ŒAý_2'üC$P:ï‰|Þµgã_à!à‰'ü‘÷ß•uŒ±TÁñM:æ cÓ4®× fÒÑqn»¥cÜ0~J¯#¾'lü±r8Ç}M?8ÞM«&8–K¯éx)ÜÃójlÓÉjƒ×ºgî#ßBAÓC:`g5Mçæµ^ú×pcÜ4žŽëC¸› 凸Ê,”‰Ú¡cê'B)ö˜ˆ9ŠÕµ2R†È;·¾´¬j/Êã 3Ÿ ìD=èXÌ ýÊGóÉ1ÍœëBŸ îõÙúò×ûàXŸx¢Úدi«]j/Æ"härÍÕø¹–õä1† ÙÀŸc³™ð¬.ü’b Ÿ "ë øÅü²Åñ¯ýkÿË_ªÁ ÿ_’ø¢Õ/M\ƒXñZÈÌ#ú…¬éãÞ=÷Ücî©ØÑþÁ

8× %妃ç‹=‹uãÐõ‹.M]—®Ü8tŸR ,6 8MïÌF ,>ËùyîtUFf<`dhÝMÝ+XÆKI¬]»Ö,{±}ûvw äYŽ5óÐ%Â@ôú@}\ö‘†  Äß;ì`–bË_}µÞû€é­û¼%Ç/EüjÔñgØc¼NÆb<  €}~PW}D?Ãuxm¬¯¼¼Ÿ>€é«ó¢%Ƈ~Aâÿ1vÄõÖ?-pÇŽõû” /¤ÜJ(¾Ë>‚Ïplس ¸„ OaNIa¥—Rd´øi«ŸîKyÎÖ8ø DK& ÐèõpÝGTða¯Çõ•™÷ÓG€0}užÊãC0 B6••r¡é !M`rô‘V*‹T‡_W / @² P&»~Y:   ¨C€°^    d Lvý²t$@$@$@$P‡`$¼@$@$@$@É&@˜ìúeéH€H€H€H  À:HxH€H€H€’M€0ÙõËÒ‘ @€uð $›`²ë—¥#   :(ë á   H6 Àd×/KG$@$@$@uPÖA $@$@$@$l€É®_–ŽH€H€H€ê ¬ƒ„H€H€H€H Ù'»x,]¥2™Œ`CÐ}¥iÙòܶmÛl1%4;4h`ÒÂ^CKVc ¼ö¯¿åkl³·‡€~hØc-)F`Æ Ò¸qciذ¡ÙŠÅ­äý¡jµ{†þP;ö6æµ?ØXfÚT¶–Æ)5±ô÷ÀòåËUæ®]»JÒÊ„ B¹Ö­['Í›7—fÍš™ 0[ý!©¾@ï#+)>õçCxÄ™R-PÖ‚ºÅyê¾Å&Ò´«V­2W5jdZ£€9YòÔbô‹+§¦Eé5(³ ‘'„“I‘@-¬]»V6mÚ$I³T ~IË“þ´­®<ô‡êø%ùi À$×nec `ÐjüÈæÍ›eëÖ­f²NØõvz5F•Šìé©¨æ’ ¥?”l#ZI€ÐÊj¡Q$P:íÛ·G"þJ·€1m"@°©6jo ý¡öu`«€¶Ö í"   ˆPF–É’ ÔOÃ6nÜXDÆ •`¨8Ó‘Øœ9sÌò#ZZ 2Ær¹ÛäÉ“M|¸ã?ä•X²öåøÃK/½äûÉ­·Þš,,!PŽ?,X°@ºwï.={öý¼ F xPÆÃ9Q¹L™2Å”göìÙf¿Ã;È|`6¬µ7qâDsý’K.IT¹Y˜üÊñ‡Ï?ÿ\à7Ø.½ôRùì³Ïò'Ê«Î(Çz÷îm>7Þ}÷]¹é¦›èÎÖ: w‘×t±ÖjhóâÅ‹å‰'ž‡zH~ö³ŸÉsÏ=g¬DÀ/úI“& ZjvÞygÙ²eK– h…ÔФIùøãõ”û ”ë'œpBVNèþ‹:Т&üïôËõ,`Ž„3f˜D:uêôïÄb<¢Ä›YYC€-€ÖT…†ÜvÛm2fÌéÕ«—¼óÎ;²hÑ"ßptñ2Dî¼óNÁj-Ã!‡R4ûƒ>¸è}Þ,@¥þðä“Oš âðúBiuF¬JüaéÒ¥rÑE…‘}ÅiÐG*FÇ&@èpåÅmúW_}%S§N•_|Qh²Ÿ6mšo„!¶#<Ò¿V«ƒþð‡¢­’¹6àúˆ#r/ó¼L•úž>|¸`<`¾e‘JýaÏ=÷ô_Óˆ•µô‘ZPgžµ&À.àZ×€Cù£›_Ü×]w±-~¼ý?ÿó?òüóÏ›®áyóæ™/tí5nÜXÚµkW“vØa‚õ¯ò\:th¾[¼VJýáÌ3Ï”“N:IÚ·ooÆ|í¸ãŽeäZ~TúBùÌ*y¢€h\½zµ´hÑÂdÙ¡C‡J²®úúHÕ™€ƒ(¬´Z™Œnš`« Æï\|ñÅò›ßüF´%°ÿþ¾yßüæ7ý1‚þŘ >?þx¹ï¾û²„`Æ ÍuŒd¨Ž@%þ0räH™5k–ÉøÁ”ƒ:H~øáê ©çiúB=€Bº]‰?àsãðÃ7`òXCò—>’ ¯%@ïUO™¤’å+Þ'‹CÌæu=Ì;WN<ñDY¿~½_”–-[š , ð¯¹|€‰-˜Q‹=ZOP¾F…V¤¤øC|•î¢? ·~PÖ2$ÑG¢ö‡ZÖó®žÇVÏ)XJ"/w`ëÖ­%)âÏRìVšE_°²ZŒQøÁYkñCè#öú-‹†`4\™ª%0f±iÓ¦Æì‡ f‰e4#nô…¸‰»—}Ľ:£Å• ¬œŸt€À©§ž* 40–bs†t /¤³ÞË)5}¤ZŒë: @×kö%УGéÓ§‰ƒ=ÎÒI€¾Îz/§Ôô‘rh1®ë(]¯AÚ_/Ì<ÅäìÒM€¾îú/¥ôô‘R(1Np˜$Ôb Ë€Iä:‘\÷54'oÖÿýßÿmÞOŒ=fµº‚]×zl»í¶ûƒ«¾€zWÀ^éápÅGÔ\ò‡ðk‹)VC€°z) øÚ*úòUÍ{ì‘ï²Õ×–,Yb–åÁú…Øl.ùƒ‹¾€º§?Ä÷à‚¸äñÕs*•`©¤/‹€¶ô¸$³ àÀ ~Ùc ÃfÍš™Íæ_úô‡èŠþ=c—rpÉ\âš&[ínRHSM8VV ¿x* ¯ÉÚ´i“Y(×fæ6ÛOMÅ“ ý!ήäâŠ?¸Â3mvR¦­ÆY^§¬[·N6oÞìÔØE§;f,ýÁ± ‹Ø\úCÄ€ž<`Â+8ªâ±Å'*²ÙénٲŴþáªÍÌm¶-›¨Ûgô·ë/lë]ñ‡°ËÍôÂ!@G¦B‘ؾ}»~X‘àu.QúƒsU©Áô‡Hñ&>q ÀÄW1 H$@$@$@Ù(³yðŒH€H€H€O€0ñUÌ’ @6 Àl<#   Ä L|§§€kÖ¬‘7¦§À,iQô‡¢xRw“þº*gë!@X ÞvƒÀŠ+¤M›6Ò¢E‹‚:Ô¼CUߨ}ÿþýeÆŒþ3Çwœ‰3þ|ÿÜ#@p¯Î¢´˜þ%]¦í* @WkŽvg¸ýöÛýó  ó/zˆ¹áÍ7ß”c=V¦L™’u ëk1¸K€þànÝEa9ý! ªLÓu€®× ítíŒ?Þ'AW,|ùå—²aÃÁk”n¹åuìØ±YÝÇMš4)–ïYL€þ`qåÔÀ4úC  3K'P:QM4²‡z¨Îí_|±Î5½€nâæÍ›KëÖ­e̘1z™û„ ?$¤"C*ý!$L&q(W¥é*ÐÖ­[eäÈ‘¦ÐsæÌñ[ôÎ;" 7nìß{öÙgýcvûú(œ= ?8[u‘Nˆ+M&¤@,Fº<þøã¦Àýúõ“Èn»í&gŸ}¶`lßܹs͵\"'t’¹ôᇚx87nœiÌËs·Ðܪ¯¨­¥?DM˜é»L€ÐåÚ£írÙe— ƒ–%K–˜cˆAÀI“&É#ê_;ôÐCeøðá2bÄÿÜ%@p·î¢°œþU¦™€I©É–cöìÙ~ Þ´iÓ[0@è-\¸Púöí¼,˜‚ñÁîà¬H¹]ñ‡üÖój­ PÖºÎÉ’%²~ýzY½zµ¬[·N¶lÙ"Û·ow¸Dö˜Ž_öøpoÕª•4mÚT5jdq,¡?ÂeúC”„‹þ ü‰) `bª2Þ‚ ¥-SÍš5“6mÚ˜÷ënݺռG7^K’™›ò…øc°¶¹uMí¥?DãÊ—þ _×RuÍ\ã›{)ÓRÓ!—@øŠ/|´Né ØCÎ&ÕÉ)cˆ?°Æ¹­Am¥?DWCʘþc—RvÉ\âš&[)ÓTÛ!—UE ö™L&äÒœ >ìõØf"ô‡hkG}€þ-gWRwÍ\áš&;)ÓTÛ”Õ•/£ŠÎ$ó ?ä’âKô‡W>‹n=.c}Ñ@   —`¸<™ XO€Ðú*¢$@$@$@$. Àpy25   °ž õUDI€H€H€H \€áòdj$@$@$@$`= @뫈’ @¸(ÃåÉÔH€H€H€HÀz\Úú*ŠÖ@¼½Cßàý¶mÛL†º6w¦ÔUp #MMCý@÷z{{ }!ìzÓôto/Z¦òùß"¢tÒ½oà}éóý])õ¼º‹ÕŸÒÊg±I€RM`Æ ¢ï•Ö×y¦H ÏÀV:Š á§[J°Ø$@$Jh\·n4oÞ\š5kfÞ5®­‚©’ÒBS¦´âÙò—ÒŠg±I€HÀ#°jÕ*áQ£F‚@ Àô¹'¤¯ÎYb  ”X»v­lÚ´É÷r©,>[SYí_w§´è‹ì¯u ©þÇ^ Î$@$P&Í›7ËÖ­[9¨LnIŠN˜¤ÚdY*"0wî\¹æškäÙgŸ••+WÖô1ºb:tè C† ‘ /¼P(좩¨Z«zȦZý!ÀJ$¾}ýaûöíñ¹•9± ØÊj¡QqxþùçÈ:è ƒdþüùY¿ˆõC?Î=–l€ \ž~úi#!ù¥ ⼉\{íµ¦åuäÈ‘òä“O ºÈâÿ…ò‚àƒ=gžy¦à‡Êõ×_oü×ù£ oU†r‘þ F&b3ïC‡!…¼±h>È[ò7ß|ÓÜûä“OüûÞ/asÍ[;Ê\Ós¤íØcÍ|þùç~üàÁ‚ 2ýúõ3ñ4þâÅ‹3^·kéÔ"x_œ¯E%óÛßþ¶Ù—œ'ìûÎw¾“ùôÓO3Þ íŒ÷¥Ÿí áxâ‰'Œ‚³ÍöuêÔ)sß}÷e¼Yœo?ý!‚ Kº?àsxöìÙ|¯^½:ƒï†ô`  ÷ŸÀŸ@÷îÝeÍš5²dÉÓMª±0VcÓ^xáÁb¢Þˆ}ôÑÒ¥KY±b…F3{Œ¯ÛsÏ=Í;‹ç0 ­¥´¢Å.¬ðÆo˜®ÖQ£F…•d$éÀ¾÷Þ{O¼kÃZmG’YŠEkÏŸþô'kZ UZ‡o¹å¹é¦›Ì:nh¥ä[9 Ѫü:ý¡rv|Ò€îÔUl–B”y-vF´µiÓFzõêe¾tÔ€Ã;LfΜ)|°'Õºuk3fŒŒ7Nn¿ývföèN›>}ºuÔQ~\<׳gO?ÞÔ©SeÊ”)æ{œCdê`÷W_}UZ´h!‡rˆ :ÔÄ»âŠ+üûš°¡ÿþ%ÍšõZÖdüøñÒ´iSß`ßO~òùýïo »ý¯%ïw¿¼öÚkfÌeø©‡Ÿ"†-x­ôFâGºQ†pÐÂáÈTì'@hÕÄB|Á\|ñÅfŒÆ£A\DanèÝ»wî%s¾÷Þ{ç½®± )Zø°Çù¬Y³LÞ^7´ ]Ø ãâ.\('N¯ËÙ´„\zé¥Ò¤I™6mš¦Ú¨éçîñ¿téR3°>÷žç»ï¾»,[¶,kÜ¿ðë)°DKwûöíÃK4”0K|ýúõþŽ 6ý!\žLÍ^€öÖ–=þøã2yòd_ Á(o¼Ÿ™ kàØ±ceçwÎºÆØ% ûï¿¿<öØcæTÝÇlÆBl¢û-ƒèîÂ^Çñ¦´TðùPŽ?ãã3©eË–ü<) u¢b¹Ñ’(äÉ* ÞX1oÞ<ñÖ“’[o½µ øC©ÑœÛBh+ ¼’Øðz¸|‚VgCçÌdÆ}´öò&Í`C«åqÇg– ÉÏótÀ,­„ “Oª Õþˆ«6>_úCuüøtå(+gÇ'Ðêçʘº€Ùu¢ " 2$o¼SO=Õ´|â&º¢ƒ³¦±\ZFsã>j–ÙÑ¥orï:Ç=¿ì щö:DË×µÔé®ÕíÍG€0^K=  ƒˆË]ëBÈå ˜ì‚±Œ˜¨‚åj (±½ÿþûrÆg˜{Y®ă_¬lüA+f–E€þ…ƒ'Ž t´âhv¼ èT¬Ý{ï½fBJ> Ðí{÷Ýw›[˜í|Ùe—IçÎý±h%½ë®»ü…µ!ÑÈ`7›ØM.™ÖÑ’Y¯©+•ךÀBÞr"˜ü“Â’gÌ{/ë+»×êgøŒ=:ã-3cŽñŒ÷¶ÿØkÌÜsÏ=æñ_ãÕïOF\ïµ^õE5ñøîÎz1U¡”ÿõÔ—nZoêz{õ‡gžyÆïý (hŸ÷z7?ÞÏZ_@ô‡ú(Uv? þ@ÿ©Ì7’ö[½ÿ(DËÛàÕuúŠ;,Wƒ€eh°4Mî ~í«kJ×ñþd]ÇœðÕ}ºüæ7¿)X.mÄø¿úÂK/½d¢à ' nà7ê).+éq‘f>Q Œ‚*ÓL,“N:©èZ†çŸ¾)ûøñã‹®õ‡‰$:YD»þ -¡ã‚„Vl>h*Þ@IDAT…Å¢?TŽÕŒ`ÍÐ3ã$:t¨?– ¯Ó»ãŽ;²Æ bÑ×K.¹Ä7†±„…Þœ’D>I+$­F«+ý¡:~|:^€ñòfnŽÐu¾V¯^]¶Å<òˆ'ˆõ}ɆúV«®ºÊ¤éÍ"­w,aÙ™ó«ðUÕQscè5¯ @€ÁCP:‰£{÷îz©¬ýÔ©SÅ[Äo |î¹ç²Þ ‚¡µ»¸¬„¹&øƒ &Ø­Í”þ`mÕа2P–‹QÓC`Ÿ}ö1oÜÀ¢ÍÅ–ïðÖ†ÄÏ øµÖ@¼ $wœßå—_.‰x£È²eËr-zŽ÷3ÄK€?âåm{nôÛkˆö•B 6,%"ã$‹À¶mÛÌd†4V?ÊÞ´iSój¶† ãû ä-Ü+7ß|³?ù…WÅaðx±°qãFiÕª•¼òÊ+ÒµkWéСƒ´hÑB5jTì1Þ+‘@Üÿ zÖYge­÷‡×~ç;ß1?F%ݺu+j=~ÀŸÔZ¶lI(J¬ô›iðúOéþä˜ñ}û%™"Ëæ^½z™÷òÆiø AƒÌkà¾üòK#æÐE\Ÿøƒ}xñ|—.]â4•yEH¯DË0½¾3ÂÏ>ûl“k}â/BÓ˜t ÐjYÉÒF¿~ñN^ŒÃÛ}÷Ýc/~ûöíb°ÔðÎ;ïÆ"¢µìÇÆà6ø6¼cú½÷Þ“uëÖ † 0¤“ý!õ^ËRSÖ’>ó®wÞ9öÀJ ûÖ[o™@tùª¬4->grä–€?r‰¸}Np»þ\²ž]À.Õm …¾01yãꫯ–Í›7‡’fT‰|õÕWrÛm·É 'œ xÞ¸qcŠÀ¨`;’nÇí:R551“þPì‰È”0ÕÈB”K`¿ýö“½öÚKî¼óÎr5þµ×^+½{÷6¶b⊠ÀXHAf­[·–•+W:QÒ>úH0éƒC¢«.úCtl™²=(í© Z|q¢+õ¢‹.’ &ÈSO=SÎåeqŠE£‡ ffý6oÞÜ´²¸<Žõņ?ì¿ÿþòòË/×ÕŠû?þ¸»€20„C€þG¦b? @ûëˆF@"êC1¯j;âˆ#äç?ÿyÙëñE`–` Šwß}׈Óþð‡rýõ×ËàÁƒÍ20XúÝÀ°!\\pykËgŸ}nÂ!§†áçž{®œvÚiYCBÎ&õÉÑRï©Ào’TT3 ™K¿òÑ:dÈÓˆ5ÕÐ%ŒVܫՆn^Ì|íµ×dÚ´irðÁKÛ¶m]R€°¶1„G<ñ#`ܸq²ÓN;™1—o¿ývxT™Þ:%cÐüío[~ô£™/úƒ@}¶Êløø¿Ðè i!À… ÓRÓ9åŒ{±Óœì­8Åàé­[· ZÆØ6lØ`&†€BܬUÜáKb_òXº€)£qõƒY³f™Å¹/^,Ë—/7-²ÑäXzªð¬‡¥€F-ûùAЮ];³W¿(=EƬ@ÒýŸ3\H¼>/Hþ} Àä×qÞR~eûöíæK³7mÚdÄ>üq¡Vݼ{Íš53{vÿ~]oaÿE=£¥ ?Ö¯_/k×®5Çð øîÇí ZF|YcCÝà øvØa3DÇ…ê}†ûê$Ý(«ó¤<Íu“R“,GEð¥ª_®_a¬_ø%ÒCjDŸ ?~ɇ7O2` Á AÞZµü1 fj½çþ(Ðeô¾Æç¾zô‡ê2û PÚ_G´0bø°W‘€P«Ö-ª~©c¯Çzûh@`ATÁlú1 ¥…ÀFاþJßP:áïéá3eŠv ´«>hM PlÕ¾%YÃT\Ùòc@ѨأŸ*‘è÷Iö\úRô>ds€6×N„¶¿L"̆I“ XHÃð#‡"ÐÂʉÉ$ À˜@Û˜ f¼bæëªU«Ì wŒyÂ@ø÷±Aüás_[ã°…yØE€ЮúˆÍ4ûc ˆþ„pÐ%Q`>4Ü €…¢Û·oo6¼#6 HpÃ`%ýÁºŠÃÒ|þ€Ï~l:0[˜‡](íªX­Ñ|ì0óU[|ðËÁ úK">ª@úƒ¾+éîÔU–æó‡àp=ŽÃæa @»ê#vk ³)öB¥,CÔUî6úCØD£K/×¢¨»(ÒŒŽHºSŽÃÒMØÝÒó]ÀîÖ-'   ŠPV„‘ €»(Ý­;ZN$@$@$@ ¬"   w Pº[w´œH€H€H€*"@X6>D$@$@$@îà20îÖ–cí@lº·Â°¡ësZªÇÆ"Ò¢«úCtl]LÙEp‘s’m¦LríF\¶wÜ‘¢/bÆK–,ñWë×»#βâäé£+ùAúCɨRÑ%HE…8VH @Ç*Ìsµ¥‡­~ÑÕ~á¯_¿Þ¼Ù«ùÛÜHˆÎ4eúƒ’à\òÖ˜8ÐÎz±Þ* ¿xªhõêÕ²iÓ&Ùºu«Õ­­ôúCý!H#ºcW>¢#À”«!@X =>KX·nlÞ¼ÙGsÄÙ1yË Ð,¯ ˜Í£?Ä )‹‡8ýû÷7“IÐzˆëŒÇwœÉ{üøñ&Nƒ dáÂ…f¬!Žï½÷^¹öÚkýg|ðA™1c†ã‡É)Ø mï–6väýÁ‘ŠŠÉLúCL ™Mj P¦¶êk_ðÅ‹ûFì³Ï>þq}o'N4ãµ{xìØ±Á‡ cñgðàÁ~òÈ‘#À{àäÑG5q1¶Û¡‡j„$f#œ~úéqxì±ÇšóyóæùÇ£G6× ^úÓŸšcþ©žý¡z†IJþ¤ÚdYl$ݬb£…´)±TlA€•0XÅÛœ9s-ƒçŸ¾i‘ƒà»è¢‹DÇâÝ~ûí2bÄ“tÛ¶mÍ$“çž{ÎćàD¾çž{®Œ3ÆÏ>8Û]ÒX†föìÙ²Ç{¾n½õVAWôÕW_mf)/Z´È–Õ ?TÇ/iOÓ’V£,mØh[¤Èž=z˜Ò¢ûwÙ²e%•\¿ݺè®Ew¬†àýêe9ðÀͱŠÃ`S—S¤?¸\{´Ýv€¶×PÂíÛu×]å•W^1¥DKºmÑ­;tèP³×7D€hCü &˜ø}úô1³y1)ÝÀh™ÃÚù‚ >½·ãŽ;šCOÌæEž¿ûÝïô¶lÚ´É?@xbFð\`.øá‡f !Äi¡g‚Ïó¸8úCq>i»KH[³¼q Œ“6óÊKcì0áBgô"„–†qãÆ &|èú€“'OŒÑC€€Ã† ÷Üs‰“¯ûV»|õ^·nÝüÉ$ºÍ.»ì¢YJîØ>ä­ö|òÉá‡Ñ ‹É(¹Ïø‰ñ ,ô‡²p%>2ý!ñUÌÖˆ@¯;+S£¼™­…¶mÛfÄÌòåË‹Z‡xQQ¸O°+VE_>cÐÝ‹?ˆ»ÜE¢óÅÏw i ?ä“»Ö`¾øˆ«ù鳘)E@«$º¨1 y •³Q£FYYuíÚÕt}cw'·lÙ²Nœ¬Ê<¡?FÈχŸÍÍpøG’?ò×>¯ºB€ËÀ¸RS)²³˜è b€`+5nð¹à1Ò(ç:˜_¹Ïóåqé‚Ì‹=E(F'9÷èÉ©K–¤¶Ø\[þÌH€H€H€b'@;rfH$@$@$@µ%@X[þÌH€H€H€b'@;rfH$@$@$@µ%@X[þÌH€H€H€b'@;rfH$@$@$@µ%@X[þÌH€H€H€b'@;rfH¥hذ¡yM…f ú} H€þ¤Áãr p!èr‰1¾! ‚D÷Ä ¼u #ØÌZmÓ}44˜*ý>$àŠ?mæ±=(í© ç,Y²d‰¬_¿^V¯^-ëÖ­“-[¶ÈöíÛ+‡ã—=>Ü[µj%M›6 õõnQ•—þYúCtl]LÙEp‘sÒm¦Lz GT>´ô eªY³fÒ¦Mó.^¼7ŠwGT«“U¾` Ö6·®©½ô‡hÜJùÒ¢áëZª®ùƒk|Ób/`Zj:ärâ¿Bñ…ߨQ##)þÂ…¬Œ!þÀç¶µ•þ] )cúCtŒ]JÙ%p‰kšl¥LSm‡\V%Ø#P† Xözná¦F—gnjêô‡\2éåǺm¬þ”;‹O$J6l0oÂ÷€®åšJ).4[SZù~º¥‹M$@©$€@¼¿½yóææmN\¯1•n €é¬w¶ü¥´ÞYl U«Vx•§¾Å‡dÒE€“@ÒUß,- ÈÚµkeÓ¦Mþ¸o"I¶¦¯ÎM‰9ö/¼ŠW–ºGÊ8ÖÖ8×cÝãCr ¨/è%¥O$·¾‹•L}@÷¶øÂæÍ›eëÖ­ T¬ò~0áÌâECæsæÌ‘gžyF^xáY±b…|þùçfCŽ]ºt1[§Näàƒ–!C†ÈÀMW‹v·P FS7µJ•>Q+òöåë‚/lß¾âÏ>׉Õ"ÎŽ·=™ai€Æ›{¬²ß’÷ß_®¿þzyðÁÀ;ì°ÃäÈ#”Î;û¢¥P1aøä“OÊÓO?mDâqÇ'\pì¶Ûn¾ä <û뽘…ô‰btÒuÏ_ÀÏÙ³gK×®]¥C‡Ò²eKÁX@†”ð~©0¤€×ôå"/¹·Ô@fË–-‘çuo¼ñFæûßÿ~¦cÇŽ™K/½4óé§Ÿ–%žÁ³ÞnæÄOÌÌš5+³qãFÃÇû5^vz| ¶èµåoSî®ù>û=˜Y¼xqfõêÕ|0¤@ô }L(q1øæ›oqˆ lýúõË<úè£~¹Ž=öXÿþ„ ò ¼ ˜ç4 ìñasÍ5×d¼®S?-Û Ìn¸á†Œ÷K9ãµüeÖ¬YSµÉHiyÝÄ™+¯¼Ò¤é ÆÎx­² ÁªñFž}"rÄÎdàª/àó˜Ð7‹ÌP ÀÈÐÚp1†´Üáס Bˆ7Ü{å•WÌ}=–VŸŸ9sf-€HÃ'gà¤I“̳ÁøÅŽƒÂ³X¼(îA¨}ôÑ™oûÛ™¥K—†žÒÜgŸ}2{ì±GæŸÿü§a…z¡ uh Ò'BCé|B.û óîJ¸ Œ÷ŸÀŸÆ¶nÝZ<‘bÆ´?^¼.KñZåƒ>0“ðd=²9r¤LŸ>]Ž:ê(³Ð(ÒÀDˆž={úñ¦N*S¦L1çØãüÙgŸ5³e1>eáÂ…2fÌñZÍ5ä{ÅWø÷1¶nîܹ&NÿþýýY¶~U`‰ؽóÎ;‹×UköU&Yçq¤2ì¾ûîf‚ÈgŸ}æ/Ëàýw×‰Ï µ%@Ÿ¨-›r§/ØT´¥R€•’KÙsC^« xãàäôÓO7“p b-7ì½÷Þ¹—²Î±)Dö8‡Ð:ôÐCå“O>1yxcîÌ}¯Q¼îc™8q¢¢7Ýt“xcé¤I“&2mÚ4ñZ}1j¨ò>Üa‡7NϤ!U@Ú3fÌã?^0A“G°<&éPFE½ütéå3Kêô…¤ÖlúÊE˜¾:¯¨ÄùË_Ìs-Z´çž{N¼1~2oÞ<#¼06lZƒ×òã5Dº?ï¼óLÚÝ»w7­o˜Y‹ñ á‰0yòdyûí·e¯½ö2×¼1ˆÒ­[7ÓÂh"Tùù@ŒõíÛ×Ìô­2¹’ÿÕ¯~%ßúÖ·ä²Ë.3b"Ðë ¦,™`téѱu-eú‚k5F{‹ ,F'å÷¼1.fé´P¡+Ög–ŽAð²eË÷½Ùou(a™´Ö¡kwåÊ•f»÷Þ{åŽ;îðãî¿ÿþòᇚs:ˆÀ?þXÐÚ‡Ö·ßÿþ÷¾èC !Þ[‰à!”ßüæ7‚F|·k×Î\ëÏÝwßmÊuçw†•dÉé 5,`^ÔŽò±°d|‘E¤OD†Ö¹„é ÎU .F ”‘„LÄ9Å&è¤ÏoÌ„Ìö<öËœŒ8ˆŸt"ˆ¦=&Ž`" ö_~ù¥I[ïß~ûílzŽYĘ@¢çHÏ깦£Sró¯äü«¯¾2³}_{íµJåä¥fÞzë­ ìñZ9)$²•%BŸ¨Œ[ŸJ’/às”³€“è¥å•‰ A{ÿ i q-Ö;Œs«fÒÐnâ(ë -—ž0–_ÿú×QfSoÚgu–™ ríµ×J›6m¤Y³f\¤µ^jÑD ODÃÕÅT“ä \ÚE ßfv‡Ï”)@¸U#þTâãíÐM=vìØ€õ_Ο?ߟ}ŒÎà6lØ03‰"57`RG0.Ž3‹…‹.ºHüñ¬—µ{¿ëŠ=Â{ ODÕÑ$é ŽVÍ.J€°(ÞL _|QvÚi'éÓ§O"c,^¡€1A‰É1ùfCç>‡øx'0ò+°, Þ!ŒYÑÞÑþ Û ÅçõhÐ'¢áêbªôk6×G€°>B¼Ÿ x·ïi§–·¬Xn“SЇ ذd &ÆhØsÏ=Íä=×½·¶™Ðø£G6—ùË_êí¼û“O>Ù´¢eÝÒh`ˆ—}"^Þ6çF_°¹vh[¥(+%ÇçC¢îwÞ‘ýöÛ¯h™0]ÒØ°LÍ1ÇcÄÄ!¹çžköÁ?˜©ŒnpÄÇâÖ˜í\, 0À,¶å`Ð ÈnàbĽGŸ—§Ë©Ñ\®=Ú^Œ`1:¼—X|ëV î¼ÌæQ´b‰œ`Ð.d,‰ã½WØÜÂÛKм5E…f `1RÑÝ£ODÇÖµ”é ®Õí-…`)”'Ñð kâÕl•6mÄ+Ý‚cþ ø:tè`ÖøÃ½«®º*¥Îñ.»ìbÖ`„øÃŒm¶ÖAéúD¤xJœ¾àTuÑØ2P–‹QI RÞZ‰æÊúü AƒŒÀÓóÜ=& @øQüåÒIÆ9}"õF)è aPdå ,—ã'’ZÿÐ Xi@·/^‘‡Ð£G¬d¼E¬Íø=¼:Ï[ÛLÁþ…^˜/xòÁ˜1ƒh}`¨ úDm¸Û˜+}ÁÆZ¡MÕ ¬– ŸO¼Oã|* :ùÝÀúcMKgã¼}ûörñÅ›[Åò[²d‰xo1ëj:ÜÇK€>/o›s£/Ø\;´­R€•’ãs‰"€%\ò½×8XÈàÌ]ŒÍû½×)‘¦ËÁèdàs: ×0äòË/ÞÎ{ì½.Ozõê% 64‘fˆ—}"^Þ6çF_°¹vh[¥(+%ÇçCâêøã—{î¹'o™TÀ¡‹WßìV=, 3xð`ÿ™÷ß_0Dƒ FLÑç‚A®¿þzšµÇ˜¿Ç{ÌL*Á ãFQfŠþ„>=cWr /¸RS´³\€åcüD8øàƒeùòå²hÑ¢:åkÙ²ek¸Ð¯_?9ãŒ3ÌbЉ»îºkV¼BËÊŒ7N ±Ö_¾€Ö?´â~Ó¦MÍ‚h dˆ—€m>ñÕW_™µ*éñúr£/ÄÏœ9FO 7Èœ£Ì£çl]XZ­K¬þ¯«]ºf7ß|ó×kðõq '˜à &˜ñ„h5„E}1ÄG€>kÛsJš/ UÃWºvíj–§Âç zÒE€Í éªo–¶´°]z饂W>½þúëbEyÆŒòüóÏ˨Q£Ìû…ñÆ?¶FÏ>7úD.‘ôžÓÒ[÷I.9`’k—e+™~£¥mâĉòãÿ¸&-£ëׯ73„ô£™–?ü*oÖ¬™€°!^ô‰xyÛœ}ÁæÚ¡m• ¬”ŸK|À£ cú ¼Î9çœXˇwþžrÊ)Òºukùîw¿+­Zµ2v@Â. ÀX«ÃdFŸˆŸ¹­9Òl­ÚU  ÀjèñÙD@7O‹-Ìl`Œ?~|,åÃxÌÿüÏÿ”÷Þ{O&Mš$íÚµ3B¶`¶1»c©†¼™Ð'òbIåEúB*«=Ñ…æ¨òDW/ Wý•®àéÓ§Ëa‡&K—.•;ï¼3² X*æôÓO—_|Qþô§?™AÙmÛ¶5-€lý+§ö¢‰KŸˆ†«‹©Ò\¬5Ú\Œ[‹Ñá½ÔÀ‡ýôSùóŸÿì‹?tkëìa¨-úDmùÛ”;}Á¦Ú -Õ ¬– ŸO|À£«k­¡+öÕW_5cóöÛo?™ä1ñ" “1.¸àùýï//½ô’à¥ð?ýéOM«]ÎcEO±¾ß[o½%#GŽ”¾}ûÊßÿþw¹îºëdĈFøáÁœÈùrâGQœ±ß¤OÄŽÜÚ é ÖV +“‚.XR¢s!èúk¢ ¯eÃ[>6nÜ(X¦eáÂ…ò»ßýNžzê)³l Þpä‘GÊŽ;îhºñöÄÿøã-}Ø?ùä“‚·{`¼âÿà?Þ½{›Y¾|:ãkþé¤|É0ØG€>a_ÔÊ"—}Ÿ/\ºVžcO¾€öÔE¬–P–†òØð&,Õ!ˆmÆ 2wî\™5k–Y8¯nÆ×u! 5ºt÷Ýw_3Ö/”Gë&w`Œ6ˆ>l¸ŽŸñÁLñWZÝÔ*}¢VäíË×U_ ´Ï—ja`-¨['`y•€z0Ã!Ü6mÚd"D"î£Õññ!‹q|èÎ…¸Ãñ±ÜpŸ]¾åÕ‡ ±é6Ô‚6¸æ €vøM­­à20µ®æï|`ê+Ù Ö ä ø‚[Pü©Ì'U Bêæ™E€>‘…#Õ'ô…TW¿³…§t¶êhx-¨`ƒÀƒCkŸn¸¦›Ú†/ÝôYìõšÆãÞ]Z¯ô wë0,Ëé a‘d:q Œƒ2óHpøÀÇ?‚îõq4è±îõ:÷É!@ŸHN]V[|?D«­e÷Ÿ§t¿+* ÝW”" p’'ž9Ym¡M*N·ÃLÖuëÖɪU«Ìǘ؀%L<ð@™9s¦[…I©µG}´ÜvÛmfIš6mژţVÀ¸FúCX4£O‡þ=c—rÈçXj âo‡v0c™Ãü¼p‰ m¡L© åcذ ö:¡ç;wÆŽÁxwq§N̲3XZ&Ìt@úƒŽð/éîÔU–æúƒNBÃD6|îãœ=AqÔ„}yPÚW'±X„xŒÁ‡„&3è>>4Ü €µñ&l-[¶ŒDÒÜðXIp§®â°4Ÿ?èdˆ? ‡-ÌÃ.€vÕG¬Öè?>ö˜Ä P[c5ˆ™UD@ÉëâÒQ´Ò*ªššëÀ"Ò·ß~»ÜÿýòüCÖ¯_ïß³åkäõêÕKŽ;î89묳+âc†¾ôùÅn-=öØcòÈ#È[o½%ü±Yd<ܪO u¿óÎ;Ë^{í%Gq„œp Æty$úDõŒ5úƒ’àžì!@hO]8k Äßá‡.}úô‘[o½UöÙgiÕª•uåÁkïæÏŸ/'t’LžùäÁ;±¶vU†C&}©àM2={ö”ý÷ß_^ýuÓ¢f³øC Á>´ü}úé§FB¼®Y³†>‚ûÒB€È$H B€ÂMCÒwÝu—|ÿûß—+¯¼Ò©âþñ”AƒÉm·Ý&6l-[¶˜Wá9UËŒýå/iÄÔõ×_oZÏ,3¯¨9hí»á†¤wïÞûáhÙæ‚¢ØŠÞ¤?ÅÛ$Ps€5¯w @7ßoû[¹êª«œ,ÄÕW_-<ð€,[¶Œ->UÖ „Æüýüç?¯2¥Ú>~Ùe—ÉSO=eư²e¸òº ?TÎŽO’@\(ã"À|0Þï‡?ü¡i5q±xhí9å”SäŽ;îŒUb+`uµøÑGIß¾}«K¤ÆO÷ë×O–/_nZUÖØ$g³§?8[u4<%(SRÑa¿ðgÏžm&„vœéyä‘òæ›oú]~·Än¿òkÌ ˜0¡ÆåûÑõ»iÓ&³§?TV›ô‡Ê¸ñ)ˆ“`œ´–×»ï¾+ pºT¸téRó…@La(Ÿ@ÒD3D N JZÙʯÝòŸH3úCù>À'ì'@hYi!>à¿øâ éÔ©“•ö•jT·nÝdÕªU¦µòlñ)•\²ãÁ¿“&b’]cÑ–Žþ-_¦^€µážˆ\!˜°~žËöCôá»\Ú~á‡Ã1)©Ð’R“,G€Ûv‚%áq¬lmÁdŽ/¿üÒ¼å£sçÎ%3 ¶üÙZ¶’ È>JýA /(‰dìéɨG–"l ‡#SÉC -ëkÖ‚ûþýûËW\! .¬ó®!.âàúP˜:uª‰7wî\? fó¶hÑÂ,LÝ¥KsÆŒþ}Ô–ý¡¶ümËþ`[О´ L[ÇX^¬˜/`ÖíĉeÏ=÷”K.¹$+оCq0A£¾€Wv!@ü9²Nt¬ëVJ`O)”ª‹ã’?TWR>] úC)”‡¢#@ÛԧܦMÃà…^0kìáí Ø,X &L0÷°ˆ4Z5¨ Ã9D Z J wÞy§‰†¼ æ0£wæÌ™Ò±cÇR÷ã°ËÏGú‹þ:&è ?ø(x@5!@XìéÊ´]»vf}¸æÍ› 6,û¬9ç{Ðì© ,¡?ØP ´!(ÓXë–”môèÑÆmÁSÓpý™gž1§Ó¦M«ÓU¬ñr÷}úô¡èË…âÈ9ýÁ‘ŠŠÉLúCL ™Mj P¦¶êí(ø™gži yå•W² Z´h‘ :Tî¹çs]ÅS¦LÉŠ<Á;‰ñ/„Ã;ÌL" N Æå±½èöÖM-,£?Ô‚:óL  À´Ô´cåÔñA§všÜrË-Æú±cÇšÉ8Á«º‚¡uëÖ2oÞ<_0büàÀåÁ Fã±£èŽV\DfÓ"ËdSE€0UÕm_aï¿ÿ~cÔàÁƒ ‡1€×\s¹™¾×Wè $Œ˜h2nÜ8ÿä“O–•+WL›7ì"@°«>jm ý¡Ö5Àü“L€0ɵkyÙ^|ñE¹ñÆ•Ç{lQk/¾øbæ0ºxO?ýô¬øÁI$˜hrà 7ø]Â~øaV\žØI€þ`g½ÔÊ*úC­È3ß´ LKM×°œº¶LÀâÎË–-“k¯½V9äc–„)eÍ?ÌÖ–½Üâ`MA,Wº!¬Y³Æ,#“çµ'@¨}ØdýÁ¦Ú -i"@˜¦Ú޹¬ºÐ+ºwõM ú¦ŽñãÇk&Mšd–„QÓ°~‚>«×u–½3Î8COý=&€œ}öÙæpX;PÇ!€üx<¨­SúCíêÀ¦œé6ÕmI# À4ÖzLeÖµùr³;ôÐCÂïý÷ß—Ü7u´lÙÒD/ô,nÞu×]’ÛeüðÃûÂk"`)ý’1ø§¦ Õ)ý¡¦ÕR³Ìé5CÏŒIÀhà½ù C$ ¶mÛfQ^¾|¹^Ê»G<,ºl›û ‹“@°4f—Ð:‰·†tîÜYÚ·ooÞ'ܨQ£R­yœ®]»ÊìÙ³û:t˜¶ÓèA'§?ЂþÀc· 4vÛ|ZOÙôm#ÙWK?ƒdHjý!9$X ?ÐHàߨüo<*“ZšÐ"àr@kaÆ ý1Š.—…¶“ @©(K%Åxu Ëô‹/¾¨sÝ¥ K—.Íš0â’í´•H€H€*%@X)¹”?‡®ÒÝvÛM\ÝÚ_ÿúWÁ`tmDµ²8åÎ(>}!ƒ‡ül $Š`¢ª3ÞÂì·ß~òÔSOÅ›iȹ=þøã²Ç{˜I#èÒæ~倛4iâ¯ÃXy*µ}ríÚµf ü€¾P]]ЪãǧI j€QNhúør5j”y7¯«oÚx饗Œ€=þøãÄÌá`K`B«.²b}ãßàY"Ë(„ñö m ¬2ý¡z†L¢$@%Ý„§Ý±cG1b„Lœ8ѹ’â!xÉÑG-(G³fÍÌ"Òa.¡â”* †`:ꨣäÊ+¯¬"•Ú>Š%„.¿ür9à€²Z„ÙX~½ÐÊgÆ'H n€qOH~ø€GkÞÊ1kÖ,ÁÛ7\ ›7o–áÇ Z9æ³vÞPÂÀÊkþpá…Ê{ï½göÛ·o¯<±<¹nÝ:9í´ÓäÕW_5¾ô‡Ê+‚þP9;>Iq Œ‹tóìÒ¥‹<øàƒ‚·oì´ÓNòüóÏ ÆQÙ°`5·¾ÿþûå ƒ’^xAî»ï>³˜u«V­Ìú`³„21TF¢é¶Ûn¼® SßqÇòöÛoW–X Oᵃ/¿ü²üò—¿”½öÚËt_ß{ï½fV8~4mÚ4ÔEµc(’UYЬªCup!è:Hx¡Tø•.St¡ÎŸ?_n¹å9óÌ3eÙ²e²iÓ¦R“‰-¾ X9ä¹ä’K¤mÛ¶²Ã; ~Ù£L åP_ÀÛH,X <ð€üïÿþ¯üìg?“+Vˆ-‚ûðÝ^½z™ìÃ?Ü´Ã'ðFúDù~ OД÷$`/¾ ÎÞº©‰e¥¾êICËžA·*ÆP­_¿Þ¼Š çg‡/þJ_‡n¹aÆ™wÿB¤Uð¥„/}tíáË­<ø¢ÇÛ\ý²·åUp¨õ´¬©/` >¢¾`“?¨Oà‡Œ¾%B}-Â®Í §?Tþ)_ ?TÎOºG€-€îÕ™Uã_’PWøÒÄ)ľôñe_é>Æè!`­ÁN8¡êrë<ì…D‹ ìűk_ôUÈ õå ¶Ùðý1€lmòØ£? ô‡ö°×Q†ÊÐ*ãÆ§H .€q‘Np>úA/Lƒ*þª)öC=dZ~øaùÑ~TMRYÏæÚ‹sl ÕGø~¨BË_]ÀQùJ ›Õ±§OTï HþG¦BQ Œ‚j ÓÔ/Lì´•G÷å"Á+Út}ÁüãfY=ÊM¦N|µ/w_'"/TL@}A•ú€î+I8*€-A_ÐãJlä3ù ÐòsáU¨5Ny¬u $,ÿà‡½ ´ –»aAP0à¼Ü4òŇMlá‰ÏéàÊ<_}”z-*@þjÅ_ô~Aˆž1s R P–JŠñb%p×]w™‰%ÈJpÎ^ô‡ôÖ}¾’ÓòQá5(`y¼;sæÌ̬-ˆÉ é#@H_+1ý¡Þ#Ò P–Ί1c"p÷Ýw›ÉÁì°”[ƒDÒsLHO]—RRúC)”‡ê'@X?#ƈ‘Ö{ä‘GêÌÅ,R\Ç}†ô ?¤§®K))ý¡JŒC¥ ,cÅDà™gž1ƒòóe‡Áú¸ÏM É“ZèÙu]Êý¡J鉓dHO-FSR¾ $®Î¦Š–6ÌŒdp‡À¼yó¤S§NæÕvXxøaúCX$ãK‡þkrŠÒ\(?m,L€ëf“Ú;6l0“0V­Z%˜|Y¸a,ä[ Ѓ:ȼ5¢P\,.Îχ¯ý5.p㿃Væ#ÀÀ|TR| kïá-›6m2ïpůñ ®É'ž^½zÉâÅ‹ãÌÒ™¼°¦1Ä^¿§"0ÌõìèθƒYКþàN}EmiŸQ—éGK€0Z¾N¦ŽÖ>lúþÖ¸ZÿòÁjݺµ¬Y³&ß-^óàW>6|ñëqØ`èa.=õúCtŒ]J9p‰mÍ&@˜Íƒgÿ"€–mõÓ}-àà‹ B”!?míÃ^óǬî*ý¡:~q=­>@ˆ‹¸ÝùÄåvS u…P"ÃëVÀX-¨h„O€þà£àG€þ@7 Ê „7]ðÿ·w°Ví?Š‚XQ¬X° Ø{ÔX0¶Øk±Än¢&–D öĨØE£1‚‰%¶`½‹ »b9ÿýÍ—ç~s×sνø¿§î3ÉÜwvvvwæyÏÝyö™wþ}|¥0FÀ#`Œ@0¬#Ø~”0FÀ#`šÀfЂë`Œ€0FÀ:"`XG°ý(#`Œ€0FÀ4&€Í ×Á#`Œ€0uDÀ°Ž`ûQFÀ#`Œ€hL›A ®ƒ0FÀ#`ꈀ `Áö£Œ€0FÀ#Ð ˜6ƒ\#`Œ€0FÀÔÀ:‚íG#`Œ€0F 0l-¸FÀ#`Œ€¨#&€uÛ2FÀ#`Œ@3 `Ø ZpŒ€0FÀ#PGLë¶eŒ€0FÀf@À°´à:#`Œ€0F Ž˜Öl?Ê#`Œ€0Í€@¯f¨„ë`ŒÀ(•Je¡¨”ŸV™?þø#üþûï1’þûï¿ÃŸþþú믘N¥ÒºvÁ ,°@@¦é4¯W¯^aá…ÿùÏb\d‘E¢Lë¢4×u*•©”ßÕýšé¼pÍשR~Z.-3oÞ¼Fô‹^SýqÌ5È4Mžô¹ÐB "Çå$z]tÑE:%ÝÑI¥2•òóÏð±0õAÀ°>8û)E íÄ =þõ×_÷ß~ãܹsƒâO?ý~üñÇðóÏ?G™“&ŸkEò$ûí·˜A£_l±Å:uòå:|åqMžLäIÇtâ<b™޹—H!äç_|ñ°ÄKD™+½ÔRK…%—\2FÒ}úô‰q™e– }ûö ä¥äz(¤ùiZç{Z¦úKÓ<ç‡~ß}÷]‡>¿ÿþû˜G>ú”î~ùå—è”ÍqªKôL@ŸDpB‡Ë-·\XqÅc]®¼òÊa¥•VêR—èV:ë©vû>F (˜EÓ-ÚÎfzÁ«£AN:5¼ýöÛáã?~øaøôÓOÃ'Ÿ|‰VŽÕV[-vh ètrêøtö]#€U ’y^wÝuÃý÷ß _mÙìÙ³£œ6mZ$’ƒ «¬²J°Ü8Ô®~X¨°ÖAÌ!äsÈdk":ÛtÓM£e ]N™2%Zí –Dˆ:…8b‰ÂÊêÐÇ’ÎÇYDôŠÎ°>®¿þúáùçŸãÇ[l±E$æ)Á7lŒÞüÔÖAÀ°utUÈšvÕá×H¤aܸqáÑG 3gÎ #GŽŒ Ízë­‡#kñlß³v0 é#¢ãÍ6Û,Œ1"Îa«ÝS}çZ €Eø­·ÞŠHdÈx—]v |p6lX$ù)!¬E=|O#Ðʘ¶²ö P÷zÀ‰'† /¼0C}ôÑa·Ýv‹äÏÖ„üØÜÄ–EB…ž¶[o½5Ù_vÙeaë­·ŽCóA¢ƒ0ÿCÀðX8Õ„Ô‹Òœyæ™á¡‡ cÆŒ {ì±G\ÕÚ„¸JFÀTA€9&L§žzjØo¿ýÂ\‡òµâÝsUÀó©B!`X(u·^c«@H›BšNóXuŠ[ ¹×ЪF: ܉H2,xÅWÄùc¬¤u0F µà•Ù7ÝtSœ›Ë|NˆrÌy­ž'_˜UŽ,¦yiºµÑr틈€—­Që-Òf‘:ù}Ã…ü™“—wÇ!Wyw"r«¡—<†„Ô°Èãî»ïŽA‹Àãj#Pþ×Ï;ï¼0vìØø­=$A~!ŠDàÊL¸îA⾇Þ¬øfu?WC¬gÎ!‘ó"‚•d•jú”h¶6 z?8E@d‰ú¬ØdÆ|®¼òʸÚÕœ¼\Y™ÉK)·*rÉÔË[/ðîÎûdv·lZo§€hxðb•1’ˆ;Ü)Ê7$¢|òî’«¤Ü±ªœ÷ï-EIlÔÜ’VEÀ°U5×âõæ¥É÷‹/¾&OžWf"ñ ¶öÚk‡ 6Ø úüÂ%‡\­àÙÁ#ÐL`5ÄE n‡ˆø’ÄUԻᆳ…o¼q\mŽdå9–IBÉfjëRL‹£ë†·Ò÷Yæàõ?þxô­‡SW\qðbÄÕ ¾ôl‰k¸ªš®XaØ] /q~Ã{¸ ázæ€áÈÙÁÔ¬‰ø0duòK/½?r!…¸’Úa‡âŽ6¼ï˜†""hë`­µâû§x]|ІÓ5A¼×_}Ød“M"ÙÙëñÇwZàÅȹC=4ZúLþj¢‚»)¾×ÒÎ*MvØaáᇎó©òäeÙÅ£R€¨Q†ÎQ]!8f¸Ÿ¡†Ô¸Cs]~wÌcr?×®ºêªQò °×m#BwêÞˆzù™=‹ï2F/x·ñŽã]Çî2£GŽÂ[n¹eØ|óÍõ×^·ä÷ÈüDM‡éÙÚønF  ÙÍÁÔl8·töÙg—²IÒ¥8 ôÔSO•²—\Mžå›ÖW_}•¥×]Æ÷Þ{¯S…¶ß~ûŽk2_mÎé [­Ëì½÷Þ1KÇz^¶óCÇ=¨GµM-è(«ëËÉÌ"]í6=~îÆoŒõºýöÛ{üÞ¾ak!À»w"ïÆl±Ié´ÓN+ñ{Ìv³‰ïÉÌ‚ØZ rm[[³^Á¡ç¸ë®»âþ«Xa22î½÷Þ°ÝvÛÙ·^ÏC]×;2„JÈ]´Tàb‡ÈÜM|(*0ë–;œkc é*0\FÀ‚Â3˜WÅs2‚XõÒ÷ß?ZVTèÙgŸ×3Ìäþûî»O§¢Ußh½‚¶–óvõB¼yŸÃÐ/ïDÞüf™KÈ(Ém·ÝØÒ‹ ÃÈF V˜Ö ÙßOü]tQxì±ÇâPnÚ :¹×éß¿Øk¯½â<;È!áÄO¬Øh†¾èôºXÝÍs<çÁ m´QÅK<ðÀxŽz@úØ ‚ë{õêçâ"©Àoõß:h†s‘ÕCÛ*sä‘GFÊveù@9b¥ÐÕùJ×9¿ùàyóÍ7Çwæ 'œî¼óÎø[0 l~ݵr M[Y{MXw\·{ì±á‰'žÇoºJµD’• oÆG`L­€d²ê[+á´iÓ*V§OŸ>ñÜ5×\çŒvÇRÇ*Ì7ß|3^G=¨O¹‘¤.î/rÅü@æ¦AóSrvñÅÇ%a¬¢×]w]Ç%š'9~üøè\œ9ˆ”aþ#y\C…×^{-®z§‘9´C¢Ìªøô|w,¨ºÞ²uà9{öìøñÄï“ߜ綎þZ­¦&€­¦±&¯/“ëO>ùä8´ÖäUuõj„À*«¬ÒAòèÌÒ€n,à «f 3XáKÀZ—&Ðk¸ëHß¾}#¡’5--«ô÷ß“LêQ-@ªÊ…ü"üñ¨Q£âöbÙœÄpùå—Ç[œrÊ)RHP;9äÍí²f*¾äÒ2A܃@ZÙºŒ˜Í C† éÀåÒK/ç;ó)†ñ†þÓ6` äwpÏ=÷DgÕüž<Ü6êmª†˜6•:Z»2Ù ØØ ¶vk\ûZ @g†U·, ¬ð…di~¡ò‘ ײj\óþ T”Ë“²ôÒµú BØ4×1[ˆÎ:ë¬8¿g²ç,›´´“!k¬9ì5­9€*sþùçsi$ºW_}u Ê‚Š»$‚ÚŠcaÎ3ò˜cމçü§=Û#~O"€z¿¶g‹ÝªF `ØÔÛø™Ìmºä’K¢[ƒ6n¦›V†}±bV^yåN%E|Ø>+‡·ÕV[u©NdX!Q,æP`ض\Ð6´®†ŒñI© «Ž+É´maȘ¡Y…ô<î=h'A€UNR> ÷ßÿ÷:GuT<-k&uVFž÷üóÏÛ—aD¤=ÿ°/9Ö?>z´}]{¶Ô­j4&€Ö@›=Ÿaµ[n¹%¬°Â ¹MÅC@‹?†e®]¥À9‘0†@âMVY¿Èg1‡æí‰`¦åI¯µÖZqë@Òçœs¢lÀ²Â…-È ´IDATDÃm"be —ɤmÔzÞÅR™ÞGÖ¾2—wd©}O>ùd¼‡îÅýD™ȳdÝqÇÃwÜÑq'Ú,||¸ çÓO?=n/§½ÊÛ£…nE³!`Øliáú`ÀùéA'Åï¼óÎUìéÐ^àNE9y&ðЩ†2U®œdžd§\Ài.C¹é‚ˆ4]îòÆO1oò”®6¦®Ï=÷\'«C·Yï¨?‘€QíáX S  Ük½õÖ‹qÕl.#í¯6?‘ëóA„ñ•W^‰ä•ûAb©‹êÍâÈ1VPÕ7KíƒûŸ³ŠþðÃqß}÷ K,±D\½Ž¥™÷*ÿ[F '0ìI4}¯ø¢â…uÄG„gžy&àïŒÍÑ÷ÜsϸýC­‹€Hˆ‰ˆ¾!j¸vQÀ–.ÂaÔõ*‡„ð0Ÿ®R`ADë2 +̽« Q©¥KõäÔu›m¶é¸tæÌ™ô1­PÞ}÷Ýã‚“¼U’áèsÏ=7^O½XBd˜º1?O_nùÏcº¹Ô‘Ç´“&O?ýt<Çð0øfŽ‚£82ÙÙÄ¡µøå—_âPï¶Ûnÿw˜¾±‡ü1u€ òD[»µ®}S"Ðr®«]á¦G #yÑ›}Öé—²U ¥l(¸”mÉUÊ:úèñ>ë(KÙ—Rf]iú¶¸‚Ȭu¬ôùGd—ŽÌas)³P•2’×ù¢ìˆs\Çõ•B6Ç/–ɆÀbî“Yÿñ¬J;‰äï›-À(e>þþq=õ`GŽr!#„¥tÇ®×qFî:.Éæ÷uº/eøM²aÜxŽºçƒÚC0Ɉg§ûe+~ã®”Ñ5²ٰ.·l!2·G¥n¸¡Äo<ûà(e¥“N:©ôÈ#”²–øÛÉ>žâ{“÷'»‚ð>u0µ@`nš½XŒ@"€Û¬}X|°z`!~úé§!ëÀãDvæ;aQÁ©ïÈ‘#£õeèСъأ•ñÍZ†˜^Õ¢ŠùmèXÒ°ôa±Ä:Í©ÓÀó°¼ÈuzNiêÃoº«r*ߕԊO¬‰åüj¾ †»ºŸÏ7~W¼ã ™¾-R"8oÞ¼@äÅHüùçŸãB‘)S¦„wÞy'°õs®‡éœ!„šØïޝÊlƒGC pÄ ~øa˜>}zÈöø k®¹f\pñË,Å‘ì15F²GÔqJü˜à`j…€ `­õ};„ b5!b,q}ÁË“—èÔ©Ss´ˆÚQŸq8J]qÅã S¶ #OùÌ›á¥ËÜ-¬ELžv0yè¬?ËVÖÒ!0 ÚÇm„ïî¾x'ốQâܹs£»"\çÌ™ Î9–s¼ð;bnæ Aƒâ|´bÍ%Bì*E•¡ž^ðÑF?¾&oŠ `“+¨ªTdxXÖA!Ç"‡’Ê“„Κ5+®*æåË‹š4/jαЀ Õ–úÈ$kí«¯k ·€«^¶HêÅ*²RLŸ¡4’{0Ô̼뮺*ì³Ï>ñÅÍ9#`Z,ÿcÇŽ ìK¾ÓN;ŽÉó>õh ï É|Zï§TBàtœ’9åç%e•§ëô¼ø`ÿ1 FÀÀ+À¯Œ$ŽPNæ žÊU*«ó•$×1ÿ‡ÊcÆŒ‰s{ØÖ¯üøéâî`Œ@s"€•âĉa„ ÑYv¿~ýâN*Ûm·]`—(ŸzåȘþ¿S™¦iuþ:KªL9Ižƒh6L›M#®O·Ùã‚4­äóªsŽ9@ cA`e2®C&Mš'{><º Á‰ðˆ#ŒCë €~™¸ÿtæ\™;òC—Dœ,;´è’¶ì™Ë®.ì¢ÂNÌËýʮ»î-ù¸Tô‰ü1ÿ—!`;Zœ¦»sœ/“¿žóF U0lM¹ž5E€N…a`æB±((Θ1#úñzýõ×£«V(3¤„{\Ö0l¼Î:ëDwì¹ph ,b»8\ ±šœ•¾|ðAô?É ô¥A䶃•š¸Â]+7嶃²žÚ=òTÜö Cô‡®ø¿CŸä1·WºbçvOÁ;€æõi>Ÿ$äOsñLÚ§S?¹¹0l.}¸6 F@ó ±ÊM ‹FHK’ÆAÇ„cW"$‘Iç¬NÆ .!°Hà—5¸‡@¦ÇX&ºF"ŽõŽàHö–gá-wäCò„;˜Ù’²0pàÀhÒBˆúfÏa¹B¯ÌåY¸ø€è£3­ú$Í=!¬Õ1繯CuøÐbÕ¾0Fg`.µÂŸY³ª\ù_"â4+|d¡˜§®U €K’¦ŒæìU¯Ïb!`X,}»µÝ@€NJAY± Ê=M*•/ɹ”¬Ð™A$pYC +‘CDˆ#ÇC$–)ÒHÎKâßPîl´s€$C^tvõà%‹©$–T¹æ˜aÑA¦‘ávbêÆ‡ó\Gy"÷QûåŠ ðõHÄ$„ŒÈÐ|ºòRiHQ¤A“ó¥gô–êPit1d¦ºDŸÒ%u%¢éˆz¢ މ£Sò$¥g¤ôLY¬VÒ¯ÒõÖ'Ïtƒ>´š©4¿cé ‰ &阴ôL9ò)C<Ñú„ì¡K$Kl‘·TÒ¡¤t+©²"}}[ý"ìþc:!`Ø Îˆ Š(ÈB(I'©(²XMê:$)$BäG(¤ˆ’r’ê€!E©E2µVÒñaù€D¨ìJÒyB‚Ô^ê—¦A…<‚0Ï$äœ:dY]°ÂPEHjJl4<)"¦„HDJÄœ6H–kÏW¾Ò©LÓ"j#:¤ Õt©óÈr’#]’NɈ”Èq^jÚ:%-\‘Ô‰v WtEšHý…‹Ú”?–nóuæ¾\¯v‘&O¿+òyFjMÓs¥Gô¦¹vHÈ­>FH¥K>ô®:"ó1ÕçÊ“§üüõÂé`Œ@eL+cã3F td>ÒY*Oid¹H¹´Lµcݳ+™Ö Ò@'žvä\O>2íø•G}è0éL Hu¤J§-Db‘’ƒxaöG×q¬NXyÝ‘ze•îŽLë—^›O«ªo[é†|¥‘iÌŸ«vœž#ÝHÝ(')‚/‰Þˆªå”Öó”DZðƒ4Ñ~(¥…È¥ôÊ=(#™OsÜUÔ³»#UTr]›O§ÏVceýÇ.0ì"0ÕH;jJ¦Ç¤kõœôYÊ«&Ós¤ ºÇ:ÿ¥ƒ-Ò|¥«ÉôérÇÊNÕÊé|9I^¥ ,ÊIòÊEîU.¿;yùkÓc¥«Éôé4ðüJAøë|z¬twdZ†t-"uLŸ“«þ–FÀÌ?&€ó™¯0ÝF ß §ÇJÿ[I%tm>§eÒ|Ò ù2êpu>/Óó•Ò\Sî\µ<ëJª>*—–Î÷´LqJÓ designate-2.0.0/doc/source/central.rst0000664000567000056710000000050112701406241021035 0ustar jenkinsjenkins00000000000000.. _central: ******* Central ******* .. _rpcapi: Central RPC API =============== .. automodule:: designate.central.rpcapi :members: :undoc-members: :show-inheritance: Central Service =============== .. automodule:: designate.central.service :members: :undoc-members: :show-inheritance: designate-2.0.0/doc/source/backends.rst0000664000567000056710000000141612701406241021165 0ustar jenkinsjenkins00000000000000.. Copyright 2013 Hewlett-Packard Development Company, L.P. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Backend Documentation ===================== Contents: .. toctree:: :maxdepth: 2 :glob: backends/bind9 backends/powerdns backends/infoblox designate-2.0.0/doc/source/diagrams/0000775000567000056710000000000012701406373020454 5ustar jenkinsjenkins00000000000000designate-2.0.0/doc/source/diagrams/README0000664000567000056710000000024212701406241021324 0ustar jenkinsjenkins00000000000000Summary ======= Dia is the preferred multi-platform tool for drawing images. Initial Dia files were built using dia (0.97.2-15ubuntu1) and dia-shapes (0.6.0-1) designate-2.0.0/doc/source/diagrams/Designate-MultiZone.dia0000664000567000056710000000725212701406241024762 0ustar jenkinsjenkins00000000000000‹í]]sÛ6}ï¯Ð¨¯ \|WM:MÚÎîLÛÝNÚÙ™}ñÐcsKK‰Nâ}Øß¾¤ü!‰”( ìî4*4çœ \ß~÷ù:|LËl>{=d„él2Ÿf³Ë×Ã?~ÿé•~÷æ«o§Yò þ¹H®ø³¥»z=¼*Š›oÎÎ>}úDò»eRÌ$ÏnÉ2=û_’çÉÞt6|óÕ`ðôÓ¤HÜg«O“¢Xd·E:˜%×éëáE2ùór1¿M‡Õ]«û&ó|¾|Lò×ï?”?óÕcÎÖž³ãÙ7Éez±H“?›MñÇÚc}“.6{}3_fxKqw³uKÃsÜŸOîYݵěf—o¾þ^|]½ÒêƒÇgÕ½h#Hq,.³Ù6ÖM^UXÒKµÐì¾N‡»è.ïnÑ/\¶<¿™/ŠE’Ûóyž&³ µXܦÇã,'IŽMlW±:”âCVó=ïÿ!É—m P}üÐÛí¹—‹lº»ã®ÝÑð”OÙ´¸:ÿ¨ºª§ßzúÇl™]äiÝÛg³ÂÛãïü<~óÛ)Ùûñ×;¶†êiò05©Låáòpy›MÓåžf¶~OÓ®V·í«õÍûÚVLõцX—yr—.Vû(ÓƒÕ¼bœA2)²÷WOêÄÝ~³Vó‹ÿ¤“bUüŸòù§ÉU²(¯o矇¶MI6}=üÝW7ø<$Çåv;»™?´4ΈZŒ$¡Ìs|³v`u]rR$³Ë<}Ä#A¬ÆŒ¹!Z[5 Š+}<~š§×ç“ùb¶f*¸,™h)‚ ˜¦BJ¦¨íˆx•f—WÅNêÓDZ¦ •  V®éP«óÅ4]ì/&%TÒêG I¥¡ªƒ¦ÏðK<_§žzú±î¿¢~5ÿt^ã°Cˆ›d:Ýc (‘Ç?¿H?uµµNª[w5ÕLi¨7îÜpß Þ{ç«7; ù¬¨‡sÿ2ø\gù¾W2[ËâÎñ+aõËKói‘M’§ÕwÜ{Ôt¯ÚoÊÐõÑz“ªkÙKNÙˆ d/jºcnw²Æ0Òîpè¡/g×iÓWÎn¯k ЬZ%ßk+±mÖß?~ù•÷}‘iö2/Ú DH`# „1áµñh…G•€1WD–×€­‰wP‰ë´HösÏ4›=軯Jm§ï"¼œ£_qVÉH.©°< †°i)¬·{”u»ÃÐæy+ õ±«— {?üúþäÊg¶¥ïÕÛy>íQÿÖÛ¤V=éŸXõnF@¬‡ QÛ `ÍŠÅݹ Wç³æ1W/#®Óy?8éç¬ðŒÔÎ=ìÞÁ“ƒ ͈q"ÀŠ^„®ð¸¶ÂEïŒrô£ñíEÝý¸ºKDÓœS)¬2 3=Ƚ]Q«°VRÞ¥VÛGïlÆ0a)cŠA ªOã.Þ9Nòè0Næ0$A&“.ÄVŒÙè0Â…ØûE’û ³Q£ÁÆddÉM ÇîA"ƒç¢ŸØGqÛ*¤`Ì jŽ É£BF… ªßÿóïQO©Ž›Q…üÕ1œ:¾GQ™&‹)Šãï®û<ÉK[©£ð¤Ž\)3’Ä2 ¦y¬ð8P0cΉ–£^Q¥µyQLôoçÀN0ÖÜb¿,¢ý~,_n»=¾o‚ö”àªOž¤¼øI‘>€h¦µË‘Vèà èR],”x\=ëЖ)0Zñð‚·Ç˜˜S`¢ü÷*ÿ ÓŒ—90Òh AŽA”æåœ¡ãÚ†¡{Ä㬃 ÂíB‹õ²Bˆtjn±1y¦!ÈáI~Ú¹q^æ£Inz!7½Â£ÜŒA^^Ê%ç_F’Ÿ·JI~1É/&ù=³I«Þ͘õ‘èðc’ß Jò3¾„UeÊ›²}ø.*4fÇ`ˆÕ\” ~ªs6AKe÷PؘÞ“bz_ôµ£‡Òê2½O²˜ÀpÒô>ëK)s ¤½زÄ3ñ$ÿay?é¥À1Ã/ŠdÌð‹¹% ƒo—¶¬mœ^ó$`˜—M`0ÚÒ€Q—Û…«ðêð(™‚XcJ(%J1SmC{È‘÷Và˜3`bLœ}îuöû63Ê ˜|…(ѽîãeü9PÍØêð#¼ˆ¦Â£RÛ13„—×@q3ÄÞ*5ÎÇâ8CüÌ‚T¦V½Ûms@ã ñ‹!fàÉBºÚ…C‚ßïÃaÌ,Æñ’W»À€îEܽ7ÎÇð8KýEm„­™*g‰1FŠþ┳Čûв‡rÚÖ*ÖK”­*<@¼‘4Ÿõ{)oœ%Ž"g‰£@n $`îöÁnò”‹0™ð'l$‰±Àú "+<ÐFð1F µÃ­Â4ð²Ö`²8 v‚Y°æö×`¾¨m`äúÁQûÉn«éPÂ5Y¢¥|:~ÔTŽV,WËq%E ± „rÍGÌí#ÙqÀõ@ˆ"Ö:ÿͳü,²¶#—þúÔ„ŒµÅ8Û«•dø‡`B?݀ˆ×?®Ùçïsù‡ l;ü]þþ'oˆe;Am/§íòIv‘^Kí¨¡‡¾A­~ªž‡‚n+gÍêJ¦-1F¸•Ð ®N3[)æ¡@Mj¹Û®7«^½NÖŸ`¸-cǨ–ò ZÒq:eK… +[ÂTHF 3æ–nQ·,¡ÚÈÀºÕ½-… $J–Äšº¼EP¸8FË\Ijfù±XQ·¢ný¥uË ¨3í’ÅuÔ-ºÕbpI{Ð-K•176¬nÝ#¸ÌF7DÀÊk«¥xþ,òÃÛÁ»üvY¤‹È'¡ù¤±Y~ |BðIÛ±¢æ‘"/öúÇ<Ïn–µéئ3Ui"¤Ò%XÅCR"Ñ’PÜ-*íˆ"-@P‹í£­,6QÖ2©É×e5 :6„^Þ -× cC‡yl.¹”œ[l„4×ö%¨å U²ÝÔo ­Ü=é@+ ê³â¥÷†h½û²ÞÖƒõÖ PU\›¡,¬õ¾GBfÎzƒ¬®­õüÉä—ߢõîÑz×7Ëh½ŸõÞ½hgŠR„YU¶ΔIQˆ$*$PÕ®P^£udòH¿³±æ±ÅŠÇ†ÞG¶1ô" ßµ¾ñ°úµ{ áˆúU{×4>_å‹6º7]uTF„06úè#u¯a‰âþ ™C@ê'úE¨_–x$†-g]µÜMÑX.K!¢2äH¿CHiÝZP^ƒF/W˽TaÔò¨åQËOGëUGE-çFD-Zþœ´ºj9Ø®]š  *ƒj9"qS!B-熈òºŒË_°–{©Â¨åQË£–‡Õr®VµŒË£–G-ïWËÛ¥·ïŸ+"Qj]æ—2ät "a®¨de|n sé-J² +Ÿ¼2¦·Äô–˜ÞòŠå^™Þbd—÷¾$j‡¨‰Îª$F)Uò½’!ãTb+ &]˜ª˜ÛϸõAãH%Œ‚- Ú_& Õ˜ªÖJYi¢ yNØü9›ÕŠ™ô1ƒÊ¥½bDó°› Pδ-¡CôØ»kQ¢…åüÈq¾É|6;OgÓ²Pǵþ^J ¾š²\ˆ#¹[Ðäfó“3:ŒkîUŸ‡ƒQîŽ]v1›ž'‹ÅüÓñIûž|ž§³ËÝ¥‘]!öÖWKרÒr f¹¥a÷ÿ2¸Ân»J®-æØK9ÿÙm$´Õôj~›Ýÿ6¬ÿöV[Üz'OÜ¢<,nb õˆÐŠ©°™–† $:e·àm—;°= æ•Æb6ïb·µGfd•È*-Yåž?/h£ÂŒ»Ó×ךÎÚ2 ˜C’@ÍØSéxÁ0.Bû¦b6Ÿ¸uÂjä…È ò‚=-ãjÀ•ë/RKa@¬t¬ ±ÝÚ1KÎJ» ˜–i¡±˜õ· `Î.yì6H‘"-¸0âD´`=¬×âBc1„ ÅÂFT`ØŒXêÂEÈ Y;‡Ü>Œh*çÎÓ¨¬ÔÑ.D^èF°ubP=§>Fšfp‹œ¨ 똢¦"mÆx­Ñ)8äãr¶7 M嬿U¢ap/ª¸ŽÄ‰áxb8/øXæ†÷G ‰V Â/PÎeÙÝ„nBC1!Jd5žñx¢3ý¸oéÅ}c{ÖL@k”o¾K<¾Â+Ÿ¸ÒM iÛÅ5>+÷í«RÛ™opfÐç ¼ …Ì·a¤ÊjÊuŸæ{{Ô+zïè½£÷öí½•ïÍ 3.qIÆDø“Ôðܦ¬rÞÊyO´j/ÊxÿðëûÁo·é"K£í>ínn¿Ñu? ×½Oz_¢òî$ªË<¹Ko¾ª.ðÿËErýæ«ÿ‘"¤ºïdesignate-2.0.0/doc/source/diagrams/Designate-Simple.dia0000664000567000056710000000572412701406241024267 0ustar jenkinsjenkins00000000000000‹í]]sÛ¸}ϯÐ(¯ àâsµÉÎ&»;í´Í6“túè¡%FfC‘жã>ô·÷‚”cK$%Š_I*q&”AÏ=¸¸¸üù—Ïëprã'› Ž^N¡Ó‰-âe­^NÿõáfúË«g?/ï'üY%Þz‚gDwôrz™¦W?ÝÞÞ’ðnã¥qBÂàšlü³ÿyaèa¡³é«g“Éã –^ê¹ï¶ßzišש?‰¼µÿrzá->­’ø:ZNóRÛr‹8Œ“ɾœ>ÿ˜}¦gÛjÎvê9P÷•·ò/ßûT]5ŵMª¾ò“ýj×Wñ&À"éÝU¡HE=îßGe¶¥6X(Z½zþ«xž_Òö‹‡ºÊ.´$]{É*ˆŠ8Ø7aÞœÎ9v†´ÆR-4»ï“Óá.†… ‡…K†… 6çWq’&^!/â8ô½(GM“k¿9Îfá…8Ä5«E+>i¹þ^¸©Ó€üë/OÛ©Oî* –‡ÜµÜËôòüsOÝ•×~×Sí7Á&¸ý²«¢´³êﺩ~ÿîdìýpzËÑ×Vi–Æ—¾<Ý<¬®ƒ¥¿92ÌvËTÔt¹-vv¬×÷ËÕí˜ü«=cA„ÞŸl«ý`¦'Û¼eœ‰·Hƒ›û£G}_üÇ_¤ÛÆþÆ·‹K/I'/&¯ãÏÓ‚$X¾œþIw{k¿}Xa¡»®â/cŠKÂ%ÀL£¬àû=Qä‘*˜‹‹}”âE«Ð@¢9C¤¹@ÂWÜΘ!BHÕ Ùýõù"N¢¢h躑TÆ1ņ~áM¤´R3#, Ê´ÀºôƒÕez ˆäŠ *¹•öáEœ,ýäXÓ(a4ÿ0a)cŠ5ìÇ Â›u¾K!e$bÝŸf›Ëøö¼D#§ \yËå®ñ/t™lVsêN§G}¯LUOdx§ÜžZ®ÐÊ L•Z‰£´ È}?ùè­ƒð¯Ç‹6ÓÉ&½sLˆ$–Ÿú?¼ñÓ`á=&ìÓ¯ ðÀ”ÞCw?¢è.½–±‚¼ÇfŒ¡ÂÕ²ÜþsS9?£´ ÛU´öËï©]¯K4É!URfX«ÄÁÙƒ%¬2ïÑ´,½d‰–ñƒ{ÍÏ·¦‘µ5špfÆ g\š-㈩h޼nU Z7’Bþ¼ò#¼‹O“7a|½üŠŒbŠ”òâu.á-˜à`Æ4ë›WªÆçS Ú­TͲKÚV.Ž<€uØê¸çmÙ $¡FŠ™&”¡z¤+‡ˆ¤ˆ•ˆ4C´¢bfòã>…|'¬#ä ÷©Ý‰ÝUÓü»Ð®oýç_TK8¸ÂVÄXm‘˜„Ç´0*ìnlÖ?Y‘–Èlhí»f…œ1J¬±²O"‰-X9Œp#ñР5E^û©wŒR–Á"íÕ¿ÕEÖòoaO gKPß‚VœB6²¡ ƒÈÌ f`Ž®:³öéâˆAÖ€Ø]îýÍzÖW™yªÛ´à²/]¼éXM°=ƒÅ¾}uñw?ª¸`‚3FµÆ €¡ `÷fÈ­9ب-N³?†ÁÕùeœÿÅa…JâÇì-jŸ ƒ"ÅÉÞ@6×nåߟ6æªnœ¢í%˜±3†ójЯöå±`@,“zÆTvܳ:jßÈ:êH!”¶œ2iA#`ô Œ„æ6þ}}]¹Î 98>bÊÀhæ»v!”[0ÙÛe ËÈ]ݯÛ[€CB f…vÞ&²ã{öz·oc=†¼n¬¥€*[áßÑ€¬…{ƒÌ”xáhòa†p£dfÌգ khÃÜ“}µóíXµ7Áf£EË‚&ÿ¾D”¿¸:£Z´m%w”…“¤mŒÕ<¼¸`á*lœÃÔ5”ÕrƉ”‚‰æ°ç&¯å(?£ÜšöØ«¥6µÀš(a}L[Äú),_ËHkZì)ó§ŸæDmYpy×âŸSwX”ùÖkx×OÞ(R©ºß”Rêg?aÓÝ®•JG_›ý+'ºûz€*qú5ê¶¢Ñiߨ;10‚0†3 B%“²û’ÃQ"ÐÊÈ9XP°Nm_.XÊÚS„m1ºcòæz“Æk¼/•÷ ª/r;’¹M®¦Têž.v›@ï)ã·f™ê­©{›ÀUißcl}Xe—+à“w¤íÇEŠŒ<íòoiìî4·é‚…$À4dòZjl﬘!*³E”ÆÎ%*T¦]l¯BÕÍž†ìî°cë oØå$\x·iä(¼Gá= ïoOxÛN¬Œ"@ ra` ï߯lñ(>—Œe>· ø÷$½{û~òîÚOÞ_Mx¿£òþ®”wåŠíï!rüÆ/Yµe­ÓMŒuKš¨Ñ´ísÙÖ!‰-·ÚŸ–(¶™%†õ¹nÛI#ëíV2LiŒImUºï­K”¦RkNñ¿z\·=eÝ$H `©´À5Œo÷·×ãî0K¸ÂmtIQ$ß<ŽK¸ý…!±ÖÉ„!”+pI´1²_ƒfõ ŒœKJ4ãv1¹ã^ Z¬cÐ8Q\ËG¬?Æ!qH-ì×Û÷£Ì€A&·¹›ŽÉnºNvó÷ *‘u’?BP5Ó.‹ƒ´=0Ô6Ü*‰HJY`s‡¬¤šá×’ò†3²EEç~´ÌZԨŢx¡ ¹ÈŠÚ†yxpì,®ö/§,£c÷[\©Ü{ø›FóFËs/IâÛæ9RŽÕ|úÑêpkd[ˆ£ýUÁ4Ðøøm æëþ7“K|`·)ÎÒ8Kï2yø-ÞwUw%'³íÉLVŸ}O5{×Ô«t±¹T¶õÊ*ÛkvIFãUÄÜ[áBa‘T gN©jeII¼L+tVTZ6rÊÈ)9E´âÕ§t¹ÁD‹jš&f@˜åÂô¾¨æðÀäxÌš9 †Ï¸ F>‘¨Îú´^̆#F3%pn¬-XÓ{Ìr²’†rÄÄûˆšt¸˜'À³qZÌFËè‚1hã mÔððÊ. ã.Íg–õn]YžE5Ïç¢Ì%YTý“~7í¬Çø’®5c’+ ÆÐ6»Œj2þ!—ïÉïm)wûöËùCFµ]À‡uî·@ô7ÿn“Æ‘?F}­è!TyÒ pv ŸpÔ>ë1vètÃx ‰#ëd·ª%\™mŽŸþ÷!»G›g~éBmžÆ¬«£®¬9çâ„iÅk‡sLóþç\ãk ‹f†UK¿t¸‡bx=ó6¾ñÎÞú×iG“ßoÐ0½¥ÍW”6çµc£²é2*zô”ôï]c P·Ž,pÙÙEžC”è3E—"Šª ‰Åç  3:wcȦ‰³êGTµ³*a=d¯Ð°RË€ã2`ãeÀ½…é›S*šY^RäÉïGJ)¥Ëp¥6ŒÂ†¢N»Ð)(†ÈO¬ˆ´J?p ê­U†¬¬@§”¶ó€NIe$•–¤²݆TäP¤Ò~³¡% ¨ÍÒCѦQÄõ6Z7ܳDTL9ÇcLgï²¢ïÉOe;ì;j³5q$•‘T²4rÍ=*ŒížÌ‡"•ÖÀ#Ôf¼ùû êqŠËÖh3¡¢,CN1„j·}Bá|¤oRÕÊ›y‹}Õ#£ŒŒR”)¦ £è¡¾+FQŒç°¸» îÕ,†°âÛa”û|@†€ed”¯Ã(´òän¥"q"oÿ¾B|È´43T š‹>7©ß#¹—> kçÜ:qâVl¹;þ.r^xÞ›öB*‰ÓSš‚– lßi/*æSH{A‡{Kl!õá‰vaŸ¨òãлó“WÏòüY%ÞúÕ³ÿN "ŸØ™designate-2.0.0/doc/source/diagrams/Designate-PowerDNS-Detail.dia0000664000567000056710000000464012701406241025673 0ustar jenkinsjenkins00000000000000‹í\]“›8}ï_A9¯>ãéLM’Ú‡dw§’©yì’Úfƒäîxö·ïØÝÆ€mÀx’ ®JªL $Kç]®ôãO_–¡õ¨’4ˆ£»²‘¥¢YìÑünôÛç_^‹ÑOon~ôùü›'riÁQj¾ÝZ¯~¸½}zz²ÃM*uœØa°¶Suû?†ò ÝŽÞÜXÖ~¾ÔÒ\Û^•Z'Át­•É¥ºMåìy¯#”—Ú–›ÅaœX2¼½zÈ>£Ûm5·…zŽÔ½’s5M”ü£¾j>ž×¦ê•J«]®â4€"z³*©©Çü¿Wf[*…BÑüÍ«Ÿé«ü‘¶^êªzÐZ½”É<ˆÊ8Ð7aÞØcè æ Ïq©‹v}Ònz]¸ðºpÉuá‚ô~':‘.CNã8T2ÊQu²VíqÒ™ aˆkV‡V<ZÇ'žÿA†é9 È/?϶¦3wžþñ‰[(QSËSàëÅý—žº+¯}ÓSíALCUõôA¤/Výæ2Õþ:{¿ÜÞq4äµÕʃ/S¬¹<ÌׯÒìX¦¦¦Å¶Øí©^?,wnÇä—Ä:ƒåF%Ûê߾ȴµý·ŒcÉ™wßöú$žþ[Íô¶±¿„ñÓl!m½¶ÞÆ_F/&,Hàßþé{ë°}Pa©»Vñó˜ÂĦcÏ&ì°Ê R0ÖŸ@d4Õ3adB]›á+n §Bµ¼ŸÅITö—kS’‘I¹]ÏbEm‡9{Ôk¡‚ùB׃!b‹K€MãÄWÉ©¦96ÚÁPÏAˆ#Ü.]ÄO÷Nõ´ 7AYIß/Jp©=-ÇV_J?Ê!”©ë‰ÌˆÊxÖÇz„æë*Éoý» •frŸ6›?Ai4Wþ&Â)~h7Ð"ÉU‘a6ÅlŒ¸MÝnXEõ;²Drœn@à-çÑRUÿ *Z/+lÁ1cP¥muú|û"FíÕ uU'‚r ˜ÂnŸe`2Ì&”ÛxŒqŸúÔ½UçH¨†ëíÜ>% ÙÄ¥{`l¨A¢‰j&Qž½U¨1 Õ^£~ûøÔé“–ZUèî¬O,Æ@~´Wyò2ˆ …u€¯“v`K¥å)¶ðƒ™îUûºöØ9ÒGm·(}´Oé³E»Úà R÷f>®“ò¯R?K›@<axDñUÁ×+AÿŠŸTòþŸþD)e-zý6ýïR(LS:FØftУ“zTG"‘N6÷&ÞG‡娷jâÇ}#¨/¾FÓååßÂ0X¥UN:K¸°‘À «Âváö)ã€D ’k{L¸ 2å¹bŒaíDéUu/ÑÈs”—ÛŒ3X‘.s‘‡½•—ØX`æ0.(rVœMVœ„Æñæì×ûväÿæ½Ôr*S5ø€ëùÎÈyà'p‘•)¬I#_&>¨Ûg3?öŒ¶ÒF;K1aMl£^§ ŒÙ„0qf0 ùBZÝ¥„çr*„àØ$ÚPÆQï±­Š±ø=Їs½…ÄcöH‡sãåQN9È˼Óa3€#q g€ý}æÉ‘°ðÄ Û㜘šùÞk Â%yŽá&¶K0Û3¦½Fº¼¢ ƃåþÎ^ò¼3Ñ Æú:Æ»Y4ÛTP1øêKg%Ô‡øT ÆÍ’?õ¬b"Gr8õ2C”ޱqqéYź7ò<ãXFO8Àó„á~_Ø@ÿa×Y!×Vž‡ÈÑ79zÿvP´k*pF.í:‘"·³š™Hº›/WpÛôâóÔl‡äØ.fhbF ÅYVƒãbþÍ8dë)ºSËLÃ¥cK/”µ‹Q[þ6FmߘKæJZ³8zæëDù¦ü:UÙ=óå&ýOh­Âõ<ˆÆ7©©IjK®õ"N¤Ù'Õf*Huln"KZ7Ÿ~ý`íbáöŸÕ;·ÕÍ’!õÕ²N“¦èNš$ËÖã½ÒeŽá8l‚aü™Õ¢€køˆ%|\‡:X…{œD)4n´9§º£¿ê{¦±±u#S+Іì`²û¯ã(ÜØÖg(—óÝŽW³*dd9UPrëh Æ ÖåùðæÔÃ:¼Jû` á:T<°fÿ¬Yš&_~Í|ù!ˆªB&^g¾4áwF³ð;w{ üA™©Ä„¢ ñläRb¨“¶üƒw‹îUäg-jÕÎÊlX„iÆé”Ñ–ã`¶:|žªMÓSO†6Š{ áÓ6ù÷2Iâ§öƒüTÍ÷¡ŠæÇ[úBœì¯3ÌPSYª]ZÒêÝ_¬LØ­Œè8{1g½ü~w^x7£íͤþæ<ÒeHußÀœ‡ÐÍLï÷e"·]æåHˆŠ àj ·8½sJu+k v Ø|2ðIŸ&|‹7ÓkÑIç§Á ¤ÞüªãÒ#¡PÇv¹ƒ‰ L&4ËÎ2©æõL'µ­¬)š…<Ø@'´¦tÈ'Wã|N ”âmÞ퓘 œ =§)¸ŒÐ,oŸSÞ?+T·óHFp— 3 ÌíÂ-ƒè°n¹§‹,[0Ûå&ö¼páÌ{°v ç Î3Io½Fh¶p©jgMQ×%ÛfI œ2pÊñ`Èeˆ¡æ¥ê¼iügfÇ¿8&}îGÜ!9Yö¡Ë&˜SdЄж¢þgl³ÌA{0ò¬÷JË௚½ê9åïâaQ\°÷ñf§v¨ïw¾†÷;&OpU.Ù» ÅÀdïÂxí[¿/‚Â)Ï„ÆNµY¦´Ê¯\Á™¡Çñ8iNj‰ÙjOô@’ºVR¼<ç&âð~ÊbÓ88Då¬cTšbTgçöÙ­•IºåÌYfS$BøÅ¡”x+ˆ­´¡#Ä\A1ˆÑÂÁbϼ®²q \+ÌÒ ,gQ[Ó⫎z9ã°—Æg^׿!_þ|í¬÷2i-ÃÔSõåàƒÕý"N‚ÿ‚àËðBGqþ5ž¡g¨t=5'—«®Ge—…§¥kæa{cb‹þÅ%B<3ÏŒ`ÑJlãÜTm‰Oç&Ö¹¼ùÙúu­’@¥µ†ù¨»:ß4_È6·yšJë\•E=³!šæPc—w‡.èóÆl;´*ÿ|¦ƒnWç¢O‘óq¿^í¥Ÿ¥è§9êä–_y¶Õù×ì¼÷77…áßÜü™×z—4fdesignate-2.0.0/doc/source/sink.rst0000664000567000056710000000025312701406241020355 0ustar jenkinsjenkins00000000000000.. _sink: **** Sink **** .. _sink-service: Sink Service ============ .. automodule:: designate.sink.service :members: :undoc-members: :show-inheritance: designate-2.0.0/doc/source/architecture.rst0000664000567000056710000001024012701406241022070 0ustar jenkinsjenkins00000000000000.. Copyright 2012 Endre Karlson for Bouvet ASA Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. .. _architecture: ============ Architecture ============ .. index:: double: architecture; brief High Level Topology ----------------------- .. image:: images/Designate-Simple.svg .. _designate-api: Designate API ----------------------- designate-api provides the standard OpenStack style REST API service, accepting HTTP requests, validating authentication tokens with Keystone and passing them to the :ref:`designate-central` service over AMQP. Multiple versions of the API can be hosted, as well as API extensions, allowing for pluggable extensions to the core API. Although designate-api is capable of handling HTTPS traffic, it's typical to terminate HTTPS elsewhere, for example by placing nginx in front of designate-api or by letting the external facing load balancers terminate HTTPS. .. _designate-central: Designate Central ----------------------- designate-central is the service that handles RPC requests via the MQ, it coordinates the persistent storage of data and applies business logic to data from the API. Storage is provided via plugins, typically SQLAlchemy, although MongoDB or other storage drivers should be possible. .. _designate-mdns: Designate MiniDNS ----------------------- designate-mdns is the service that sends DNS NOTIFY and answers zone transfer (AXFR) requests. This allows Designate to integrate with any DNS server that supports these very standard methods of communicating. designate-mdns also encapsulates all other forms of DNS protocol that Designate performs. For example, sending SOA queries to check that a change is live. .. _designate-pool-manager: Designate Pool Manager ----------------------- designate-pool-manager is a service that manages the states of the DNS servers Designate manages. The Pool Manager is configured to know which DNS servers Designate manages, and their type of backend (PowerDNS, BIND9, etc). It can also divide those servers into 'Pools' so that zones within Designate can be split across different sets of backend servers. The Pool Manager is also responsible for making sure that backend DNS servers are in sync with the Designate database. .. _designate-sink: Designate Sink ----------------------- designate-sink is an optional service which listens for event notifications, such as compute.instance.create.end, handlers are available for Nova and Neutron. Notification events can then be used to trigger record creation & deletion. The current sink implementations generate simple forward lookup A records, using a format specified in :ref:`handler-nova` configuration. Any field in the event notification can be used to generate a record. .. _dns-backend: DNS Backend ----------------------- Backends are drivers for a particular DNS server. Designate supports multiple backend implementations, PowerDNS, BIND, NSD, DynECT, you are also free to implement your own backend to fit your needs, as well as extensions to provide extra functionality to complement existing backends. .. _message-queue: Message Queue ----------------------- Designate uses oslo.rpc for messaging between components, therefore it inherits a requirement for a supported messaging bus (such as RabbitMQ, Qpid or ZeroMQ). Typically this means a RabbitMQ setup is dedicated to Designate, but as only a single virtualhost is required for a normal installation, you’re free to use other RabbitMQ instances as you see fit. .. _database: Database/Storage ----------------------- Storage drivers are drivers for a particular SQL/NoSQL server. Designate needs a SQLAlchemy-supported storage engine for the persistent storage of data. The recommended driver is MySQL. designate-2.0.0/doc/source/getting-involved.rst0000664000567000056710000000356012701406241022702 0ustar jenkinsjenkins00000000000000================ Getting Involved ================ #openstack-dns -------------- There is an active IRC channel at irc://freenode.net/#openstack-dns, where many of the designate contributors can be found, as well as users from various organisations. Weekly meetings --------------- There is a weekly irc meet. The agenda and other details are listed at `Designate meetings wiki page`_. Currently the meeting is held every Wednesday at 17:00 UTC on the IRC channel irc://freenode.net/#openstack-meeting-alt Contributing ------------ We welcome fixes, extensions, documentation, pretty much anything that helps improve Designate, contributing is easy & follows the standard OpenStack `Gerrit workflow`_, if you're looking for something to do, you could always checkout the blueprint_ & bug_ lists. Assuming you've already got a working :ref:`Development Environment`, here's a quick summary: Install the git-review package to make life easier .. code-block:: shell-session pip install git-review Branch, work, & submit: .. code-block:: shell-session # cut a new branch, tracking master git checkout --track -b bug/id origin/master # work work work git add stuff git commit # rebase/squash to a single commit before submitting git rebase -i # submit git-review Coding Standards ---------------- Designate uses the OpenStack flake8 coding standards guidelines. These are stricter than pep8, and are run by gerrit on every commit. You can use tox to check your code locally by running .. code-block:: shell-session # For just flake8 tests tox -e flake8 # For tests + flake8 tox .. _Gerrit workflow: http://docs.openstack.org/infra/manual/developers.html#development-workflow .. _blueprint: https://blueprints.launchpad.net/designate .. _bug: https://bugs.launchpad.net/designate .. _Designate meetings wiki page: https://wiki.openstack.org/wiki/Meetings/Designate designate-2.0.0/doc/source/install/0000775000567000056710000000000012701406373020333 5ustar jenkinsjenkins00000000000000designate-2.0.0/doc/source/install/ubuntu-dev.rst0000664000567000056710000001736612701406241023172 0ustar jenkinsjenkins00000000000000.. Copyright 2013 Rackspace Hosting Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ********************************* Development Environment on Ubuntu ********************************* Designate is comprised of four main components :ref:`designate-api`, :ref:`designate-central`, :ref:`designate-mdns`, and :ref:`designate-pool-manager`, supported by a few standard open source components. For more information see :ref:`architecture`. There are many different options for customizing Designate, and two of these options have a major impact on the installation process: * The storage backend used (SQLite or MySQL) * The DNS backend used (PowerDNS or BIND9) This guide will walk you through setting up a typical development environment for Designate, using BIND9 as the DNS backend and MySQL as the storage backend. For a more complete discussion on installation & configuration options, please see :ref:`architecture` and :ref:`production-architecture`. For this guide you will need access to an Ubuntu Server (14.04). .. _Development Environment: Development Environment +++++++++++++++++++++++ Installing Designate ==================== .. index:: double: install; designate 1. Install system package dependencies (Ubuntu) :: $ apt-get update $ apt-get install python-pip python-virtualenv git $ apt-get build-dep python-lxml 2. Clone the Designate repo from GitHub :: $ mkdir openstack $ cd openstack $ git clone https://git.openstack.org/openstack/designate.git $ cd designate 3. Setup a virtualenv .. note:: This is an optional step, but will allow Designate's dependencies to be installed in a contained environment that can be easily deleted if you choose to start over or uninstall Designate. :: $ virtualenv --no-site-packages .venv $ . .venv/bin/activate 4. Install Designate and its dependencies .. note:: If you run into the error: Installed distribution pbr 1.1.1 conflicts with requirement pbr>=0.6,!=0.7,<1.0, try doing pip install pbr==0.11.0 :: $ pip install -r requirements.txt -r test-requirements.txt $ python setup.py develop 5. Change directories to the etc/designate folder. .. note:: Everything from here on out should take place in or below your designate/etc folder :: $ cd etc/designate 6. Create Designate's config files by copying the sample config files :: $ ls *.sample | while read f; do cp $f $(echo $f | sed "s/.sample$//g"); done 7. Make the directory for Designate’s log files :: $ mkdir -p ../../log 8. Make the directory for Designate’s state files :: $ mkdir -p ../../state Configuring Designate ====================== .. index:: double: configure; designate Open the designate.conf file for editing :: $ editor designate.conf Copy or mirror the configuration from this sample file here: .. literalinclude:: ../examples/basic-config-sample.conf :language: ini Installing RabbitMQ =================== .. note:: Do the following commands as "root" or via sudo Install the RabbitMQ package :: $ apt-get install rabbitmq-server Create a user: :: $ rabbitmqctl add_user designate designate Give the user access to the / vhost: :: $ sudo rabbitmqctl set_permissions -p "/" designate ".*" ".*" ".*" Installing MySQL ================ .. index:: double: install; mysql Install the MySQL server package :: $ apt-get install mysql-server-5.5 If you do not have MySQL previously installed, you will be prompted to change the root password. By default, the MySQL root password for Designate is "password". You can: * Change the root password to "password" * If you want your own password, edit the designate.conf file and change any instance of "mysql+pymysql://root:password@127.0.0.1/designate?charset=utf8" to "mysql+pymysql://root:YOUR_PASSWORD@127.0.0.1/designate?charset=utf8" You can change your MySQL password anytime with the following command:: $ mysqladmin -u root -p password NEW_PASSWORD Enter password Create the Designate tables :: $ mysql -u root -p Enter password: mysql> CREATE DATABASE `designate` CHARACTER SET utf8 COLLATE utf8_general_ci; mysql> CREATE DATABASE `designate_pool_manager` CHARACTER SET utf8 COLLATE utf8_general_ci; mysql> exit; Install additional packages :: $ apt-get install libmysqlclient-dev $ pip install pymysql Installing BIND9 ================ .. index:: double: install; bind9 Install the DNS server, BIND9 :: $ apt-get install bind9 # Update the BIND9 Configuration $ editor /etc/bind/named.conf.options # Change the corresponding lines in the config file: options { directory "/var/cache/bind"; dnssec-validation auto; auth-nxdomain no; # conform to RFC1035 listen-on-v6 { any; }; allow-new-zones yes; request-ixfr no; recursion no; }; # Disable AppArmor for BIND9 $ touch /etc/apparmor.d/disable/usr.sbin.named $ service apparmor reload # Restart BIND9: $ service bind9 restart Initialize & Start the Central Service ====================================== .. index:: double: install; central Sync the Designate database. :: $ designate-manage database sync Start the central service. :: $ designate-central You'll now be seeing the log from the central service. Initialize & Start the API Service ================================== .. index:: double: install; api Open up a new ssh window and log in to your server (or however you’re communicating with your server). :: $ cd openstack/designate # Make sure your virtualenv is sourced $ source .venv/bin/activate # Start the API Service $ designate-api You’ll now be seeing the log from the API service. Initialize & Start the Pool Manager Service =========================================== .. index:: double: install; pool-manager Open up a new ssh window and log in to your server (or however you’re communicating with your server). :: # Sync the Pool Manager's cache: $ designate-manage pool-manager-cache sync # Start the pool manager service: $ designate-pool-manager You'll now be seeing the log from the Pool Manager service. Initialize & Start the MiniDNS Service =========================================== .. index:: double: install; minidns Open up a new ssh window and log in to your server (or however you’re communicating with your server). :: # Start the minidns service: $ designate-mdns You'll now be seeing the log from the MiniDNS service. Exercising the API ================== .. note:: If you have a firewall enabled, make sure to open port 53, as well as Designate's default port (9001). Using a web browser, curl statement, or a REST client, calls can be made to the Designate API using the following format where "api_version" is either v1 or v2 and "command" is any of the commands listed under the corresponding version at :ref:`rest` :: http://IP.Address:9001/api_version/command You can find the IP Address of your server by running :: curl -s checkip.dyndns.org | sed -e 's/.*Current IP Address: //' -e 's/<.*$//' A couple of notes on the API: - Before Domains are created, you must create a server (/v1/servers). designate-2.0.0/doc/source/install/ubuntu-kilo.rst0000664000567000056710000001631612701406241023344 0ustar jenkinsjenkins00000000000000.. Copyright 2013 Rackspace Hosting Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ************************* Installing Kilo on Ubuntu ************************* .. _Development Environment: Development Environment +++++++++++++++++++++++ Installing Designate ==================== .. index:: double: install; designate 1. Install system package dependencies (Ubuntu) :: $ apt-get update $ apt-get install python-pip python-virtualenv git $ apt-get build-dep python-lxml 2. Clone the Designate repo from GitHub :: $ mkdir openstack $ cd openstack $ git clone https://git.openstack.org/openstack/designate.git $ cd designate 3. Checkout a specific version (in this case, the Kilo release) :: $ git checkout stable/kilo 4. Setup a virtualenv .. note:: This is an optional step, but will allow Designate's dependencies to be installed in a contained environment that can be easily deleted if you choose to start over or uninstall Designate. :: $ virtualenv --no-site-packages .venv $ . .venv/bin/activate 5. Install Designate and its dependencies .. note:: If you run into the error: Installed distribution pbr 1.1.1 conflicts with requirement pbr>=0.6,!=0.7,<1.0, try doing pip install pbr==0.11.0 :: $ pip install -r requirements.txt -r test-requirements.txt $ python setup.py develop If you run into the error: "Installed distribution oslo.config 1.9.3 conflicts with requirement oslo.config>=1.11.0", add the following into requirements.txt then repeat step 5: :: python-keystoneclient>=1.1.0,<1.4.0 pycadf>=0.8.0,<0.9.0 6. Change directories to the etc/designate folder. .. note:: Everything from here on out should take place in or below your designate/etc folder :: $ cd etc/designate 7. Create Designate's config files by copying the sample config files :: $ ls *.sample | while read f; do cp $f $(echo $f | sed "s/.sample$//g"); done 8. Make the directory for Designate’s log files :: $ mkdir -p ../../log 9. Make the directory for Designate’s state files :: $ mkdir -p ../../state Configuring Designate ====================== .. index:: double: configure; designate Open the designate.conf file for editing :: $ editor designate.conf Copy or mirror the configuration from this sample file here: .. literalinclude:: ../examples/basic-config-sample-kilo.conf :language: ini Installing RabbitMQ =================== .. note:: Do the following commands as "root" or via sudo Install the RabbitMQ package :: $ apt-get install rabbitmq-server Create a user: :: $ rabbitmqctl add_user designate designate Give the user access to the / vhost: :: $ sudo rabbitmqctl set_permissions -p "/" designate ".*" ".*" ".*" Installing MySQL ================ .. index:: double: install; mysql Install the MySQL server package :: $ apt-get install mysql-server-5.5 If you do not have MySQL previously installed, you will be prompted to change the root password. By default, the MySQL root password for Designate is "password". You can: * Change the root password to "password" * If you want your own password, edit the designate.conf file and change any instance of "mysql://root:password@127.0.0.1/designate" to "mysql://root:YOUR_PASSWORD@127.0.0.1/designate" You can change your MySQL password anytime with the following command:: $ mysqladmin -u root -p password NEW_PASSWORD Enter password Create the Designate tables :: $ mysql -u root -p Enter password: mysql> CREATE DATABASE `designate` CHARACTER SET utf8 COLLATE utf8_general_ci; mysql> CREATE DATABASE `designate_pool_manager` CHARACTER SET utf8 COLLATE utf8_general_ci; mysql> exit; Install additional packages :: $ apt-get install libmysqlclient-dev $ pip install mysql-python Installing BIND9 ================ .. index:: double: install; bind9 Install the DNS server, BIND9 :: $ apt-get install bind9 # Update the BIND9 Configuration $ editor /etc/bind/named.conf.options # Change the corresponding lines in the config file: options { directory "/var/cache/bind"; dnssec-validation auto; auth-nxdomain no; # conform to RFC1035 listen-on-v6 { any; }; allow-new-zones yes; request-ixfr no; recursion no; }; # Disable AppArmor for BIND9 $ touch /etc/apparmor.d/disable/usr.sbin.named $ service apparmor reload # Restart BIND9: $ service bind9 restart Initialize & Start the Central Service ====================================== .. index:: double: install; central Sync the Designate database. :: $ designate-manage database sync Start the central service. :: $ designate-central You'll now be seeing the log from the central service. Initialize & Start the API Service ================================== .. index:: double: install; api Open up a new ssh window and log in to your server (or however you’re communicating with your server). :: $ cd openstack/designate # Make sure your virtualenv is sourced $ source .venv/bin/activate # Start the API Service $ designate-api You’ll now be seeing the log from the API service. Initialize & Start the Pool Manager Service =========================================== .. index:: double: install; pool-manager Open up a new ssh window and log in to your server (or however you’re communicating with your server). :: # Sync the Pool Manager's cache: $ designate-manage pool-manager-cache sync # Start the pool manager service: $ designate-pool-manager You'll now be seeing the log from the Pool Manager service. Initialize & Start the MiniDNS Service =========================================== .. index:: double: install; minidns Open up a new ssh window and log in to your server (or however you’re communicating with your server). :: # Start the minidns service: $ designate-mdns You'll now be seeing the log from the MiniDNS service. Exercising the API ================== .. note:: If you have a firewall enabled, make sure to open port 53, as well as Designate's default port (9001). Using a web browser, curl statement, or a REST client, calls can be made to the Designate API using the following format where "api_version" is either v1 or v2 and "command" is any of the commands listed under the corresponding version at :ref:`rest` :: http://IP.Address:9001/api_version/command You can find the IP Address of your server by running :: curl -s checkip.dyndns.org | sed -e 's/.*Current IP Address: //' -e 's/<.*$//' A couple of notes on the API: - Before Domains are created, you must create a server (/v1/servers). designate-2.0.0/doc/source/install/ubuntu-liberty.rst0000664000567000056710000002725212701406241024061 0ustar jenkinsjenkins00000000000000**************************** Installing Liberty on Ubuntu **************************** This section describes how to install Designate on Ubuntu 14.04. To install other OpenStack services, see `OpenStack Installation Guide `_. This section assumes the Identity service runs on the host ``controller``. Install and configure Basic Environment ======================================= Enable OpenStack repository --------------------------- #. Enable the OpenStack Liberty repository: .. code-block:: console $ sudo apt-get update $ sudo apt-get install software-properties-common $ sudo add-apt-repository cloud-archive:liberty #. Upgrade the packages on your host: .. code-block:: console $ sudo apt-get update $ sudo apt-get dist-upgrade Install and configure SQL database ---------------------------------- #. Install the MariaDB packages: .. code-block:: console $ sudo apt-get install mariadb-server python-pymysql Choose a suitable password for the database root account. Install and configure message queue ----------------------------------- #. Install the RabbitMQ packages: .. code-block:: console $ sudo apt-get install rabbitmq-server #. Add the ``openstack`` user: .. code-block:: console $ sudo rabbitmqctl add_user openstack RABBIT_PASS Creating user "openstack" ... Replace ``RABBIT_PASS`` with a suitable password. #. Permit configuration, write, and read access for the ``openstack`` user: .. code-block:: console $ sudo rabbitmqctl set_permissions openstack ".*" ".*" ".*" Setting permissions for user "openstack" in vhost "/" ... Install DNS server ================== #. Install the BIND9 packages: .. code-block:: console $ sudo apt-get install bind9 #. Add the following options in the ``/etc/bind/named.conf.options`` file: .. code-block:: none options { ... allow-new-zones yes; request-ixfr no; recursion no; }; #. Restart the DNS service: .. code-block:: console $ sudo service bind9 restart Install Designate ================= #. Install the ``designate`` package: .. code-block:: console $ sudo apt-get install designate #. In the ``Configuring designate-common`` prompt, complete the following actions: * select ``Yes`` for the question ``Set up a database for Designate?``. * enter ``localhost`` for the ``IP address of your RabbitMQ host``. * enter the ``openstack`` as ``Username for connection to the RabbitMQ server``. * enter the ``password for connection to the RabbitMQ server`` that you chose for the RabbitMQ server at the previous step. * press the ``enter`` key at the prompt ``Authentication server hostname``. * press the ``enter`` key at the prompt ``Authentication server password``. * select ``No`` for the question ``Register Designate in the Keystone endpoint catalog?``. * select ``Yes`` for the question ``Configure database for designate-common with dbconfig-common``. * select ``mysql`` for ``database type to be used by designate-common``. * enter the ``password of the database's administrative user`` that is chosen for the root account at the previous step. * enter the ``MySQL application password for designate-common``. * enter the same password as ``password confirmation``. .. note:: the ``designate-common`` package offers automatic creation of the database tables for Designate during the installation process. Configure Designate =================== #. Source the admin credentials to gain access to admin-only CLI commands. #. Create the ``designate`` user: .. code-block:: console $ openstack user create --domain default --password-prompt designate User Password: Repeat User Password: +-----------+----------------------------------+ | Field | Value | +-----------+----------------------------------+ | domain_id | default | | enabled | True | | id | b7dd483c69654442b09a7458f7daf8d3 | | name | designate | +-----------+----------------------------------+ #. Add the admin role to the ``designate`` user and ``service`` project: .. code-block:: console $ openstack role add --project service --user designate admin #. Create the ``designate`` service entity: .. code-block:: console $ openstack service create --name designate \ --description "OpenStack DNS service" dns +-------------+----------------------------------+ | Field | Value | +-------------+----------------------------------+ | description | OpenStack DNS service | | enabled | True | | id | 6f634693062946579f678c32c006e097 | | name | designate | | type | dns | +-------------+----------------------------------+ #. Create the DNS service API endpoints: .. code-block:: console $ openstack endpoint create --region RegionOne \ dns public http://controller:9001 +--------------+----------------------------------+ | Field | Value | +--------------+----------------------------------+ | enabled | True | | id | 05bf0535afad4e0897fcbc4686bf1ab9 | | interface | public | | region | RegionOne | | region_id | RegionOne | | service_id | 6f634693062946579f678c32c006e097 | | service_name | designate | | service_type | dns | | url | http://controller:9001 | +--------------+----------------------------------+ $ openstack endpoint create --region RegionOne \ dns internal http://controller:9001 +--------------+----------------------------------+ | Field | Value | +--------------+----------------------------------+ | enabled | True | | id | b8f56bf8a8ed4e88b1655655a3327ae6 | | interface | internal | | region | RegionOne | | region_id | RegionOne | | service_id | 6f634693062946579f678c32c006e097 | | service_name | designate | | service_type | dns | | url | http://controller:9001 | +--------------+----------------------------------+ $ openstack endpoint create --region RegionOne \ dns admin http://controller:9001 +--------------+----------------------------------+ | Field | Value | +--------------+----------------------------------+ | enabled | True | | id | f081aef76b06472cb791aa04d920f195 | | interface | admin | | region | RegionOne | | region_id | RegionOne | | service_id | 6f634693062946579f678c32c006e097 | | service_name | designate | | service_type | dns | | url | http://controller:9001 | +--------------+----------------------------------+ #. Edit the ``/etc/designate/designate.conf`` file and complete the following actions: * In the ``[service:api]`` section, configure ``auth_strategy``: .. code-block:: ini [service:api] api_host = 0.0.0.0 api_port = 9001 auth_strategy = keystone enable_api_v1 = True enabled_extensions_v1 = diagnostics, quotas, reports, sync, touch enable_api_v2 = True enabled_extensions_v2 = quotas, reports * In the ``[keystone_authtoken]`` section, configure the following options: .. code-block:: ini [keystone_authtoken] auth_host = controller auth_port = 35357 auth_protocol = http admin_tenant_name = service admin_user = designate admin_password = DESIGNATE_PASS Replace DESIGNATE_PASS with the password you chose for the ``designate`` user in the Identity service. * In the ``[service:pool_manager]`` section, configure ``pool_id``: .. code-block:: ini [service:pool_manager] pool_id = 794ccc2c-d751-44fe-b57f-8894c9f5c842 * Configure the pool: .. code-block:: ini [pool:794ccc2c-d751-44fe-b57f-8894c9f5c842] nameservers = 0f66b842-96c2-4189-93fc-1dc95a08b012 targets = f26e0b32-736f-4f0a-831b-039a415c481e [pool_nameserver:0f66b842-96c2-4189-93fc-1dc95a08b012] port = 53 host = 127.0.0.1 [pool_target:f26e0b32-736f-4f0a-831b-039a415c481e] options = port: 53, host: 127.0.0.1 masters = 127.0.0.1:5354 type = bind9 * In the ``[storage:sqlalchemy]`` section, configure database access: .. code-block:: ini [storage:sqlalchemy] connection = mysql+pymysql://designate-common:DESIGNATE_DBPASS@localhost/designatedb ``DESIGNATE_DBPASS`` is automatically set to the password you chose for the Designate database. * In the ``[pool_manager_cache:sqlalchemy]`` section, configure database access: .. code-block:: ini [pool_manager_cache:sqlalchemy] connection = mysql+pymysql://designate-common:DESIGNATE_DBPASS@localhost/designate_pool_manager Replace ``DESIGNATE_DBPASS`` with a suitable password. #. Restart the Designate central and API services: .. code-block:: console $ sudo service designate-central restart $ sudo service designate-api restart Install Designate pool manager and mdns ======================================= #. Create the ``designate_pool_manager`` database and grant proper access: .. code-block:: console $ mysql -u root -p Enter password: mysql> CREATE DATABASE `designate_pool_manager` CHARACTER SET utf8 COLLATE utf8_general_ci; mysql> GRANT ALL PRIVILEGES ON designate_pool_manager.* TO 'designate-common'@'localhost' IDENTIFIED BY 'DESIGNATE_DBPASS'; mysql> exit; #. Install the ``designate-pool-manager`` and ``designate-mdns`` package: .. code-block:: console $ sudo apt-get install designate-pool-manager designate-mdns #. Sync the Pool Manager cache: .. code-block:: console $ sudo su -s /bin/sh -c "designate-manage pool-manager-cache sync" designate #. Restart the Designate pool manager and mDNS services: .. code-block:: console $ sudo service designate-pool-manager restart $ sudo service designate-mdns restart Verify operation ================ .. note:: If you have a firewall enabled, make sure to open port 53, as well as Designate's default port (9001). Using a web browser, curl statement, or a REST client, calls can be made to the Designate API using the following format where "api_version" is either v1 or v2 and "command" is any of the commands listed under the corresponding version at :ref:`rest`. :: http://controller:9001/api_version/command You can find the IP Address of your server by running: :: curl -s checkip.dyndns.org | sed -e 's/.*Current IP Address: //' -e 's/<.*$//' .. note:: Before Domains are created, you must create a server (/v1/servers). designate-2.0.0/doc/source/install/ubuntu-juno.rst0000664000567000056710000001021012701406243023346 0ustar jenkinsjenkins00000000000000************************* Installing Juno on Ubuntu ************************* .. _install-ubuntu-architecture: Architecture ============ Please see :ref:`production-architecture` for general production architecture notes. * Ubuntu as the Operating System * Designate * RabbitMQ * MySQL * :ref:`backend-powerdns` * Keystone for AuthN / AuthZ (Not included in this guide) .. _install-ubuntu-prerequisites: Prerequisites ============= .. _install-ubuntu-prereq-install: Install ^^^^^^^ :: $ sudo apt-get install mysql-server rabbitmq-server pdns-server pdns-backend-mysql .. _install-ubuntu-prereq-setup-rabbitmq: RabbitMQ ^^^^^^^^ .. note:: Do the following commands as "root" or via sudo Create a user: :: $ rabbitmqctl add_user designate designate Give the user access to the / vhost: :: $ sudo rabbitmqctl set_permissions -p "/" designate ".*" ".*" ".*" .. _install-ubuntu-prereq-setup-mysql: MySQL ^^^^^ .. note:: The following commands should be done using the mysql command line or similar. Create the MySQL user :: $ mysql -u root -p Enter password: mysql> GRANT ALL ON designate.* TO 'designate'@'localhost' IDENTIFIED BY 'designate'; mysql> GRANT ALL ON powerdns.* TO 'powerdns'@'localhost' IDENTIFIED BY 'powerdns'; Create the database :: mysql> CREATE DATABASE `designate` CHARACTER SET utf8 COLLATE utf8_general_ci; mysql> CREATE DATABASE `powerdns` CHARACTER SET utf8 COLLATE utf8_general_ci; .. _install-ubuntu-prereq-pdns: PowerDNS ^^^^^^^^ Edit the config:: $ sudo editor /etc/powerdns/pdns.conf Settings:: launch = gmysql Edit the MySQL backend settings:: $ sudo editor /etc/powerdns/pdns.d/pdns.local.gmysql.conf Settings:: gmysql-host=localhost gmysql-dbname=powerdns gmysql-user=powerdns gmysql-password=powerdns Delete a couple unnecessary files:: $ rm /etc/powerdns/bindbackend.conf $ rm /etc/powerdns/pdns.d/pdns.simplebind.conf .. _install-ubuntu-source: Installing using Source (Git) ============================= 1. Install pre-requisites: :: $ sudo apt-get install libmysqlclient-dev $ sudo apt-get install git python-dev python-pip $ sudo apt-get build-dep python-lxml 2. Clone the repository: :: $ git clone https://git.openstack.org/openstack/designate designate 3. Change directory to the newly cloned repository :: $ cd designate 4. Checking out a specific version: In some cases you might want to pin the repository version to a specific version of the repository like a stable one. Example for the Juno release: :: $ git checkout stable/juno 3. Install all dependencies using pip :: $ sudo pip install -r requirements.txt $ sudo pip install MySQL-python 4. Install Designate: :: $ sudo python setup.py develop 5. Copy over configuration files :: $ sudo cp -R etc/designate /etc/ $ ls /etc/designate/*.sample | while read f; do sudo cp $f $(echo $f | sed "s/.sample$//g"); done Create directories ^^^^^^^^^^^^^^^^^^ Since we are not running packages some directories are not created for us. :: $ sudo mkdir /var/lib/designate /var/log/designate # Needed if you are running designate as a non root user. $ sudo chown designate /var/lib/designate /var/log/designate Configuring =========== Designate ^^^^^^^^^ :: $ sudo editor /etc/designate/designate.conf Copy or mirror the configuration from this sample file here: .. literalinclude:: /examples/basic-config-sample-juno.conf :language: ini Sync Database schemas ^^^^^^^^^^^^^^^^^^^^^ Initialize and sync the database schemas for Designate and PowerDNS:: $ designate-manage database sync $ designate-manage powerdns sync Register Designate with Keystone ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ For howto register Designate with Keystone you can check the code used in the devstack plugin. There should be no version registered in the URL for the endpoint. Starting the services ===================== Central:: $ designate-central API:: $ designate-api You should now be able to create zones and use nslookup or dig towards localhost to query pdns for it. designate-2.0.0/doc/source/production-guidelines.rst0000664000567000056710000001112412701406241023724 0ustar jenkinsjenkins00000000000000********************* Production Guidelines ********************* This document aims to provide a location for documented production configurations and considerations. Including common misconfigurations, attack mitigation techniques, and other relevant tips. DNS Zone Squatting ================== Designate's multi-tenant nature allows for any user to create (almost) any zone, which can result in the legitimate owner being unable to create the zone within Designate. There are several ways this can occur: 1. The squatter simply creates "example.com." in Designate before the legitimate owner can. 2. The squatter creates "foo.example.com." as a zone in Designate, preventing the creation of any parent zones (example.com., com.) by any other tenant. 3. The squatter creates "com." as a zone in Designate, preventing the creation of any zones ending in "com." by any other tenant. 4. The squatter creates "co.uk." as a zone in Designate, preventing the creation of any zones ending in "com." by any other tenant. Scenario #1 and #2 Mitigation ----------------------------- There is no automated mitigation that can reasonably be performed here, DNS providers have typically used a manual process, triggered through a support request, to identify the legitimate owner and request the illegitimate owner relinquish control, or action any other provider specific policy for handling these scenarios. Scenario #3 Mitigation ---------------------- This scenario can be mitigated by ensuring Designate has been configured, and is updated periodically, with the latest list of gTLD's published as the `IANA TLD list`_. These TLDs can be entered into Designate through the :doc:`TLD API `. Scenario #4 Mitigation ---------------------- This is a variation on Scenario #3, where public registration is available for a second level domain, such as is the case with "co.uk.". Due to the nature of public second level domains, where the IANA has no authority, these are not included in the `IANA TLD list`_. A Mozilla sponsored initiative has stepped up to fill this gap, crowdsourcing the list of "public suffixes", which includes both standard TLDs and public second level domains. We recommend configuring, and periodically updating, Designate with Mozilla's `Public Suffix list`_. These public suffixes can be entered into Designate through the :doc:`TLD API `. DNS Cache Poisoning =================== Multi-tenant nameservers can lead to an interesting variation of DNS Cache Poisoning if nameservers are configured without consideration. Two tenants, both owning different zones, can under the right circumstances inject content into DNS responses for the other tenants zone. Let's consider an example: Tenant A owns "example.com.", and has created an additional NS record within their zone pointing to "ns.example.org." Tenant B, the attacker in this example, can now create the "example.org." zone within their tenant. Within this zone, they can legitimately create an A record with the name "ns.example.org.". Under default configurations, many DNS servers (e.g. BIND), will now include Tenant B's A record within responses for several queries for "example.com.". Should the recursive resolver used by the end-user not be configured to ignore out-of-bailiwick responses, this potentially invalid A record for "ns.example.org." will be injected into the resolvers cache, resulting in a cache poisoning attack. This is an "interesting variation" of DNS cache poisoning, because the poison records are returned by the authoritative nameserver for a given zone, rather than in responses for the attackers zone. `Bug 1471159`_ includes additional worked examples of this attack. BIND9 Mitigation ---------------- BIND9 by default will include out-of-zone additionals, resulting is susceptibility to this attack. We recommend BIND is configured to send minimal responses - preventing the out-of-zone additionals from being processed. In BIND's global options clause, include the following statement:: minimal-responses yes; PowerDNS Mitigation ------------------- PowerDNS by default will include out-of-zone additionals, resulting is susceptibility to this attack. We recommend setting the `out-of-zone-additional-processing` configuration flag set to "no" - preventing the out-of-zone additionals from being processed. In the main PowerDNS configuration file, include the following statement:: out-of-zone-additional-processing=no .. _IANA TLD list: https://data.iana.org/TLD/tlds-alpha-by-domain.txt .. _Public Suffix list: https://publicsuffix.org/ .. _Bug 1471159: https://bugs.launchpad.net/designate/+bug/1471159 designate-2.0.0/doc/requirements.txt0000664000567000056710000000006312701406241020642 0ustar jenkinsjenkins00000000000000-r ../requirements.txt -r ../test-requirements.txt designate-2.0.0/doc/ext/0000775000567000056710000000000012701406373016165 5ustar jenkinsjenkins00000000000000designate-2.0.0/doc/ext/__init__.py0000664000567000056710000000000012701406241020256 0ustar jenkinsjenkins00000000000000designate-2.0.0/doc/ext/support_matrix.py0000664000567000056710000003043112701406243021634 0ustar jenkinsjenkins00000000000000# Copyright (C) 2014 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. """ This provides a sphinx extension able to render the source/support-matrix.ini file into the developer documentation. It is used via a single directive in the .rst file .. support_matrix:: """ import six import six.moves.configparser as config_parser from docutils import nodes from docutils.parsers import rst from designate.backend.base import Backend from designate.backend.agent_backend.base import AgentBackend class SupportMatrix(object): """Represents the entire support matrix for Nova virt drivers """ def __init__(self): # List of SupportMatrixFeature instances, describing # all the features present in Nova virt drivers self.grades = [] self.grade_names = {} # Dict of (name, SupportMatrixTarget) enumerating # all the hypervisor drivers that have data recorded # for them in self.features. The 'name' dict key is # the value from the SupportMatrixTarget.key attribute self.backends = {} class SupportMatrixGrade(object): def __init__(self, key, title, notes, in_tree): self.key = key self.title = title self.notes = notes self.in_tree = in_tree class SupportMatrixBackend(object): def __init__(self, key, title, status, maintainers=None, variations=None, repository=None, type=None): self.key = key self.title = title self.type = type self.status = status self.maintainers = maintainers self.variations = variations self.repository = repository class SupportMatrixDirective(rst.Directive): option_spec = { 'support-matrix': unicode, } def run(self): matrix = self._load_support_matrix() return self._build_markup(matrix) def _load_support_matrix(self): """Reads the support-matrix.ini file and populates an instance of the SupportMatrix class with all the data. :returns: SupportMatrix instance """ cfg = config_parser.SafeConfigParser() env = self.state.document.settings.env fname = self.options.get("support-matrix", "support-matrix.ini") rel_fpath, fpath = env.relfn2path(fname) with open(fpath) as fp: cfg.readfp(fp) # This ensures that the docs are rebuilt whenever the # .ini file changes env.note_dependency(rel_fpath) matrix = SupportMatrix() # The 'targets' section is special - it lists all the # hypervisors that this file records data for for item in cfg.options("backends"): if not item.startswith("backend-impl-"): continue # The driver string will optionally contain # a hypervisor and architecture qualifier # so we expect between 1 and 3 components # in the name key = item[13:] title = cfg.get("backends", item) name = key.split("-") try: status = cfg.get("backends.%s" % item, "status") except config_parser.NoOptionError: if cfg.get("backends.%s" % item, "type") == "xfr": backend = Backend.get_driver(name[0]) elif cfg.get("backends.%s" % item, "type") == "agent": backend = AgentBackend.get_driver(name[0]) status = backend.__backend_status__ if len(name) == 1: backend = SupportMatrixBackend( key, title, status, name[0]) elif len(name) == 2: backend = SupportMatrixBackend( key, title, status, name[0], variations=name[1]) else: raise Exception("'%s' field is malformed in '[%s]' section" % (item, "DEFAULT")) backend.in_tree = cfg.getboolean( "backends.%s" % item, "in-tree") backend.type = cfg.get( "backends.%s" % item, "type") backend.notes = cfg.get( "backends.%s" % item, "notes") backend.repository = cfg.get( "backends.%s" % item, "repository") backend.maintainers = cfg.get( "backends.%s" % item, "maintainers") matrix.backends[key] = backend grades = cfg.get("grades", "valid-grades") grades = grades.split(",") for grade in grades: title = cfg.get("grades.%s" % grade, "title") notes = cfg.get("grades.%s" % grade, "notes") in_tree = cfg.get("grades.%s" % grade, "in-tree") matrix.grade_names[grade] = title grade = SupportMatrixGrade( grade, title, notes, in_tree) matrix.grades.append(grade) return matrix def _build_markup(self, matrix): """Constructs the docutils content for the support matrix """ content = [] self._build_grade_listing(matrix, content) self._build_grade_table(matrix, content) self._build_backend_detail(matrix, content) return content def _build_backend_detail_table(self, backend, matrix): table = nodes.table() tgroup = nodes.tgroup(cols=2) thead = nodes.thead() tbody = nodes.tbody() for i in range(2): tgroup.append(nodes.colspec(colwidth=1)) tgroup.append(thead) tgroup.append(tbody) table.append(tgroup) header = nodes.row() blank = nodes.entry() blank.append(nodes.emphasis(text=backend.title)) header.append(blank) blank = nodes.entry() header.append(blank) thead.append(header) graderow = nodes.row() gradetitle = nodes.entry() gradetitle.append(nodes.strong(text="Grade")) gradetext = nodes.entry() gradetext.append(nodes.paragraph( text=matrix.grade_names[backend.status])) graderow.append(gradetitle) graderow.append(gradetext) tbody.append(graderow) treerow = nodes.row() treetitle = nodes.entry() treetitle.append(nodes.strong(text="In Tree")) if bool(backend.in_tree): status = u"\u2714" else: status = u"\u2716" treetext = nodes.entry() treetext.append(nodes.paragraph(text=status)) treerow.append(treetitle) treerow.append(treetext) tbody.append(treerow) maintrow = nodes.row() mainttitle = nodes.entry() mainttitle.append(nodes.strong(text="Maintainers")) mainttext = nodes.entry() mainttext.append(nodes.paragraph(text=backend.maintainers)) maintrow.append(mainttitle) maintrow.append(mainttext) tbody.append(maintrow) reporow = nodes.row() repotitle = nodes.entry() repotitle.append(nodes.strong(text="Repository")) repotext = nodes.entry() repotext.append(nodes.paragraph(text=backend.repository)) reporow.append(repotitle) reporow.append(repotext) tbody.append(reporow) noterow = nodes.row() notetitle = nodes.entry() notetitle.append(nodes.strong(text="Notes")) notetext = nodes.entry() notetext.append(nodes.paragraph(text=backend.notes)) noterow.append(notetitle) noterow.append(notetext) tbody.append(noterow) return table def _build_backend_detail(self, matrix, content): detailstitle = nodes.subtitle(text="Backend Details") content.append(detailstitle) for key in six.iterkeys(matrix.backends): content.append( self._build_backend_detail_table( matrix.backends[key], matrix)) content.append(nodes.line()) return content def _build_grade_listing(self, matrix, content): summarytitle = nodes.title(text="Grades") content.append(summarytitle) table = nodes.table() grades = matrix.grades tablegroup = nodes.tgroup(cols=2) summarybody = nodes.tbody() summaryhead = nodes.thead() for i in range(2): tablegroup.append(nodes.colspec(colwidth=1)) tablegroup.append(summaryhead) tablegroup.append(summarybody) table.append(tablegroup) content.append(table) header = nodes.row() blank = nodes.entry() blank.append(nodes.strong(text="Grade")) header.append(blank) blank = nodes.entry() blank.append(nodes.strong(text="Description")) header.append(blank) summaryhead.append(header) for grade in grades: item = nodes.row() namecol = nodes.entry() namecol.append(nodes.paragraph(text=grade.title)) item.append(namecol) notescol = nodes.entry() notescol.append(nodes.paragraph(text=grade.notes)) item.append(notescol) summarybody.append(item) return content def _build_grade_table(self, matrix, content): summarytitle = nodes.title(text="Backends - Summary") summary = nodes.table() cols = len(list(six.iterkeys(matrix.backends))) cols += 2 summarygroup = nodes.tgroup(cols=cols) summarybody = nodes.tbody() summaryhead = nodes.thead() for i in range(cols): summarygroup.append(nodes.colspec(colwidth=1)) summarygroup.append(summaryhead) summarygroup.append(summarybody) summary.append(summarygroup) content.append(summarytitle) content.append(summary) header = nodes.row() blank = nodes.entry() blank.append(nodes.strong(text="Backend")) header.append(blank) blank = nodes.entry() blank.append(nodes.strong(text="Status")) header.append(blank) blank = nodes.entry() blank.append(nodes.strong(text="Type")) header.append(blank) blank = nodes.entry() blank.append(nodes.strong(text="In Tree")) header.append(blank) blank = nodes.entry() blank.append(nodes.strong(text="Notes")) header.append(blank) summaryhead.append(header) grades = matrix.grades impls = list(six.iterkeys(matrix.backends)) impls.sort() for grade in grades: for backend in impls: if matrix.backends[backend].status == grade.key: item = nodes.row() namecol = nodes.entry() namecol.append( nodes.paragraph(text=matrix.backends[backend].title)) item.append(namecol) statuscol = nodes.entry() statuscol.append(nodes.paragraph(text=grade.title)) item.append(statuscol) typecol = nodes.entry() typecol.append(nodes.paragraph( text=matrix.backends[backend].type)) item.append(typecol) if bool(matrix.backends[backend].in_tree): status = u"\u2714" else: status = u"\u2716" intreecol = nodes.entry() intreecol.append(nodes.paragraph(text=status)) item.append(intreecol) notescol = nodes.entry() notescol.append(nodes.paragraph( text=matrix.backends[backend].notes)) item.append(notescol) summarybody.append(item) return content def setup(app): app.add_directive('support_matrix', SupportMatrixDirective) app.add_stylesheet('support-matrix.css') designate-2.0.0/designate.sublime-project0000664000567000056710000000260112701406241021602 0ustar jenkinsjenkins00000000000000{ "folders": [ { "file_exclude_patterns": [ "*.pyc", "*.pyo", "*.exe", "*.dll", "*.obj", "*.o", "*.a", "*.lib", "*.so", "*.dylib", "*.ncb", "*.sdf", "*.suo", "*.pdb", "*.idb", ".DS_Store", "*.class", "*.psd", "*.db", ".vagrant" ], "folder_exclude_patterns": [ ".svn", ".git", ".hg", "CVS", "*.egg", "*.egg-info", ".tox", "venv", ".venv", ".testrepository", "doc/build", "doc/source/api", "build", "__pycache__" ], "path": "." } ], "settings": { "default_line_ending": "unix", "detect_indentation": false, "ensure_newline_at_eof_on_save": true, "rulers": [ 79 ], "tab_size": 4, "translate_tabs_to_spaces": true, "trim_trailing_white_space_on_save": true } } designate-2.0.0/LICENSE0000664000567000056710000002363712701406241015632 0ustar jenkinsjenkins00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. designate-2.0.0/ChangeLog0000664000567000056710000022511512701406372016377 0ustar jenkinsjenkins00000000000000CHANGES ======= 2.0.0 ----- * Adding v2 namespaced event to zone manager * Do not log pool-manager-caches SQL transactions * Added "view" option to bind9 rndc options * Partitoner references invalid exception class * devstack: compile message catalogs during stack.sh * Update .gitreview for stable/mitaka 2.0.0.0rc1 ---------- * Enable use of Pools YAML * Add New Pools DB Tables and Code * Default to not logging all SQL Quries made during a test run * DevStack: Explicitly install libcap2-bin and don't fail without AA * Documentation changes for Admin API Quotas page * Add release note for not allowing .json on urls * Avoid logging tracebacks for EAGAIN errors * Add scheduler for pools * Switch get_serial_number logging to debug * Do not allow GET /resource.json * Fix _find_masters + unit tests * Replace deprecated LOG.warn with LOG.warning * Strip "\n" character from result * Move zone masters to a new table * Cleanup unused Oslo Incubator _i18n * Added "expected" to OverQuota Exceptions * Add warning to devstack/README.rst * Updated from global requirements * Fix for TCP connections not sending full content * Moved CORS middleware configuration into set_defaults * Updated from global requirements 2.0.0.0b3 --------- * Use a single recordset validation method * Ensure the zone records quota is enforced * Use assertGreater() * Improve error handling for TCP connections * Use lazy properties in services * Fixed typos in docstrings * Add syntax highlighting to backend docs * Updated from global requirements * Move SOA refresh interval into unit tests * Update README to RST * Set Ubuntu as primary Vagrantfile VM * Update PoolAlsoNotify object name * Fix bug where building validators for ListObjects fails * Add AttributeListObjectMixin class * Set InvalidRecordSetName and InvalidRecordSetLocation as expected * Stop using WritableLogger() which is deprecated * Add an on-demand single-target sync method * Update Bind 9 backend and other documentation * Cleanup after enable files refactor * Randomize SOA refresh interval * Allow to use project_name in handler formats * Updated from global requirements * Syntax, grammar, and typo fixes * Fix a missing '\' in doc * Minor unicode test fixes * Add delayed NOTIFY * Actually poll for zone deletes * Improve performance and utility of Recovery * A request hook interface for the functional test client * Ensure ZoneManager emits valid objects * Update numbering of dashboard enable files * Updated from global requirements * Functional tests for MX, TXT, SPF, SSHFP validation * Use "# noqa" instead of "#flake8: noqa" * Simplify NeutronFloatingHandler process_notification * Change the name of the test_create_wildcard_NS test * Updated from global requirements * Switch "managed" fields from unicode to string * Minor test cleanup * Use unicode strings in description fields * Fix misspellings * Make supported record type configurable * Log stacktraces of MultipleExceptions in functionaltests * Added Keystone and RequestID headers to CORS middleware * Remove outdated pot files * Fix wildcard NS record * Updated from global requirements * Update functional test TLDCLient * Policy.json still has references to domain * Add docs for PATCH and DELETE call of Zone transfer request * Switch to mock fixtures, minor cleanup * Add validation for MX, TXT, and SSHFP records * Do not create /dev/shm/designate * Fix integration doc that example config not formatted * Fix order of installation in Devstack * Fix _assert_exception() * Ensure mocks are stopped after use * Fixes wording of exceptions for delete * Fix the python34 check job * Rename zone > domain for errors in V1 * Updated from global requirements * Replace assertEqual(None, *) with assertIsNone in tests * test: make enforce_type=True in CONF.set_override * Update the link to CLI Reference * Add retry logic on periodic_sync * Skip possible heisenbug test_init_no_pool_targets * Fix V1 Quotas API Extension * Use tmpfs on /dev/shm for database if available * Update unit test execution syntax Closes-Bug: #1532802 * Document that keystone auth can use memcached * Added bandit to designate * Updated from global requirements 2.0.0.0b2 --------- * Update email addresses hp.com to hpe.com * Add FloatingIPs reverse endpoint * Improve unit testing * Added doc for /v2/tsigkeys endpoint * Updated from global requirements * Update periodic-sync-seconds help * Retry Coordinator start indefinitely * Fix CI Tempest jobs * [docs] Create installing Liberty on Ubuntu * Add UniqueConstraint for pool_id + hostname * Tox: ignore Rope dirs * Replace deprecated LOG.warn with LOG.warning * Add Pool Manager tests * Move to [oslo_messaging_rabbit] * Add test of BIND9 backend * Remove unused comments in create zone * Improve logging in designate.zone_manager * Update Devstack docs * Improve logging in designate.notification_handler * Improve logging in designate.agent * Fix tox ValueError: No closing quotation * Use keystoneauth instead of keystoneclient * Add documentation for Limits * Deprecated tox -downloadcache option removed * Describe how to install Designate client * Set zone in ERROR status on periodic sync fail * Remove iso8601 dependency * Object model: require "priority" field * Emit notification on update_status() on a zone * Removes MANIFEST.in as it is not needed explicitely by PBR * Use git.openstack.org as Git repository * Switch devstack to use local.conf * pass environment variables of proxy to tox * Fix NO_DOMAIN handling with The Big Rename * Remove version from setup.cfg 2.0.0.0b1 --------- * Remove py26 support from designate * Updated from global requirements * Check TXT record length limit * Remove deprecated devstack in contrib * Updated from global requirements * Migrate existing Devstack integration into a Devstack plugin * Another improvement of info level log messages * Improving info level log messages * Test database schema and indexes * Replaces map() with six.moves.map() to provide py2/3 compatibility * Added HTTP_X_FORWARDED_PROTO/HOST support to API * Updated from global requirements * Ensure designate-manage reads config before policy * Adds api_export_size attribute to admin API * Add Reno for release notes tracking * Add mdns unit tests for main service handler * Hide zones flagged for deletion in API v1 * Rename all references of Domain to Zone * Added placeholder migrations for stable/liberty * Improve logging in designate.network_api * Add support for interface and service * Handle NO_DOMAIN status * remove default=None for config options * Fix argument order in assertEqual to (expect, obs) * Switch to oslo.reports * Use oslo_config PortOpt type for port options * Removes zone files when a zone is deleted * Use assertIn and assertNotIn * Use assertTrue/False instead of assertEqual(T/F) * Uses assertIsNone instead of assertEqual(None, ***) * Use oslo_config IPOpt support * Updated from global requirements * Fixes Output for zone type filter * Added CORS support to Designate * Fix order of argument in assertEqual * Updated api-export-size attribute in quota update docs * Add functional tests for TLDs * Fix typos in sample config files * Block oslo.messaging 2.6.0 release * retry creates/deletes in the pool manager * Use assertFalse instead of assertEqual(False, ***) 1.0.0 ----- * Fix handling of Pool NS changes * Fix order of arguments in assertEqual * Functional tests: optionally disable ssl cert validation * Functional tests: Use a configurable url pattern * Fix order of argument in assertEqual * Functional tests: optionally skip admin actions in setups * Added test cases for records * Fix handling of Pool NS changes * Clear out pyc files before a tox run * Fix order of argument in assertEqual * Fix order of argument in assertEqual * Fix order of argument in assertEqual * Unauthed tests for Pools (Security) * Unauthed tests for Blacklists (Security) * Unauthed tests for Zones (Security) * Cleanup of Translations * Cleanup of Translations * Added test cases for tsigkeys extention for V1 api * Functional tests: configure putting the version in the url * Open Mitaka development 1.0.0.0rc1 ---------- * Add zone type specific validators * Ensure recordset name checking accounts for child domains * Ensure blacklists complete in a reasonable time * Fix unhandled exceptions in adapters parsing * Add Kilo upgrade nodes * Fix #1494799 handle limit=max on v2 and Admin APIs * Ensure unique records when listing recordsets * Fix race condition in V1 Records API * Fix Vagrantfile for Rally repo changes * Correct a possible DNSService connection leak * Ensure API workers > 1 starts correctly * Updated from global requirements * Change ignore-errors to ignore_errors * A functional test to check CNAME recordsets allow only 1 record * Unauthed tests for RecordSets (Security) * Ensure CNAME RRSets only have one record * Remove functional-tests.log, update .gitignore * Updated from global requirements * Imported Translations from Zanata * Add backend for Designate using SECONDARY zones * [zm] Periodic Secondary zone refresh task * Replace request.request_mac with request.mac * Handling Forbidden Exception * Check the contents of a zone export in the functional tests * Cleanup data created in the functional tests * Agent - If no allow_notify hosts are specified, allow all * Change ip->host in the agent * Updated from global requirements * Modify centrals 'purge_domains' arguments * Implement deleted zone purging * Fix AXFR / Secondary zone functionality * Activate pep8 check that _ is imported * Fix typos in comments 1.0.0.0b3 --------- * Updated from global requirements * Updated from global requirements * Correct generated links when behind an SSL terminating proxy * Correct pool_target options in sample config * The address for cloning designate is corrected * Asynchronous Zone Export * Add a service catalog override url for the functional tests * Refactor Zone Import Internals * Remove unused dependency: discover * Add functional tests that query for wildcard records * Grammar mistakes have been corrected * Show functional test request logging * Update docs for the functional tests * Fixes bug 1484332 git url was wrong. Modified to proper url * Add DomainMaster Object to designate objects * Add functional tests for wildcard records * Updated from global requirements * Refactor notify logic into backends * Replaces str to byte to provide py3 compatibility * Replaces x.keys() with six.iterkeys(x) * Export Zones * Provide error messages on CRUD actions * Verify DNS changes when updating RRSet * Fixing datagen random_pool_data * Move iteration code to base task * Updated from global requirements * Fix zone transfer requests + add tempest tests * Cleaning up add_filters * Add a iteritems = items on DictObjectMixin * Remove auth* related param keys in middleware * Convert str to byte for py3 compatibility * Added 'add_filters' to ClientMixin for GET vars * Updated from global requirements * Imported Translations from Transifex * Updated from global requirements * Fix eleven typos on designate documentation * Implement test timeout helper. Minor fixes * Install dnspython3 on py3 * Added some unit tests to test_domains.py * Added some unit tests in test_servers.py * Add __str__() methods to DesignateObjects * Wildcard records * Fixed a test case name * Enable filter on get pools * Add support for Host header in REST queries * Increase unit tests coverage * Updated from global requirements * Add tests for limits api in V1 api * Imported Translations from Transifex * Replace assertTrue(a in b) with assertIn(a, b) 1.0.0.0b2 --------- * Ensure RecordSet quotas are enforced * Ensure a single RRSet over max_packet_size doesn't loop forever * Introduce a Production Guidelines document * Fix the incorrect JSON format in v1 REST API doc * Updated from global requirements * Reject invalid filters * Add unit testing for pool * Imported Translations from Transifex * Fixes designate-manage tld's command by passing the correct params * Fixed timeout variable scope issues * Updated from global requirements * Fix test in test_coordination.py for py3 compatibility * Fixup v2 API Validation * Remove unused V2 schemas * Fix duplicate domain error handling * Only print flake8 table if there is results * Create unit tests dir, move objects tests there * Replacing dict.iteritems() with dict.items() * Replaced print with print() to provide py 2/3 compatibility * Updated from global requirements * Modify UT in test_limits.py * Add some UTs to test_pools.py * Add some UTs to test_zones.py * Allow multiple reader/writers to UDP DNS Sockets * Add some UTs to test_tsigkeys.py * Add some UTs to test_recordsets.py * DevStack: Support installing client at released versions * Added some UTs to test_tlds.py * Correct exists event field names * Add functional tox env * Add some UTs to test_records.py for record update * Fix the displayed error message in V2 API * Add Zone Manager Service options to sample config * Add some UTs to test_records.py * Fix iteritems > items to avoid recursion loops * Add some missing UTs to test_domains.py * Pass configration of what tasks are enabled * Update ubuntu-dev guide * Add some basic missing UTs to test_utils.py * Fix broken UTs due to PY3 in test_import_export * Convert old style class to new style class * Refactor mDNS packet finalization * Add __pycache__ to ST2 Ignore * Correct sample coord URL * Default to memcache for PM cache * Ensure only one pool-manager performs periodic tasks * Implement support for LeaderElections * Standup coordination during start * Increase coverage of RRset tests * Handle unhandled exception in dnsutils.py for py3 * Imported Translations from Transifex * Fix for ttl values * Test - add nicer formating to flake8 output * Functional tests for Blacklists * Enable filter on blacklists & tlds * Switch from MySQL-python to PyMySQL * Error message for database config * Correct 'DESIGNATE_SQL_DEBUG' export behaviour * Add tasks and periodic emits * Resolve one py3 compatibility issue * Add support for BETWEEN and add tests * Fixed broken UTs in notification_handler module * Fix broken UTs for python3 * Ensure test_find_zone_imports waits for all imports * Ensure validations account for trailing newlines * Fix broken UTs in test_mdns.test_handler * Updated from global requirements * Fix broken UTs in test_coordination for py34 * Add v1 API deprecation warnings * Designate Dashboard now has it's own repo * Replace Exception.message with six.text_type(Exception) * Fix broken UTs due to py3 * Updated from global requirements * Add zone filter for TTL, description, & status * Use released versions of tempest-lib * DevStack: Keystone V3 Service/Endpoint Creation * DevStack: Keystone V3 User Creation * Return the correct recordsets total_count * Use six.iterkeys(x) instead of x.keys() * Replace dict.items() with list(dict.items()) * fix broken UTs for python3 compatibility * Standardize API service launcher * Add DevStack support for coordination URL * Rename coordination tests to match established naming pattern * Silence some DEBUG logs * oslo.service triggers shutdown * Replace dict.iterkeys() with six.iterkeys(dict) * Remove 'L' from long int * Add shard and domain_shard to tables * Enable designate-zone-manager in DSVM gates * Replace dict.iteritems() with dict.items() * Update urllib/urlparse to use six.moves * Use six.moves.map/zip in place of map/zip * Allow logging hookpoint intialization * Add Zone Manager service shim * Remove leftover print statement in tests * Add a couple of new hacking checks * Add base for coordination as a mixin / tooz * Updated from global requirements * Add py3 compatibility related changes * Ensure quotas ext doesn't mutate dict during iteration * Re-arrange default log levels and add iso8601 * Updated from global requirements 1.0.0.0b1 --------- * port to oslo.service * Edits to dev guide, juno guide, and kilo guide * Updated from global requirements * Asynchronous Zone Import * Fix incorrect status code on Pool update * Updated from global requirements * Enable random hash seeds * Update version for Liberty * Updated from global requirements 1.0.0a0 ------- * Added expected=True to InvalidDomainName * Eventlet+DNSPython breaks /etc/hosts resolution * Add Tempest tests for V2 Pools * Add utility code for negative testing * Updated from global requirements * Add tempest-lib from git for gate devstack * Reset check_for_tlds after deleting the last TLD * Updated from global requirements * Updated from global requirements * Sync with oslo-incubator 61f4461f91 * Correcting missing import for dashboard messaging * Changes in rally-jobs/README.rst * Updated from global requirements * Enforce usage of project scoped token * Agent: Optional middleware to rate limit NOTIFYs * Mark Infoblox as Release Compatible * Give a nicer error upon 401 from Akamai * Add domain record detail screen * Add .eggs to .gitignore * Updated from global requirements * Add the Hook Point API * Fix exceptions on pep8 check due to missing tempest.conf * Pin python version to 2.7 * Add filter for status on recordsets * Fix the v2 XFR task API * Add Backend grading, and associated docs page * Fix designate-manage pool show_config command * Imported Translations from Transifex * Drop incubating theme from docs * Updating cmd/manage.py get_arg_string() argument parser * Infoblox Backend * Update Dashboard requirements * Drop use of 'oslo' namespace package * Disable recursive queries with bind in Devstack * DevStack: Attempt to cleanup stale domains * DevStack: Remove SOA/NS checks * Add some more settings to the sample conf file * Add NSD4 backend * Add tests for dynect * Add Akamai Management comamnds * Fix check+set race condition in APIv1/Sink * Remove unnecessary RestController usage * Set cfg.pool_target.options as secret * Allow sink to create multiple entries per instance * updating tox pep8 issues * Add quota check for domain create * Moved RecordSet lookup to a custom join query * Add support for settings wsgi MAX_HEADER_LINE * Switch pip-missing-reqs for pip-check-reqs * Add suds-jurko to requirements.txt * Utility script to help create n+ records at a time * Updated from global requirements * Ensure Sink Handlers encode UTF8 names * Add docs for X-Auth-Sudo-Tenant-ID api header * Drop use of 'oslo' namespace package * Updated from global requirements * Improve UX of create and update record screen * Vagrant: NFS should only be used for libvirt * Fixed SO_REUSEPORT not supported by Linux <3.9 * Fix a wrong obj_reset_changes field * Imported Translations from Transifex * Updated from global requirements * Drop use of 'oslo' namespace package * Updated from global requirements 2015.1.0 -------- * Remove duplicated index on table 'records' of pDNS backend * central.update_status should be transactional * Add an index to speed up update_status * Add the /v2/zones//nameservers endpoint back * Add the /v2/zones//nameservers endpoint back * Update JSON in howtos examples to match the API * Service ThreadPool size should be configurable * Handle socket.error's in mDNS * Move the Central rpcapi update_status to cast * PM: Ensure only one periodic task runs per host * Ensure addition of TSIG do not trigger a TooBig exception * Simplify designate.api.versions * Allow to use network label in nova_fixed handler format * Denominator Agent * Imported Translations from Transifex * Minor fixes: pep8 and redundant code * central.update_status should be transactional * Include README.rst in dashboard sdist * Functional tests to check recordset ownership * Zone ownership tests * Rally is now openstack/rally * Handle socket.error's in mDNS * Remove duplicated index on table 'records' of pDNS backend * Imported Translations from Transifex * PM: Ensure only one periodic task runs per host * Functional tests: minus tempest, plus noauth support * Service ThreadPool size should be configurable * Ensure addition of TSIG do not trigger a TooBig exception * Release Import of Translations from Transifex * Correct designate-dashboard domain detail screen * Update PM pooling defaults * Add policy support to designatedashboard * update .gitreview for stable/kilo * Correct mDNS TCP/UDP socket flags * Move the Central rpcapi update_status to cast * Shuffle of the order of BIND9 masters * Updated from global requirements * Update JSON in howtos examples to match the API * Shuffle of the order of BIND9 masters * Correct mDNS TCP/UDP socket flags * Imported Translations from Transifex 2015.1.0rc1 ----------- * Fix missing '/' in self link after zone import * Reduce excessive stacktraces in logs * Move Zone Import / Export to /admin API * Ensure mDNS TCP/UDP threads service unhandled exceptions * Correct the max_zone_name_length name * Add validation of RRSet Type * Change rackspace.com > example.com in docs * Remove unused pool view * Refactored BaseAddressHandler * Switch to API v2 as the new CURRENT * Add stable/kilo placeholder migrations * DevStack: Reduce periodic intervals in the gate * Open Liberty development * Restrict editing of managed records to policy based ACL * Imported Translations from Transifex * Added tenant impersonation to API * Fixup DevStack Horizon install * Validate SRV records have the correct name on the recordset * Fixed sort key to not sort by an un-indexed field by default * Fix Record Object conversions * Fix handling of filtering params * Add Ceilometer support to DevStack plugin * DevStack: Akamai/Dyn Support for Jenkins Credentials and Exercises * Split out Optional OpenStack services in localrc * Support Vagrant Libvirt * First Tempest tests for recordsets * Remove zone wrapper object in Tempest tests * Add global limits to V2 limits endpoint * Fix min_ttl config to be an IntOpt * Implement default and max page size for V2 API * Fix output of errors on base recordset properties * Correct min-ttl default config value * Update periodic sync defaults * Ensure mDNS can AXFR zones over 65k * Fixup updates in the agent backend * Fix support for PostgreSQL * Imported Translations from Transifex * Akamai: mDNS must run on port 53 * Agent Pool Manager Backend * Add Akamai EDNS Backend * DynECT: Convert to a Pool Backend * Add also-notifies support to Pool Manager * Implement Pool Targets * Reduce the # of SQL queries during AXFRs * Add code to allow triggering of AXFR from API * Fix 'zone' link in transfer_accepts * Imported Translations from Transifex * Enable Record Data Validation in v2 API * Sync up FIP behaviour to match latest PoolManager * Fix ownership issue with Zone's created on set fip * Fixed rootwrap file installation * Add _to_string() methods on RRData Objects * Add Schema to RRData Objects * Replace API_v2 views with Adapters * RFC1996 Requires NOTIFY packets have the AA flag set * Ensure mDNS originated queries are non-blocking * Unwind mDNS XFRMixin from NotifyEndpoint and Handler * Correct Pool Object * Add API_v2 Adapter Objects * Support mDNS response up to 65k * Install etc/designate/* files * forgot missing __init__.py file * Allow for duplicate domains in different pools * Remove usage of relative_path in ValidationError Objects * Fix handling of wildcards in api / storage * Reduce the # of records loaded by Central.update_status * improving designatedashboard packaging * Imported Translations from Transifex * Fixed misspellings in central * Validation Error Middleware does translation of keys to new format * Added FloatingIP object to DesignateObjects * Omit deleting zones from mass ns record updates * Imported Translations from Transifex * Archive non-pool backends * Combine Backend and PoolBackend * Refacor function for parsing host:port strings * Spelling & formatting doc fixes * Updated from global requirements * Revert "Disable tempest in the gate, for now" * Retry serial number check in one more case * Move Pool NS Records to their own table * Imported Translations from Transifex * Don't allow updates to zones that are being deleted 2015.1.0b3 ---------- * Imported Translations from Transifex * Remove "Including all tenants items" debug log * Disable tempest in the gate, for now * Fix the use of private symbols from oslo.messaging * Ensure Quotas can be updated concurrently * Only attempt XFR if zone.type is SECONDARY * Add Admin API and add extensions * Add DESIGNATE_SQL_DEBUG toggle * Move the DesignateAdapter to return non-wrapped objects * Imported Translations from Transifex * Added ValidationErrorMiddleware * Added Schemas to DesignateObjects * MDNS part of Secondary zones * Support secondary zones * Add iPythonNotebook files to git ignore * Implement TSIG Support in mDNS * Imported Translations from Transifex * Add Tempest zone tests * Enable Tempest Functional Tests * Use the oslo.policy package * Smarter Create/Delete in BIND9/Agent * Imported Translations from Transifex * Send the correct domain object to update_domain * Update localrc docs sample * Fix DesignateObjects ListObjectMixin interactions * Introduce Guru Meditation Reports into Designate * Call central's update_status correctly * Initial Pool API docs * Fixed ssl.PROTOCOL_SSLv3 not supported by Python 2.7.9 * Agent configuration and BIND9 improvements * Validate SSHFP records * Create DesignateAdapter and surrounding infrastructure * Imported Translations from Transifex * Updated from global requirements * Updated from global requirements * Fix exception handling * Imported Translations from Transifex * Add initial code for tempest tests * Updated from global requirements * devstack/install.sh shouldn't rely on exact paths * Add designate-agent to DevStack * Updated from global requirements * Rename _retrieve_from_cache to _retrieve_statuses * Updated from global requirements * Imported Translations from Transifex * Updated from global requirements * Implement Scoped TSIG Key Support * Service Class Cleanup - Part 3/3 * Service Class Cleanup - Part 2/3 * Service Class Cleanup - Part 1/3 * Fixed _is_superdomain check in central * Imported Translations from Transifex * Add Developer Guidelines docs page * Update default managed_resource_email * Update tests to use Object.from_dict() method * Sync with oslo-incubator * Remove explicit thread-local update in context * Ensure pool_manager cache keys are strings * Remove bulk actions from records page * Add python-memcached>=1.48 to requirements.txt * Add error state transition for creation of domains * Modifications for Resilient Pool Manager Cache * Ensure DNSPython modules are imported correctly * Add howto for creating PTR records * Imported Translations from Transifex * A small intro to the REST API * Implement an Object.from_dict() method * Updated from global requirements * Deprecate designate-sink non managed mode * Retry transactions on database deadlocks * Correct PoolAttribute module name * Set PYTHONDONTWRITEBYTECODE=1 in tox.ini * Use fully qualified domain names in the mx record examples * Workaround eventlet 0.17's broken monkeypatching * Pass SSL CA Cert to client * Pass ssl no verify to client * Assume a new developer won't create a "designate" user in the dev guide * Add noop cache support to Pool Manager * Allow MiniDNS to Send Everything Over TCP * Replace nova with designate in pybasedir help * Updated from global requirements * Add memcache support to Pool Manager * Get on an abandon zone returns 405 * Ensure count record/recordsets respect deleted domains * Deleting a recordset returns 202 * Fix up links in Ubuntu Dev Environment * Imported Translations from Transifex * Docs: Top level Install Guides section * Docs: Automate How To Index * Fix Production Arch docs * Update Designate Architecture Docs * Docs: Howto Create and Manage Domains * Added docs env to tox * Updated Sample Config and Documentation Page * Update Getting Started Guide * Doc sprint: Update glossary * Doc sprint: Update Getting Involved * Update zone status when recordsets are changed * DevStack: Sync function rename with DevStack * Updated from global requirements * Return correct response codes for v2 recordset api * Fix a reference link in the doc * Doc: fix the designate-manage powerdns sync command * Fix some typos in 6 files * Nameservers added via /v2/pools are not validated * Imported Translations from Transifex * Return a status field from the recordsets API * Remove dead server code in storage and add tests 2015.1.0b2 ---------- * Updated from global requirements * Add pretty_tox subunit wrapper * Add a new API for abandoning a zone from storage * Allow Periodic Sync to be restricted to a subset of zones * Add pool_manager migrate.cfg in MANIFEST.in * Updated from global requirements * Cleanup use of oslo.messaging's ConfFixture * Add a debug tox environment * Imported Translations from Transifex * Extract fixtures into their own module * Updated from global requirements * Agent cleanup/refactoring * Imported Translations from Transifex * The New Agent * Imported Translations from Transifex * Refactor RecordSet Relation Loads * Ensure Pool Manager Cache is Cleared * Move some methods from mdns to dnsutils * Switch to oslo.log * Imported Translations from Transifex * Fix v2 api update_recordset * Fix sink neutron_floatingip handler passing payload * Temporary fix for bad _dispatch() invocation * Server Pool Storage Clean Up * Call the Correct Pool Manager Instance for the Domain * Clean requirements * Periodic sync and recover Timers Throw Descriptive Errors * Updated from global requirements * Imported Translations from Transifex * Move PM warning log inside the correct if block * Update mDNS to accept server object * Pool Manager should reuse the existing threadgroup * Pool Manager Throws An Error When No Servers are Defined * Add Unit Tests for Pool Manager * Ensure Pool Manager Works for Multiple Backend Servers * Add more tests to the central service * Add more unit tests to mdns service * Add more unit tests to Base Object class * Add Unit Tests for v2 API Reports * PowerDNS Backend Tests * Updated from global requirements * Moved to oslo_utils namespace * Remove dead designate.wsgi * Remove dead SQLAlchemy code * Add .coveragerc configuration file * Update Vagrantfile with new Ubuntu box * Moved to oslo_db namespace * Imported Translations from Transifex * Fix powerdns db table records missing column disabled * Update README.md doc build instructions * Switch to oslo_middleware namespace * Imported Translations from Transifex * Updated from global requirements * Updated from global requirements * Allow Domain to Be Created on More Than One Server * Better Logging for Pool Manager * Separate Periodic Recovery from Periodic Sync * Domain Creation Includes Zone Transfer For Proper Status * Updated from global requirements * Migrate Server table * Updated from global requirements * Pool_Attribute Storage Tests * Change SLA check for Designate * Adds negative unittests to test_domains.py and test_records.py * Adds negative tests to test_records.py * Imported Translations from Transifex 2015.1.0b1 ---------- * Remove duplicate fields from ZoneTransferRequest object * Documentation, comments, and extraneous code fixes * Post-pool merge cleanup * Adds negative tests to test_records.py * Imported Translations from Transifex * Added smart update of Records Objects in v2 * Changed oslo.messaging's default log level * Fixed the syntax of obj_reset_changes in SQLA * Pool Manager Integration with Central * Remove the agent service and old-style backend tests * Remove the non-pools bind9 backend * Convert PowerDNS to a Pools Backend * Pools Config Changes * Add Werkzeug>=0.7 to requirements.txt * Adds "domain-servers-list" to test_domains.py * Cleanup validation regex's * Adds negative tests to test_servers.py * Updated from global requirements * Imported Translations from Transifex * Switch to oslo.context and sync from incubator * Standardize creation of rpcapi client instances * Updated from global requirements * rename oslo.concurrency to oslo_concurrency * Updated from global requirements * Imported Translations from Transifex * Workflow documentation is now in infra-manual * Updated from global requirements * Add DynECT DevStack plugin * Handle multi-packet TCP queries * Allow DevStack to retry DNS queries to handle async CRUD * Handle priority the same way as when create_record * Correct RRSet delete notification * Pool Manager * Add docs for MX, SSHFP, SPF and SRV record set types * Add metadata, totalcount fields to zones/recordsets collections * Add bashate tox env for DevStack plugin * Update DevStack PORT vars for naming consistency * Update gate_hook to support multiple drivers * Added designate-dashboard code to contrib/designate-dashboard * Rename rally-scenarios/ to rally-jobs/ * Imported Translations from Transifex * Updated from global requirements * Added functionality to allow for zone ownership transfers * Updated from global requirements * Add Rally to Vagrant VM * Move Central notifications to a decorator * Add a reverse name columns to domains/recordsets * Updated from global requirements * Fix rally job readme file * Add synchronized_domain decorator * Add some helpful SQL indices * Return the correct RRSet object in Central.create_recordset * Updated from global requirements * Detect CPU on OSX as well * Fix rally gates * Can't Access Default Pool through API * Add tox check for missing pip requirements * Add rally job related files * Updated from global requirements * Support Nested/Recursive Object Validations * Add basic validation functionality to DesignateObjects * Updated from global requirements * Move import code to dnsutils * Add a new field type 'relation' to objects * Imported Translations from Transifex * Missing Unique Constraint on Pool Attributes table * Add ability to configure extensions via local.conf * Move from incubator to o.concurrency * Fixed API v1 issue with horizon * Add Symantec's nova and neutron plugins to docs * Add pool_id column to Domains Table * Imported Translations from Transifex * Pool Manager - Central/Storage Changes * Pool Manager - BIND9 Pool Backend Driver Fixes * Updated from global requirements * Pool Manager - Pool Manager Proxy Backend and Devstack * Imported Translations from Transifex * Imported Translations from Transifex * Support for server pools in minidns * Initial documentation for v2 API record sets * Move rec.priority into rec.data * Imported Translations from Transifex * API for pools * Server Pools Storage * Updated from global requirements * Pool Manager Service Changes * Ensure version column is correctly incremented * Updated from global requirements * Updated from global requirements * Implement a DesignateObject Registry * Correct int datatypes during zone import * Enforce all Object attributes are private or well defined * Add a UUID Schema format checker * Convert Object FIELDS from list to dict * Reduce SQLAlchemy loglevel during tests * Updated from global requirements * Imported Translations from Transifex * Imported Translations from Transifex * Updated from global requirements * Add a new PowerDNS backend based on MiniDNS * Ensure mDNS sends NOTIFYs on all zone changes * PowerDNS schema should cascade domain deletes * Add Jinja2 to requirements.txt * Switch to oslo.middleware and remove deprecated incubator * Sync oslo-incubator and remove json|str utils * Imported Translations from Transifex * Multi backend attepts to read a deleted domain * Bind a random port for MDNS tests * Open Kilo development 2014.2.rc1 ---------- * Use devstack's new way of doing things * Updated from global requirements * Fixes missing Module Index in Sphinx-build * Make use of SQLA Core in PowerDNS * Prevent update/delete of managed records in v1 API * Fixes minor errors and warning in Sphinx build * Fixes docstring typos * Updated from global requirements * Notif handlers:remove double check of event type * Imported Translations from Transifex * Missing Tests for Blacklist storage layer methods * Fix example response for reports/tenant * Update oslosphinx requirement * Fix issues with timeout and if a domain exists * Add v1 missing api docs * Backends need to implement c/u/d_recordset * Updated from global requirements * Missing tests for TLD storage layer methods * Updating README * Removing *.shapes files from Desginate diagrams * Add png for `Designate-PowerDNS-Detail` * Adding Dia file for `Designate-PowerDNS-Detail` * Adding Dia file for `Designate-MultiZone` * Adding Dia file for `Designate-Simple` * Bind9 zone file should end with a new line * Correct Vagrant+DevStack paths * Use non-deprecated notification_driver * Split Vagrant out of contrib/devstack * Fixed the logging of powerdns metadata addition / removals * Updated from global requirements * Fix warnings made by keystone_authtoken * Devstack Integration : Coding style fix * Getting deleted recordsets returns a 404 * Devstack setup : use get_or_create_* helpers * Updated from global requirements * Downgrade in 039 does not delete NS recordsets * Add index on powerdns.records.designate_record_id * Updated from global requirements * Support filtering on Zone/RecordSet status * _find_recordsets returns active recordsets only * Ensure designate-api has policy initialized * Ensure designate-sink has policy initialized * Rollback master backend on all exceptions in multi backend * Delete SOA records correctly on a downgrade * Call _handle_query_error correctly * Updated from global requirements * Update README.md doc links 2014.2.b3 --------- * warn against sorting requirements * Creating a Recordset doesn't increment the serial number * Support the same api versions format as keystone * Imported Translations from Transifex * Fixed policy loading in agent service * Imported Translations from Transifex * Implement mDNS Middleware * Squash Icehouse DB Migrations * Move DNS packet serialization into mDNS service * Update default notification-topics for nova/neutron * Received notifications context is not a DesignateContext * Add support for AXFR requests * Expose SOA and NS records * Fix get_record_id to return only the requested id * Fix DevStack xtrace output * Updated from global requirements * Updated from global requirements * Updated from global requirements * Imported Translations from Transifex * Validate that no parent zones are created in another tenant * Issue one SQL statement per execute() call * Added policy checking for all all_tenent=True contexts * Add two more hacking checks * Updated from global requirements * Imported Translations from Transifex * V2 Report Uses 'Domains' * Ensure Object change lists are sorted during to_primitive * Reimplement Filtering by Record Data * API v1 for creating domains ignore some attributes now * Fixes a typo in the binary name for test's service fixture * Designate API tests for Tempest Framework * Add proxy support to dynect client * Add instructions on installing Designate with MySQL backend * Imported Translations from Transifex * Migrate to SQLAlchemy Core * Update testr config for better logging * Remove obsolete methods from Storage * Empty RecordSets can be re-provisioned * Install only the necessary files during a DevStack gate run * devstack exercise for deletion, dns checking * Set python hash seed to 0 in tox.ini * Add quotas documentation * Imported Translations from Transifex * Switchover to oslo.i18n package * Remove the Priority Field in V2 * Moved the thread storage to a per instance level, vs global * Update from oslo-incubator * Use auth_token from keystonemiddleware * Move oslotest into test-requirements.txt * Imported Translations from Transifex * Updated from global requirements 2014.2.b2 --------- * Revert o.m and o.c 1.4.0 alpha updates * Add a minimal gate_hook.sh script * Moved v2 API errors to separate controller * Enable X-Auth-Project flag in HTTP headers * Cleaning up index.rst file * Imported Translations from Transifex * Handle tcp requests correctly in mdns * Modify Recordset API * Clear out junk from Vagrant+DevStack configs * Correct JSON Syntax is v2 Collections Docs * Ensure o.c.local is populated with the current Context * DevStack: Enable V2 API * DevStack: Correct the key's passed to setup_colorized_logging * PowerDNS: Ensure each greenthread uses it's own Session instance * Ensure eventlet monkey patching happens as early as possible * Attach records to RecordSet objects * Ensure each greenthread uses it's own Session instance * Add docs for links, pagination, filtering * Enable hacking check H104 * Add validate_log_translations flake8 check * Imported Translations from Transifex * Avoid logging "Expected" exceptions returned over RPC * Fixed issue with elevated contexts modifying the original context * Imported Translations from Transifex * Port Report Extensions from v1 to v2 * Added proper handling for 405 errors * Fixed D701 Hacking check * Implement a ListObjectMixin class * Implement equality methods on DesignateObject * Updated from global requirements * Answer dns record queries * Iterator methods should be on DictObjectMixin * Added oslosphinx theme & enabled the incubating theme * Enabled hacking check H401 * Update's should use objects * Provide a standard method for populating an object from a model * Expand Zones Documentation * Updated from global requirements * Don't create new objects when doing a create_* * Track the original/persisted values in Objects * Object fields should not be marked changed if the value has not changed * Ensure RPC serializes all types to primitives * Setup for translation * Implement DesignateObject.__deepcopy__ * Change API filter wildcard from '%' to '*' * Updated from global requirements * Ensure contrib/devstack/install.sh works from any path * Ensure we always accept trailing /'s in URLs * Updated from global requirements * Change logging level AUDIT to INFO * Ensure DesignateObject.from_sqla does not trigger change tracking * Update stackforge references to openstack * Support recursive object serialization * Revert "Added olso sphinx, and enabled it for building docs" * Update .gitreview for repository move * Specify minimum and maximum correctly in schemas * Add Extensions to the v2 API * Added olso sphinx, and enabled it for building docs * Don't monkeypatch pecan.core.Request in newer versions of pecan * mdns: Add support for NOTIFY's * Implement change tracking in DesignateObjects * Ensure that 404's are returned as JSON * Change log string format to '%' for consistency * Objects should have a concrete list of their fields * Added all fields to limits endpoint, and corrected casing * Fixes default content type on /v2/zones endpoint * Unify Storage vs Rest of World fixture creation * Switch to oslo.db and fix cmd.manage * Added *.sqlite3 to gitignore * Remove the StorageAPI class * Indent lines for readability * Switch to oslotest library * Finalize tox.ini codes * Fix style errors H305 and H307 * Fix style error E265 * Fix style error E251 * Fix style error E111 * Fix style error H236 * Update hacking package, fix I18n style issues * Sync with global-requirements * Sync in o.middleware and replace our own * DevStack: PowerDNS and Bind9 should listen on SERVICE_HOST * DevStack: Fix Bind9 Apparmor profile * Change log statements to meet I18n guidelines * DevStack: Additional exercises for records and domain-servers-list * DevStack/Vagrant: Specify the minimum supported Vagrant version * DevStack Gate: Enable Designate exercises * DevStack: Sync up our logging options * DevStack: Sync up our service startup commands * DevStack/Vagrant: Set # of CPU's to # of physical cores * DevStack/Vagrant: Don't configure LOGFILE by default * DevStack: Support configuring bind host/port * DevStack: Migrate from keystone CLI to OpenStack CLI * DevStack: Support PowerDNS on Fedora * DevStack: Support devstack with bind9 backend on Fedora * DevStack: Split backends out into plugins * DevStack: Use a timeout rather than hard sleep * DevStack: Support running with bind9 as non-root user * DevStack: Default to PowerDNS rather than the fake backend * DevStack: Ensure PowerDNS is configured correctly * Add DevStack Vagrantfile * Sync test-requirements with global-requirements * Partial sync with global-requirements * Add pre/post dsvm test hooks * Added detection of powerdns package name to devstack script * Wait a little after starting Designate * Revert "add sink support to designate devstack" * Bug #1261894: Deleting Record With BIND 9 Driver Fails * Ensure we configure all keystone middleware options * Ensure our DevStack plugin cleans up services it starts * Switch stop_designate to use screen_stop rather than `kill` * Ensure designte-sink does not exit when no handlers are enabled * Implement mDNS Service * API now passes objects to central * Ability to pass along multiple endpoints * Fix FreeIPA tests mock's * Adding custom flake8 check for mutable default arguments * DynECT backend exceptions should be added to allowed exmods * Create missing domains during Bind9Backend start * Update DevStack docs for the contrib/devstack plugin * Correct DESIGNATE_TEST_NSREC default value * Correct typo in DynECT backend * set default auth_strategy to keystone * Allow Roles to be Passed When Using Noauth Middleware * add support for FreeIPA backend - phase 6 - devstack * add support for FreeIPA backend - phase 5 - requirements * add support for FreeIPA backend - phase 4 - migration * add support for FreeIPA backend - phase 3 - live tests * add support for FreeIPA backend - phase 2 - tests * add support for FreeIPA backend - phase 1 * Ensure objects are passed over RPC * add sink support to designate devstack * Update oslo.policy * only call sink handlers for supported event types * Print versions * Raise correct exception on blocked operation * Ignore 404 on deletion * Remove redundant setup.cfg entry points * Correct DynECT backend config option types * Fixed the self link returned for floating IPs * sink crashes due to a missing _get_handler_event_types * Update Record object with structured RRdata * Post oslo.messaging fixes * DynECT support * Remove leftover bin/* files * Set a Configurable Minimum TTL * Allow targeting of specific agent * Update Storage layer to return objects * Update install_venv from Oslo * Sync with openstack/oslo-incubator * Sync with openstack/requirements * Sync up openstack-common.conf * Switch to oslo.messaging * v1 api does not allow priority of 0 * WIP - Implement Capture the Notification Context in Designate Sink * Sync requirements with openstack/requirements * Open Juno development 2014.1 ------ * Read the Docs needs a single requirements file * Remove designate-manage dependancy on cliff * Fix sync functionality in V1 / central * Provide a production like guide for Ubuntu * Blacklists API Documentation * Document the PowerDNS backend 2014.1.b3 --------- * Ensure that request body in v2 contains valid fields * Remove JSONSchema 1.3 compatibility code * Support more record types * create_server fails if server is not unique * Sync with global-requirements repo * V2 API zone import/export documentation * Return 404 for empty parameters in URLs * Ensure that URL is valid while validating UUID * Return 400 for invalid Json for api v2 * Introduce nameservers endpoint for zones * Standardize doc requirements * Ensure Storage Implementions match the Interface * Ensure that wanted API calls returns exceptions * Fill in missing Records tests for V2 api * UUID changes to api / utils * Remove use of uuidutils.generate_uuid * Fixes filtering in delete and update in PowerDNS * Register as a endpoint without version * Handle invalid pagination parameters * Add the handler plugin example to the contrib folder * Add Bind9 Support to the DevStack Plugin * Correct misspelled words 2014.1.b2 --------- * DevStack: Set the correct state_path * Disabled paging by default * Don't install designate packages twice with Devstack * Add support for paging in V2 api for collections * Add RMQ+Other options to sample config * Switch to oslo.rootwrap * Sync with oslo-incubator 9a7f2f85 * Sync with global-requirements * Blacklists mysql error * Add paging to Central rpcapi and service * Adds support for paging in the storage layer * Shouldn't pass items to get_collection_href here * Ensure default DB connection strings use unique defaults * Fix arguments in get_collection_href * Default state-path to /var/lib/designate * Adds a setting for the location of the nzf files * Stop abusing state_path in find_config * Add a new ExtensionPlugin class * Add Unit Tests for Blacklists V2 * Update notification_driver documentation * Import TLDs to Designate * Prevent Schema regex's from capturing input * General Plugin Cleanups * Create API calls to Manage Blacklisted Domains * Fix TLD Delete From Storage * Sync with oslo-incubator rev fa785cea * Sync with openstack/requirements rev 661e6bad * Various small fixes to documentation * Keep the DevStack plugin in-tree * Add TLD Api documentation * Make Database Interactions More Transactional * Remote Designate Agent Calls Fail * Remove dnsmasq backend * Replace os.exists with os.path.exists * Validate name during v2 zone create * Sink - Delete record on floatingip.delete event * Check if RS belongs in childzone * Add APIs for managing TLDs * provide designate getting started instructions for Fedora 19 * Update setup.cfg for the Neutron -> Quantum handler rename * Remove dependencies on pep8, pyflakes and flake8 * Sync with global requirements * Ensure APIv2 list respose formats are correct * FloatingIP PTR record functionality * Moved Limits API endpoint to a RESTController * Return a HTTP 405 for unsupported HTTP methods * six is now a requirement of many of the oslo-incubator modules * Made Pecan HTML debugging an option for v2 API * PowerDNS backend tests * Ensure Flask uses our JSON Encoder * Add support for specifying tenant/user/token in the NoAuthMiddleware * Removing Docs about the old Sudo mechanismn * Designate requires Babel during runtime now * Cleanup API v2 Link Generation and Views * Ensure migrations run on PostgreSQL * Switch out designate.notifier for oslo's version * Reinstate RecordSet placement validation * Sync with oslo-incubator * The default port is not 0.0.0.0, it is 9001 * Ensure JSON Schema format validators operate only on strings * Database fixture * Ensure SQLite has the correct unique_record index * Docs spelling/capitalization fixes * Specify column names during the PowerDNS backends InsertFromSelect's * Do not try to update records if there are none * Introduce RecordSets concept to core, and add initial RRSet API to v2 * Provide support for "All Tenants" access * Correct migration 33 * Fixed bug where sync_all could not be run * Use % when printing keyfile/certfile errors * Make sure that certfile and keyfile are readable * BUG# 1258262 Added secret parameter to options for sensitive data * Bug #1257888: Remote Designate Agent Call Fails * Denormalize tenant_id into the records table * Multi-backend * Put test resources into own folder * Backend tests restructure * Ensure logs are captured and displayed when tests fail * Fix typo in config and rename Quantrum > Neutron everywhere * Multiple testing fixes * Allow a context to be elevated to admin status * Don't require domain_id in find_record* methods * Pass the service-catalog if any to the context * Add placeholder migrations to allow backports to Havana * Added a check for HTTP_X_IDENTITY_STATUS * Add SLDs that act like TLDs * Support building wheels (PEP-427) * Add .testrepository to ST2 project ignore * nsd4slave backend * Update notifications towards oslo.messaging * Switch to testr / testtools / fixtures, remove nose * Update PPA URL * Expose touch_domain via an API extension * Update TLD list per IANA list version 2013110700 * Fix inconsistent dnspython imports bug * Domain Import/Export * Update setup.cfg for Icehouse development cycle 2013.2 ------ * Ensure we're compatible with JSONSchema 1.3.0 through 2.2.0 * Sync requirements with stable/havana requirements * Zoneextractor tool * Ensure all FakeBackend methods use info level logs * Abstract quota enforcement in central service * Minor tox.ini changes, should speed things up * Add status fields for domains and records * Correct JSONSchemas for min/max TTLs * Added info on flake8 to docs * Update domains when servers are created, modified or deleted * Add rudimentary migration testing * docs: Correct errors in the Create Record examples * BIND9 Plugin Cleanup * Ensure beta versions are not downloaded from pypi * Correct PowerDNS migration 006 * Monkeypatch WebTest to support HTTP PATCH * Give more meaningful error message when no servers are configured * Add initial BIND9 backend docs * Ensure default TTL is respected by PowerDNS backend * Allow default SOA values to be configured * Ensure tables are InnoDB and UTF8 * Cleaned up fake backend backend * Central RPCAPI should call the correct sync methods * Add APIv2 Zones Controller * Fixed broken links in README.md * Fixup CNAME placement validation * PowerDNS - Correctly quote TXT and SPF record * Fix utils.render_temaplate_to_file() test case name * Revert "PowerDNS - Ensure SPF records are quoted correctly" * docs: Add 'description' field to domains * Cleanup v2 schema links * Add description field to v2 schemas * Minor v1 records schema corrections * Add "Invalid TLD" error message * Correct V2 limits schema * Switch to EntryPoints for the binaries * Add API v2 /limits endpoint * Update Getting Started Guide * Sync doc/requirements.txt with openstack/requirements * API Version 2 - Initial Framework * Sync requirements with openstack/requirements * Add more API documentation for record types * Bug 1206849: Add more logging to the API Layer * PowerDNS - Ensure SPF records are quoted correctly * Add Description Field to Domains/Records * Update PBR to 0.5.21 * Fixup incorrect exception handler * Update PBR * Restore JSONSchema 1.1.0 compatibility * Fix a minor doc build warning * Ensure all errors raised from netaddr are caught * Internal SQLA Storage Consistency Cleanup * Ensure the deleted column is not truncated * Update 'Getting Started' Doc * Reduce logspam from amqp * Ensure backend resources are always deletable * Refactor JSONSchema handling code * Remove out of date TODOs from README * Move doc/examples to doc/source/examples * Move Keystone config to main designate config * re-org docs & add details on production architecture * Ensure Code Coverage only includes designate * better ipv4 validation * Replace missing indexes for SQLite * Ensure StorageAPI always re-raises exceptions appropriately * corrected event details in Nova Handler notes * Logging & docs improvement for notification_handler * Remove unnecessary default criterion value * find_record should take a domain_id argument * find_records does not need to perform an is_admin check * Sync requirements with openstack/requirements * Remove openstack.common.cfg * Remove invalid entrypoints * Accept trailing /'s on URLs * Add 'Getting Started' Doc * Implement a Quota management API extension * bug# 1198890 internal api tidy * Update docs links from moniker.rtfd.org to designate.rtfd.org * Add DevStack documentation page * Override default config values correctly * Middlewares should tell you they have started * Sync with oslo-incubator stable/grizzly * Update link to designate-cookbook * Add doc link to sample plugin repo * Add a related links page to the docs * Remove comments from *requirements.txt (workaround pbr bug) * bug# 1198849 - from blallau * Update the outdated install document * Ensure sphinx and sphinxcontrib-httpdomain are installed for doc builds * Ensure RTD builds install all the necessary deps * bug# 1198885 - report 'latest' instead 'None' on database-sync * Ensure central cleans up storage if the backend fails * Add the Request-ID as a HTTP reponse header * Carry oslo-incubator review #34949 * Sync with oslo stable/grizzly c7862b5239822d701b7fb155faa4607eff602627 * Ensure all backend methods respect deleted domains * quota-domain-records sould be an IntOpt * Ensure the unique index on domains.name is correctly dropped * Bug #1194889 - Fix migration 16 on SQLite * Added notes on setting up a designate dev environment * bug/1195284 - correct ttl checks to match RFC * Add simple Maintenance Mode WSGI middleware * Update jsonschema dependancy * Sync requirements with openstack/requirements (except jsonschema) * Keep deleted domains in the DB * Ensure domains that fail to create are cleaned * Ensure request media-types are sane * Ensure records are unique, per RFC2181 Sec 5.0 * Add LICENSE file * Rename to designate in .gitreview * Rename keystone-setup script for designate * Correct some overzealous s/moniker/designate/'s * Bump version to 2013.2 * Correct a few links broken during the s/moniker/designate/ * Rename Moniker -> Designate * Switch to Flake8 and add Hacking checks * Sync requirements with openstack/requirements. (Except jsonschema) * Fix pyflakes error * Guard against deletion of a parent domain * Remove unused SQLA utils code * Ensure record placement validation does not prevent updates * Validate UUID URL parameters * Add request-id to the API's fault responses * Switch to PBR * Helper utilities * The utils module in oslo is no more * Ensure create domain/record records call the correct count_* methods * Ensure our quotas/limits are consistent with other OpenStack projects * Implement Quota Support * Ensure two PTR records cannot have the same name * Update import of oslo's processutils * Extend reports API extension with more information * Cleanup method/varible ordering in the various places they are defined * Update report API ext method names to match URLs * Remove unnecessary try/catches from API extensions * Ensure all error responses are JSON * Ensure API calls fail when junk/unexpected properties are supplied * Add tests to ensure domain notifications are sent correctly * Removing unused test helpers * Add periodic_task from Oslo * Correct the service name used in notifications * Add a "force" option to context sudo * Add Central.find_*() methods * Show log level in moniker-manage output * Commands should extend our Base Command, rather than cliff.Command * Remove un-used base CLI command classes * Update to the latest loopingcall from oslo * Convert openstack-common.conf to the new format * Ensure X-Moniker-Sudo-Tenant-ID values are either a UUID or int * Prefix all Moniker notifications with "dns." * Add a test case for email addr's with a trailing period * 0.0.0.0 is an invalid IPv4 address * Cleanup PowerDNS database schema * Support all valid (per RFC1035) email addresses * Implement support for RPC Versioning * Remove redundant moniker-manage commands * Ensure record changes trigger a backend serial increment * Abstract API exception handling * Tighten up TTL and Priority acceptable value ranges * Added /reports, /reports/domains, /reports/records & /reports/tenants * A domain may not have a NULL TTL * Ensure supplied email addresses are valid for use in the SOA RNAME field * Add support for specifying custom domain/record name max lengths * Validate SRV record format * Add localhost, localdomain and local and remove com, net, org from default blacklist * Set the default value for accepted TLD's to match the IANA TLD list * Quick fix to oslo-wsgi for wsgi.Service compat with service.ProcessLauncher * Domain name's should not be accepted with wildcards * Add 'accepted_tld_list' config option * Add ability to "touch" a domain via the API * Allow for record create/update/delete's and domain updates's without incrementing the serial number * Add a simple profiling decorator * Prevent is_subrecord iterating past the domain name itself * Revert "A domain's TTL must not be null." * A domain's TTL must not be null * Use the 'fake' backend by default * Make Diagnostics and Sync API's optional * Separate notification handling from the central service * Remove base Plugin testcase * API tests should tearDown in the correct order * Refactor DNSMasq plugin for easier transition to the upcoming transactional changes * Remove the distinction between a storage engine and connection * Add Also-Notify support to PowerDNS backend * Wrap backend interactions in try/catch blocks * Add a base 'Backend' exception class for backend specific exceptions to extend from * Fetching a domain's list of authoritative name servers should not be filtered by tenant_id * Ensure database-sync works when no version is specified * Rename sync-all to the more accurate "sync-domains" * Ensure we enforce the various rules for CNAME records * Add novalocal to the default domain name blacklist * Fixup migration #12 and support a target version when doing a database-sync * Ensure migrate.cfg's are included in the sdist tarball * Saner default values for SOA * Ensure serial number does not go backwards * Pin to jsonschema less than 1.0 * Rename the X-Moniker-Tenant-ID header to X-Moniker-Sudo-Tenant-ID to make more clear its meaning and use * Support SSHFP records * Correct migration #10 * Massively improve hostname validation * Move diagnostics API resource under /v1/ and split out the sync methods * Add support for plugin provided API resources * Add 'servers' link to domain schema * Drop the ipv4 and ipv6 columns from servers. It's never been used and makes little sense * Add ability to fetch the list of nameservers hosting a particular domain * Consistently use try/except/else * Ensure doc examples use valid JSON * Correct Context-Type -> Content-Type typo in docs * Attach context to local.store a little earlier * Ensure tools/* is included in sdist * Remove unnecessary test api-paste and policy.json * Ensure resources are included in dist packages * Ensure we attach the context object to oslo-local for oslo-log to find * Simple implementation of DNSMasq backend * PowerDNS: Allow domain type to be configured * Ensure PowerDNS backup updates the SOA serial when necessary * Add ordername/auth cols to PowerDNS Record model * Set the auth field correctly for PowerDNS * Allow Context properties to be passed through get_admin_context() * Fixup moniker-manage sync commands * Add moniker-manage CLI commands to trigger sync's * Allow admin context's to retrieve domains from all tenants * PowerDNS currently only supports hmac-md5 TSIG * Calls to get_servers from backends should use an admin context * Add moniker-manage commands for maintaining servers and TSIG keys * Use a dash as the command separater in moniker-manage * Fix incorrect column name used when updating a TSIG key * Add support for TSIG to PowerDNS backend * Add tests for incorrect domain_id checks * Ensure records belong to the domain_id supplied in the URL * Pass TSIG Key Create/Update/Delete to backend implementations * Fixup a rebase gone wrong. * Provide initial support for TSIG * Pass an instance of the central service, or the central_api proxy to backends * Add initial PowerDNS migration repo * Fixup bug in bind9 backend * Domain Sync should not attempt to delete records after deleting the domain * Prevent renaming of a domain, and ensure records are contained in their parent domain * Add SPF to type ENUM in Records Table * Update REST API docs to remove links * Remove some magic from the RPC Backend API * Add naive domain/record synchronization implementations 2013.1.alpha1 ------------- * Ensure config files are included in sdist tarball * Rename moniker-api-paste.ini -> api-paste.ini * Cleanup and simplify Tenant "Sudo" Code * Cleanup Blacklist code, Protect from sub-domain hijacking. Upgrade to pyflakes 0.6.1 * Override the format for records * Replace reserved domain suffixes with regex based domain name blacklist * Use Policy enforcement to record an Audit trail * Update to JSONSchema 0.8 final * Re-add version.py * Initial Diagnostics API endpoint * Sync with Oslo 30a50c8a * Move config files from 'etc/' to 'etc/moniker/' to match what oslo's update.py expects * Allow Moniker Services to Spawn N processes each * Add sample config entry for reserved_domain_suffixes * Change to rootwrapper - bug #1075120 * A Domain's TTL should be optional * Sanitize content field for certain record types * Pass server list from central -> backend for domain operations * Add sample PowerDNS backend config * Minor doc cleanup's * Update Docs with GetRecord call * PowerDNS Backend Driver * Fix bug #1075268 - Support multiple notification handlers listening to the same notification type * Log messages produced by the Keystone Auth Token middleware * Add support for a "sudo" like mechanism in the API * Add dummy versions list endpoint * Add support for admin-reserved DNS domain name suffixes * Add support for PTR records * *Really* cleanup the sample config this time * Sync with oslo a8973c52 * Add tests for API 409 Handling (Duplicates / Conflicts) * Add tests for API 404 Handling * Handle RPC timeout's appropriately in the API * Updated Docs with recent API changes, particularly records * Cleanup sample config file * Add tests for KeystoneContextMiddleware and NoAuthMiddleware * Allow wildcard DNS records using a * * Update MANIFEST.in to ensure only sample configs are included * Ensure `moniker-manage --version` reports the correct version number * Sync with oslo-incubator ad93e4e3 * Fix coverage output folder * Switch to a single config file, using a config group per service * Fixup default policy.json * Allow configuration file to be specified via --config-file * Add more happy path API tests for servers/domains/records * Ensure Schema handle datetime objects appropriately * Centralize argv slicing * Use consistent base class name for moniker.backend tests * Remove dead code from moniker.storage * Fixup hostname regex + add some tests for valid host names * Provide sample logdir config option * Sync with oslo 8888ad01 * Ensure bin/moniker-manage is executable * Ensure MANIFEST.in is correct - No longer include *.pyc * Exclude ST2 project file from sdist * Ditch pre_version argument to oslo-version * Added generic SQLOPTS * Record TTL should default to, and accept, NULL values * Remove unnecessary if/else block from the bind9 zone template * Move database_connection sample config to the correct section * Remove unnecessary steps from the install guide * Ensure partial API updates are validated correctly * Include setup-requires in tox.ini * Sync with Oslo e6c576d9 * Fixup sample moniker-api.conf * moniker-manage CLI should read DB connection string from correct config group * Minor install doc corrections * Ensure Plugin config declarations are compatible with oslo-config's `import_opt` method * Partial fix for bug #1074093 * Correctly raise Duplicate exceptions with MySQL * Fixup migration #3 for MySQL * Add /bind9 to .gitignore * Fixup bind9 zone template * bug #1086467, fixed by using moniker record ID in dns_domains column * Fixup final pyflakes error + enable pyflakes check by default * Fixup Server JSONSchema * Allow the central and agent services to have separate defaults for the backend_driver config option * cfg.CONF is a global, let's not pass it around unnecessarily * Add backend_driver default to moniker-central.conf * Switch to plain .json schemas and improve Schema handling * Added central backend changes and rpc plugin. Added write_database flag to mysqlbind agent * Fix inconsistencies in use of IPAddr and UUID instances * Fixup API after breakage in change Ie65b6d25 * Cleanup use of Flask Blueprint's in the API * Sync with Oslo-Incubator 1fd7694e * Move SQLA types to shared location * Add empty testcase for the MySQL Bind9 backend * Working mysqlbind agent. Thank you to Endre and Kiall for the help! * Fixed a single-letter typo in docs * Move out session from the sqlalchemy impl to a more re-usable place * Keystone helper * Change the use of self.conf to cfg.CONF[self.name] * Fixup sample agent config * Tests cleanup and add helpers * Add more test helpers * More install doc corrections * Install doc corrections * POST helper for API tests * Do teardown properly * Abstract test functionality a bit more - make more use of get_*_fixture * Fixup config access in bind9 backend * Add DB init commands to README.md * Add first API test for listing servers * The PyFlakes tox env should not run by default * Process only events with handlers - skip the rest * Fixes bug #1081525 * Typo fix in install docs * Move fixtures to be available to all tests * Move docs where they belong (RTFD) * Add cliff to pip-requires and ensure all bin/ files are checked with pep8 * Make us client library independent for server side operations * Fix so it invokes on load * Generalize tests of plugins take 2, bug #1080415 * Add Quantum handlers for floating ip with tests * Fixes bug #1080467 * Generalize testcases for handlers, bug #1080415 * Fix broken version for migrate. * Implemented deltetion in the bind9 agent, fixed deletion in the backend, added migrate for foreign key changes * Cleanup tox / test deps * Fix most issues identified by PyFlakes * Add PyFlakes tox env * Update readme a bit * Add Quantum samples * Minor test cleanups * Remove `get_config_overrides` method from tests * Add policy checks for all resource create/update/delete/get/list actions * Pull Keystone middleware from the keystone client package * Restrict the Servers resource to admin users * Parse roles from Keystone into the Context * Track plugin name and type within records * Update the docs to use virtualenv's --no-site-packages flag * Update docs according to latest plugin change * Abstract out functionality into plugins * Fixed bind9 agent backend to handle new domains properly * Add *.egg to .gitignore * Subclass OS-Common's Context class * Added fix to zone template to append dot to end of data for various records that require it * Add utils.resource_string() method * Ensure Agent service calls the backends register_opts() method * Be consistent with sample state_path configuration value * Switch bind9 agent to a driver based implementation * Sync up notification handler test naming * Remove backported unittest assertions in favour of unittest2 * Ensure database-connection config variable is defined correctly * Minor sample config file fixes * Make notification handler config option name consistent * Add nosexcover and nosehtmloutput Nosetests plugins to tools/test-requires * Document state-path configuration option * Fix bug #1075595 - Ensure a missing configuration file raises an error * Ensure the bind9 agent logs an error when there are no servers configured * Provide a sane sample database_connection config value * Ensure we depend on SQLAlchemy 7.x * Added moniker API documentation * Re-order tox.ini sections * Fixup broken migration * Cleanup UnitTest assert backports * Add initial support for handling notifications from other OpenStack services * Add filtering to the storage layers get_* methods * Split on "+" to determine driver. * Update requirements for monikerclient -> python-monikerclient * Add pypi trove classifiers * Import and make use of openstack.common.version module * Sync with OS-Common 3d6c2368a5de16d875341426db8ddc9888213264 * Remove duplicated line from docs * Update docs a little * Add requirements for RTD * Cache pip downloads on Jenkins * Remove Travis CI config, now that Moniker is on Gerrit * Fixup deps and tox.ini for Stackforge+Gerrit * Update docs for Servers API * Hide autogenated doc files in Sublime Text 2 project * Add sample API call to the sphinx docs (It's not necessarily accurate!) * Add sphinx doc skeleton * Update MANIFEST.in * Ensure CLI only loads local file if it exists * Move optional dep's to their own file * Use a local config file only when it exists * Sync with OS Common aca1805d911caefe14a73edb6ced281cf54e7ad2 * Update default config files * Remove DB migrations from TODO list * Move SQLA dep in pip-requires to indicate it is optional (kinda) * Complete Skipped storage tests * Ensure we use a single Service instance per test case * Ensure tearDown is performed in the reverse order of setUp * Switch from Query.filter() -> Query.get() for single record fetches * Add Storage test for get_record/get_records * Minor cleanup * Lower the default SQL debug level * NULL is an acceptable value for tenant_id * Ensure `moniker database` commands read the moniker-central config file * Cleanup SQLA migrate changes + "Un-Abstract" the type definitions * Migrate scripts now work! Also re-coded the tenant_id NULL fix * Found a bug that allows insertion into domains with NULL tenant_id * Changes to get sqlalchemy migrate to work. Still not there * Move create/destroy DB hacks to the tests themselves, and ensure they respect the storage driver choice * Update DB CLI commands for database -> storage changes * Fixup previous commit * Saner default values for Path+DB configs * Ensure the SQLA tests actually use the SQLA driver * Remove unnecessary hack inherited from ceilometer * Rename "sqla" to "impl_sqlalchemy" * Fix license headers and skip setting engine before connection * Attempt to make backends more driver based like in Ceilometer * Switch from git:// to GubHub tarball via https for python-monikerclient dep * Rename sql_connection to the more generic database_connection * PEP8 Fix * Add database init + sync commands * Backport a few of assert methods not present in Py26. Fixes the tests on Py26 * Remove pypi from travis-ci config * Add openstack.nose_plugin as a test dep * Add Openstack-Nose test dep * Fixup Travis-CI and tox config * Two newlines needed for zone files that have more than one RR to have one newline at end * Add Travis-CI config file * Final fixes for migrations addition * Add tests policy.json * Ensure utils.find_config() raises correctly on failure to find config * Policy implementation (part 1) * Add Database driver server method tests * Ensure agents recieve the correct params for delete_domain calls * Handle `exceptions.Forbidden` appropriately in the API * Correct handling of duplicates * Fixup PEP8 errors in previous merge + remove license info from empty files * Add SQLAlchemy Migrate dep * Add some missing deps required by OS-Common * Delete duplicated schemas.py * Include newer bin/ files on tox pep8 checks * Use the latest version of PEP8 * Re-creating changes, this time with Git identity set! * Changes to models.py to set column width * Added initial migration scripts * Add PasteDeploy dep to tools/pip-requires * Remove duplicate requirement on setuptools-git * Extract setup-requires from setup.py * Add tests_require to setup.py * Move TODO's to the bottom on the readme * Move some dep's from test-requires to pip-requires * Add some *really* basic instructions * Add .venv to gitignore file * Ensure all bin/ files are as "dumb" as possible * Add Moniker Central tests for domains and records * Remove temporary keystone config options * Remove Debug API endpoint + Remove some unneeded imports * Switch from Flask's WSGI Server to OpenStack Commons + Use PasteDeploy for easier Keystone integration * Add OpenStack Common WSGI module * Ensuring fitering a empty collection works * Move API app from __init__.py -> app.py * Use fake RPC backend for testing * Add Moniker Central server management tests * Remove some un-used imports * Move create schema hack into into it's own method * Add tox and venv to ST2 folder ignores * Fix another missing license header * Add skeleton test framework * Fix license headers * Make use of OpenStack Common setup module * Ensure the bind9 agent's output path is created, if necessary * Ensure delete's are flushed to the DB immediately * Ensure moniker's exceptions are re-raised over RPC * Reapply WIP openstack common patch from https://review.openstack.org/#/c/13953/ * Ensure the RNDC call only supplies a config file option if one has been explicitly set * Remove leftover config file * Sync with OpenStack Common rev f182936b * Add some temp config vars to disable keystone and use a default tenant/user instead * Lots of changes: * Add utils and exception modules from openstack-common * Switch default sql_connection to an in-memory sqlite DB * Sync to openstack-common rev 974989d9 * Remove leftover file * Add TODO note * Rename TODO list * Initial Public Commit designate-2.0.0/PKG-INFO0000664000567000056710000000650312701406373015721 0ustar jenkinsjenkins00000000000000Metadata-Version: 1.1 Name: designate Version: 2.0.0 Summary: DNS as a Service Home-page: https://launchpad.net/designate Author: Kiall Mac Innes Author-email: kiall@managedit.ie License: UNKNOWN Description: =================== OpenStack Designate =================== Designate is an OpenStack project, providing DNSaaS. IRC: #openstack-dns Installation: http://docs.openstack.org/developer/designate/getting-started.html Development =========== Designate follows the `OpenStack Gerrit Workflow`_ Setup ----- Setup a working environment: .. code-block:: shell git clone https://github.com/openstack/designate.git cd designate virtualenv .venv . .venv/bin/activate pip install -r requirements.txt -r test-requirements.txt python setup.py develop Building Docs ------------- To build the documentation from the restructured text source, do the following: .. code-block:: shell cd doc pip install -r requirements.txt sphinx-build source/ build/html/ now point your browser at html/index.html (the official documentation is published to `docs.openstack.org`_ by the maintainers. Contributing ------------ Install the git-review package to make life easier .. code-block:: shell pip install git-review Branch, work, & submit: .. code-block:: shell # cut a new branch, tracking master git checkout --track -b bug/id origin/master # work work work git add stuff git commit # rebase/squash to a single commit before submitting git rebase -i # submit git-review Testing ------- Execute a single test using py27 (test is CentralServiceTest.test_count_domains) .. code-block:: shell tox -e py27 -- designate.tests.test_central.test_service.CentralServiceTest.test_count_zones_policy_check * Free software: Apache license * Documentation: http://docs.openstack.org/developer/designate * Source: http://git.openstack.org/cgit/openstack/designate * Bugs: http://bugs.launchpad.net/designate .. _OpenStack Gerrit Workflow: http://docs.openstack.org/infra/manual/developers.html#development-workflow .. _docs.openstack.org: http://docs.openstack.org/developer/designate Platform: UNKNOWN Classifier: Environment :: OpenStack Classifier: Environment :: No Input/Output (Daemon) Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: POSIX :: Linux Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Topic :: Internet :: Name Service (DNS) designate-2.0.0/rally-jobs/0000775000567000056710000000000012701406373016676 5ustar jenkinsjenkins00000000000000designate-2.0.0/rally-jobs/plugins/0000775000567000056710000000000012701406373020357 5ustar jenkinsjenkins00000000000000designate-2.0.0/rally-jobs/plugins/__init__.py0000664000567000056710000000000012701406241022450 0ustar jenkinsjenkins00000000000000designate-2.0.0/rally-jobs/plugins/README.rst0000664000567000056710000000060112701406241022035 0ustar jenkinsjenkins00000000000000Rally plugins ============= All *.py modules from this directory will auto loaded by Rally and all plugins will be discoverable. There is no need in any extra configuration and there is no difference between writing them here and in rally code base. Note that it is better to push to Rally code base all interested and useful benchmarks, as that simplifies a lot life of operators. designate-2.0.0/rally-jobs/designate-designate.yaml0000664000567000056710000000255112701406241023463 0ustar jenkinsjenkins00000000000000--- DesignateBasic.create_and_delete_domain: - runner: type: "constant" times: 10 concurrency: 10 context: users: tenants: 2 users_per_tenant: 2 sla: failure_rate: max: 0 DesignateBasic.create_and_delete_records: - args: records_per_domain: 10 runner: type: "constant" times: 10 concurrency: 10 context: users: tenants: 2 users_per_tenant: 2 sla: failure_rate: max: 0 DesignateBasic.create_and_list_domains: - runner: type: "constant" times: 10 concurrency: 10 context: users: tenants: 2 users_per_tenant: 2 sla: failure_rate: max: 0 DesignateBasic.create_and_list_records: - args: records_per_domain: 10 runner: type: "constant" times: 10 concurrency: 10 context: users: tenants: 2 users_per_tenant: 2 sla: failure_rate: max: 0 DesignateBasic.list_domains: - runner: type: "constant" times: 3 concurrency: 2 context: users: tenants: 2 users_per_tenant: 2 sla: failure_rate: max: 0 designate-2.0.0/rally-jobs/extra/0000775000567000056710000000000012701406373020021 5ustar jenkinsjenkins00000000000000designate-2.0.0/rally-jobs/extra/README.rst0000664000567000056710000000025412701406241021503 0ustar jenkinsjenkins00000000000000Extra files =========== All files from this directory will be copy pasted to gates, so you are able to use absolute path in rally tasks. Files will be in ~/.rally/extra/* designate-2.0.0/rally-jobs/README.rst0000664000567000056710000000165712701406241020370 0ustar jenkinsjenkins00000000000000Rally job related files ======================= This directory contains rally tasks and plugins that are run by OpenStack CI. Structure: * designate-designate.yaml is rally task that will be run in gates * plugins - directory where you can add rally plugins. Almost everything in Rally is plugin. Benchmark context, Benchmark scenario, SLA checks, Generic cleanup resources, .... * extra - all files from this directory will be copy pasted to gates, so you are able to use absolute path in rally tasks. Files will be in ~/.rally/extra/* Useful links: * More about Rally: https://rally.readthedocs.org/en/latest/ * Rally release notes: https://rally.readthedocs.org/en/latest/release_notes.html * How to add rally-gates: https://rally.readthedocs.org/en/latest/gates.html * About plugins: https://rally.readthedocs.org/en/latest/plugins.html * Plugin samples: https://github.com/openstack/rally/tree/master/samples/plugins designate-2.0.0/tox.ini0000664000567000056710000000636312701406243016137 0ustar jenkinsjenkins00000000000000[tox] minversion = 1.6 envlist = py34,py27,flake8 skipsdist = True [testenv] usedevelop = True install_command = pip install {opts} {packages} deps = -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt setenv = PYTHONDONTWRITEBYTECODE=1 whitelist_externals = sh find rm commands = find . -type f -name "*.pyc" -delete sh tools/pretty_tox.sh '{posargs}' passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY [testenv:py34] commands = ostestr --blacklist_file=tests-py3.txt [testenv:docs] commands = python setup.py build_sphinx -E [testenv:cover] commands = python setup.py testr --coverage --testr-args='{posargs}' [testenv:bandit] deps = -r{toxinidir}/test-requirements.txt commands = bandit -c bandit.yaml -r designate -n5 -p gate [testenv:debug] commands = oslo_debug_helper {posargs} [testenv:flake8] commands = sh tools/pretty_flake8.sh [testenv:pep8] basepython = python2.7 commands = sh tools/pretty_flake8.sh [testenv:pyflakes] commands = sh tools/pretty_flake8.sh [testenv:bashate] deps = bashate whitelist_externals = bash commands = bash -c "find {toxinidir}/devstack \ -not \( -type d -name .?\* -prune \) \ -not \( -type d -name doc -prune \) \ -type f \ -not -name \*~ \ -not -name \*.md \ \( \ -name \*.sh -or \ -name \*rc -or \ -name functions\* -or \ -wholename \*/lib/\* \ \) \ -print0 | xargs -0 bashate -v" [testenv:pip-check-reqs] # do not install test-requirements as that will pollute the virtualenv for # determining missing packages # this also means that pip-missing-reqs must be installed separately, outside # of the requirements.txt files deps = pip-check-reqs -r{toxinidir}/requirements.txt commands=pip-missing-reqs -d --ignore-file=designate/tests/* designate [testenv:functional] usedevelop = False setenv = VIRTUAL_ENV={envdir} OS_TEST_PATH=functionaltests/ passenv = TEMPEST_CONFIG OS_STDOUT_CAPTURE OS_STDERR_CAPTURE OS_LOG_CAPTURE OS_DEBUG [testenv:releasenotes] commands = sphinx-build -a -E -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html [testenv:venv] commands = {posargs} [flake8] # ignored flake8 codes: # H302 import only modules # H306 imports not in alphabetical order # H402 one line docstring needs punctuation # H404 multi line docstring should start with a summary # H405 multi line docstring summary not separated with an empty line # H904 Wrap long lines in parentheses instead of a backslash # E126 continuation line over-indented for hanging indent # E128 continuation line under-indented for visual indent ignore = H302,H306,H402,H404,H405,H904,E126,E128 exclude = .venv,.git,.tox,dist,doc,*openstack/common*,*openstack/deprecated*,*lib/python*,*egg,build,tools,.ropeproject [hacking] local-check-factory = designate.hacking.checks.factory designate-2.0.0/contrib/0000775000567000056710000000000012701406373016260 5ustar jenkinsjenkins00000000000000designate-2.0.0/contrib/vagrant/0000775000567000056710000000000012701406373017722 5ustar jenkinsjenkins00000000000000designate-2.0.0/contrib/vagrant/local.conf0000664000567000056710000000650412701406241021662 0ustar jenkinsjenkins00000000000000[[local|localrc]] # General DevStack Config # ======================= ADMIN_PASSWORD=password MYSQL_PASSWORD=password RABBIT_PASSWORD=password SERVICE_PASSWORD=password SERVICE_TOKEN=password # IP Address for services to bind to (Should match IP from Vagrantfile) SERVICE_HOST=192.168.27.100 # Logging #LOGFILE=/opt/stack/logs/stack.sh.log SCREEN_LOGDIR=/opt/stack/logs VERBOSE=True LOG_COLOR=True # Disable all services except core ones disable_all_services enable_service rabbit mysql key # Enable designate enable_plugin designate https://git.openstack.org/openstack/designate # Designate Devstack Config # ========================= # Enable core Designate services enable_service designate,designate-central,designate-api,designate-pool-manager,designate-zone-manager,designate-mdns # Optional Designate services #enable_service designate-agent #enable_service designate-sink # Backend Driver (e.g. powerdns, bind9. See designate.backend section of # setup.cfg) #DESIGNATE_BACKEND_DRIVER=powerdns # Pool Manager Cache Driver (e.g. noop, memcache, sqlalchemy. See # designate.backend section of setup.cfg) #DESIGNATE_POOL_MANAGER_CACHE_DRIVER=memcache # mDNS Service DNS Port Number #DESIGNATE_SERVICE_PORT_MDNS=5354 # Designate Backend Config # ======================== # DynECT Backend # NOTEs: # - DynECT requires DESIGNATE_SERVICE_PORT_MDNS is set to "53" # - DESIGNATE_DYNECT_MASTERS must be a Publicly reachable IP, pointed to mDNS #DESIGNATE_DYNECT_CUSTOMER= #DESIGNATE_DYNECT_USERNAME= #DESIGNATE_DYNECT_PASSWORD= #DESIGNATE_DYNECT_NAMESERVERS=ns1.p13.dynect.net,ns2.p13.dynect.net,ns3.p13.dynect.net,ns4.p13.dynect.net #DESIGNATE_DYNECT_MASTERS= # Akamai Backend #DESIGNATE_AKAMAI_USERNAME= #DESIGNATE_AKAMAI_PASSWORD= #DESIGNATE_AKAMAI_NAMESERVERS=a5-64.akam.net,a11-65.akam.net,a13-66.akam.net,a14-64.akam.net,a20-65.akam.net,a22-66.akam.net #DESIGNATE_AKAMAI_MASTERS= # Designate D2D Backend # NOTEs: # - DESIGNATE_D2D_ALSO_NOTIFIES needs to be set to the source mdns ip:port in # order for designate to receive the proper NOTIFY # - DESIGNATE_D2D_* credentials should be setup either to the source keystone # or the destination #DESIGNATE_D2D_MASTERS= #DESIGNATE_D2D_ALSO_NOTIFIES= #DESIGNATE_D2D_NAMESERVERS= # Authentication options #DESIGNATE_D2D_KS_VERSION=3 #DESIGNATE_D2D_AUTH_URL= #DESIGNATE_D2D_USERNAME= #DESIGNATE_D2D_PASSWORD= # Keystone V2 #DESIGNATE_D2D_TENANT_NAME=${DESIGNATE_D2D_TENANT_NAME:-} #DESIGNATE_D2D_TENANT_NAME=${DESIGNATE_D2D_TENANT_ID:-} # Keystone V3 #DESIGNATE_D2D_PROJECT_NAME= #DESIGNATE_D2D_PROJECT_DOMAIN_NAME= #DESIGNATE_D2D_USER_DOMAIN_NAME= # Designate Misc Config # ===================== # Enable a Notification Driver (e.g. for Ceiliometer) #DESIGNATE_NOTIFICATION_DRIVER=messaging # Set Notification topics #DESIGNATE_NOTIFICATION_TOPICS=notifications # Set coordination service URL (e.g. kazoo://localhost/) #DESIGNATE_COORDINATION_URL= # Other Devstack Config # ===================== # Optional TLS Proxy #enable_service tls-proxy # Optional Tempest #enable_service tempest # Optional Rally #enable_service rally # Optional Horizon #enable_service horizon # Optional Glance #enable_service g-api,g-reg # Optional Nova #enable_service n-api n-cpu n-net n-cond n-sch n-novnc # Optional Neutron #disable_service n-net #enable_service q-svc q-agt q-dhcp q-l3 q-meta designate-2.0.0/contrib/vagrant/Vagrantfile0000664000567000056710000000753512701406241022113 0ustar jenkinsjenkins00000000000000VAGRANTFILE_API_VERSION = "2" GITCONFIG = `cat $HOME/.gitconfig` Vagrant.require_version ">= 1.5" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.ssh.forward_agent = true config.vm.network "forwarded_port", guest: 5354, host: 5354, protocol: "tcp" config.vm.network "forwarded_port", guest: 5354, host: 5354, protocol: "udp" config.vm.provider "virtualbox" do |vb, override| vb.customize ["modifyvm", :id, "--memory", "2048"] if not RUBY_PLATFORM.downcase.include?("mswin") vb.customize ["modifyvm", :id, "--cpus", `awk "/^processor/ {++n} END {print n}" /proc/cpuinfo 2> /dev/null || sh -c 'sysctl hw.logicalcpu 2> /dev/null || echo ": 2"' | awk \'{print \$2}\' `.chomp ] end vb.customize ["modifyvm", :id, "--nicpromisc3", "allow-all"] override.vm.synced_folder "../..", "/opt/stack/designate" if File.directory?("../../../python-designateclient") override.vm.synced_folder "../../../python-designateclient", "/opt/stack/python-designateclient" end if File.directory?("../../../designate-dashboard") override.vm.synced_folder "../../../designate-dashboard", "/opt/stack/designate-dashboard" end if File.directory?("../../../../openstack/rally") override.vm.synced_folder "../../../../openstack/rally", "/opt/stack/rally" end end config.vm.provider :libvirt do |lv, override| lv.graphics_ip = '0.0.0.0' lv.nested = true lv.memory = 8192 if not RUBY_PLATFORM.downcase.include?("mswin") lv.cpus = `awk "/^processor/ {++n} END {print n}" /proc/cpuinfo 2> /dev/null || sh -c 'sysctl hw.logicalcpu 2> /dev/null || echo ": 2"' | awk \'{print \$2}\' `.chomp end override.vm.synced_folder ".", "/vagrant", type: "nfs" override.vm.synced_folder "../..", "/opt/stack/designate", type: "nfs" if File.directory?("../../../python-designateclient") override.vm.synced_folder "../../../python-designateclient", "/opt/stack/python-designateclient", type: "nfs" end if File.directory?("../../../designate-dashboard") override.vm.synced_folder "../../../designate-dashboard", "/opt/stack/designate-dashboard", type: "nfs" end if File.directory?("../../../../openstack/rally") override.vm.synced_folder "../../../../openstack/rally", "/opt/stack/rally", type: "nfs" end end $script = <