From c318106c01b2b3976049f2c3ba0c8502a874242b Mon Sep 17 00:00:00 2001 From: Graham Hayes Date: Fri, 17 Nov 2017 17:17:38 +0000 Subject: [PATCH] Remove v1 API This completes the long awaited removal of the V1 API. Change-Id: I30c8a5e8569b1b86286c5e3cb07856c06ebe5803 --- .../versions/get-versions-response.json | 10 - contrib/ipaextractor.py | 362 -------- designate/api/__init__.py | 12 - designate/api/middleware.py | 17 - designate/api/v1/__init__.py | 149 --- designate/api/v1/domains.py | 173 ---- designate/api/v1/extensions/__init__.py | 0 designate/api/v1/extensions/diagnostics.py | 34 - designate/api/v1/extensions/quotas.py | 83 -- designate/api/v1/extensions/reports.py | 78 -- designate/api/v1/extensions/sync.py | 52 -- designate/api/v1/extensions/touch.py | 31 - designate/api/v1/limits.py | 46 - designate/api/v1/records.py | 277 ------ designate/api/v1/servers.py | 226 ----- designate/api/v1/tsigkeys.py | 155 ---- designate/api/versions.py | 4 - designate/common/policies/record.py | 72 -- designate/common/policies/recordset.py | 37 - designate/common/policies/tsigkey.py | 18 - designate/common/policies/zone.py | 38 - designate/objects/adapters/api_v1/__init__.py | 0 designate/objects/adapters/api_v1/base.py | 20 - designate/resources/schemas/v1/domain.json | 76 -- designate/resources/schemas/v1/domains.json | 17 - designate/resources/schemas/v1/fault.json | 53 -- designate/resources/schemas/v1/limits.json | 29 - designate/resources/schemas/v1/record.json | 246 ----- designate/resources/schemas/v1/records.json | 17 - designate/resources/schemas/v1/server.json | 44 - designate/resources/schemas/v1/servers.json | 17 - designate/resources/schemas/v1/tsigkey.json | 43 - designate/resources/schemas/v1/tsigkeys.json | 17 - designate/schema/__init__.py | 6 +- designate/tests/test_api/test_v1/__init__.py | 118 --- .../tests/test_api/test_v1/test_domains.py | 522 ----------- .../tests/test_api/test_v1/test_limits.py | 39 - .../tests/test_api/test_v1/test_records.py | 862 ------------------ .../tests/test_api/test_v1/test_servers.py | 244 ----- .../tests/test_api/test_v1/test_tsigkeys.py | 136 --- designate/tests/test_schema/__init__.py | 4 +- designate/tests/test_utils.py | 5 - devstack/gate/run_tempest_tests.sh | 2 +- devstack/plugin.sh | 3 - devstack/settings | 2 - doc/source/configuration/index.rst | 11 - doc/source/examples/basic-config-sample.conf | 130 --- doc/source/install/install-obs.rst | 2 - doc/source/install/install-rdo.rst | 2 - doc/source/install/install-ubuntu.rst | 2 - doc/source/user/manage-ptr-records.rst | 135 --- doc/source/user/rest.rst | 33 +- doc/source/user/rest/v1/diagnostics.rst | 66 -- doc/source/user/rest/v1/domains.rst | 293 ------ doc/source/user/rest/v1/quotas.rst | 141 --- doc/source/user/rest/v1/records.rst | 832 ----------------- doc/source/user/rest/v1/reports.rst | 238 ----- doc/source/user/rest/v1/servers.rst | 205 ----- doc/source/user/rest/v1/sync.rst | 112 --- etc/designate/api-paste.ini | 15 - etc/designate/policy.yaml.sample | 70 +- .../grenade-devstack-designate-pdns4/run.yaml | 2 +- .../notes/remove-v1-api-e38de408c6454de2.yaml | 9 + setup.cfg | 13 - 64 files changed, 25 insertions(+), 6682 deletions(-) delete mode 100644 contrib/ipaextractor.py delete mode 100644 designate/api/v1/__init__.py delete mode 100644 designate/api/v1/domains.py delete mode 100644 designate/api/v1/extensions/__init__.py delete mode 100644 designate/api/v1/extensions/diagnostics.py delete mode 100644 designate/api/v1/extensions/quotas.py delete mode 100644 designate/api/v1/extensions/reports.py delete mode 100644 designate/api/v1/extensions/sync.py delete mode 100644 designate/api/v1/extensions/touch.py delete mode 100644 designate/api/v1/limits.py delete mode 100644 designate/api/v1/records.py delete mode 100644 designate/api/v1/servers.py delete mode 100644 designate/api/v1/tsigkeys.py delete mode 100644 designate/objects/adapters/api_v1/__init__.py delete mode 100644 designate/objects/adapters/api_v1/base.py delete mode 100644 designate/resources/schemas/v1/domain.json delete mode 100644 designate/resources/schemas/v1/domains.json delete mode 100644 designate/resources/schemas/v1/fault.json delete mode 100644 designate/resources/schemas/v1/limits.json delete mode 100644 designate/resources/schemas/v1/record.json delete mode 100644 designate/resources/schemas/v1/records.json delete mode 100644 designate/resources/schemas/v1/server.json delete mode 100644 designate/resources/schemas/v1/servers.json delete mode 100644 designate/resources/schemas/v1/tsigkey.json delete mode 100644 designate/resources/schemas/v1/tsigkeys.json delete mode 100644 designate/tests/test_api/test_v1/__init__.py delete mode 100644 designate/tests/test_api/test_v1/test_domains.py delete mode 100644 designate/tests/test_api/test_v1/test_limits.py delete mode 100644 designate/tests/test_api/test_v1/test_records.py delete mode 100644 designate/tests/test_api/test_v1/test_servers.py delete mode 100644 designate/tests/test_api/test_v1/test_tsigkeys.py delete mode 100644 doc/source/examples/basic-config-sample.conf delete mode 100644 doc/source/user/rest/v1/diagnostics.rst delete mode 100644 doc/source/user/rest/v1/domains.rst delete mode 100644 doc/source/user/rest/v1/quotas.rst delete mode 100644 doc/source/user/rest/v1/records.rst delete mode 100644 doc/source/user/rest/v1/reports.rst delete mode 100644 doc/source/user/rest/v1/servers.rst delete mode 100644 doc/source/user/rest/v1/sync.rst create mode 100644 releasenotes/notes/remove-v1-api-e38de408c6454de2.yaml diff --git a/api-ref/source/samples/versions/get-versions-response.json b/api-ref/source/samples/versions/get-versions-response.json index 3c9615494..f490a02d4 100644 --- a/api-ref/source/samples/versions/get-versions-response.json +++ b/api-ref/source/samples/versions/get-versions-response.json @@ -1,16 +1,6 @@ { "versions": { "values": [ - { - "id": "v1", - "links": [ - { - "href": "http://127.0.0.1:9001/v1", - "rel": "self" - } - ], - "status": "DEPRECATED" - }, { "id": "v2", "links": [ diff --git a/contrib/ipaextractor.py b/contrib/ipaextractor.py deleted file mode 100644 index 4e49d54f4..000000000 --- a/contrib/ipaextractor.py +++ /dev/null @@ -1,362 +0,0 @@ -# Copyright (C) 2014 Red Hat, Inc. -# -# Author: Rich Megginson -# -# 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 sys -import logging -import pprint -import json -import copy - -import requests -from oslo_config import cfg - -from designate.backend import impl_ipa -from designate.i18n import _LI -from designate.i18n import _LW -from designate.i18n import _LE -from designate import utils - - -logging.basicConfig() -LOG = logging.getLogger(__name__) - -cfg.CONF.import_opt('api_base_uri', 'designate.api', 'service:api') -cfg.CONF.import_opt('backend_driver', 'designate.central', 'service:central') - - -class NoNameServers(Exception): - pass - - -class AddServerError(Exception): - pass - - -class DeleteServerError(Exception): - pass - - -class AddDomainError(Exception): - pass - - -class DeleteDomainError(Exception): - pass - - -class AddRecordError(Exception): - pass - - -cuiberrorstr = """ERROR: You cannot have Designate configured -to use the IPA backend when running this script. It will wipe -out your IPA DNS data. Please follow these steps: -* shutdown designate-central -* edit designate.conf -[service:central] -backend_driver = fake # or something other than ipa -* restart designate-central and other designate services -""" - - -class CannotUseIPABackend(Exception): - pass - - -# create mapping of ipa record types to designate types -iparectype2designate = {} -for rectype, tup in list(impl_ipa.rectype2iparectype.items()): - iparectype = tup[0] - iparectype2designate[iparectype] = rectype - - -# using the all: True flag returns fields we can't use -# strip these keys from zones -zoneskips = ['dn', 'nsrecord', 'idnszoneactive', 'objectclass'] - - -def rec2des(rec, zonename): - """Convert an IPA record to Designate format. A single IPA record - returned from the search may translate into multiple Designate. - IPA dnsrecord_find returns a "name". Each DNS name may contain - multiple record types. Each record type may contain multiple - values. Each one of these values must be added separately to - Designate. This function returns all of those as a list of - dict designate records. - """ - # convert record name - if rec['idnsname'][0] == '@': - name = zonename - else: - name = rec['idnsname'][0] + "." + zonename - # find all record types - rectypes = [] - for k in rec: - if k.endswith("record"): - if k in iparectype2designate: - rectypes.append(k) - else: - LOG.info(_LI("Skipping unknown record type " - "%(type)s in %(name)s"), - {'type': k, 'name': name}) - - desrecs = [] - for rectype in rectypes: - dtype = iparectype2designate[rectype] - for ddata in rec[rectype]: - desreq = {'name': name, 'type': dtype} - if dtype == 'SRV' or dtype == 'MX': - # split off the priority and send in a separate field - idx = ddata.find(' ') - desreq['priority'] = int(ddata[:idx]) - if dtype == 'SRV' and not ddata.endswith("."): - # if server is specified as relative, add zonename - desreq['data'] = ddata[(idx + 1):] + "." + zonename - else: - desreq['data'] = ddata[(idx + 1):] - else: - desreq['data'] = ddata - if rec.get('description', [None])[0]: - desreq['description'] = rec.get('description')[0] - if rec.get('ttl', [None])[0]: - desreq['ttl'] = int(rec['dnsttl'][0]) - desrecs.append(desreq) - return desrecs - - -def zone2des(ipazone): - # next, try to add the fake domain to Designate - zonename = ipazone['idnsname'][0].rstrip(".") + "." - email = ipazone['idnssoarname'][0].rstrip(".").replace(".", "@", 1) - desreq = {"name": zonename, - "ttl": int(ipazone['idnssoarefresh'][0]), - "email": email} - return desreq - - -def getipadomains(ipabackend, version): - # get the list of domains/zones from IPA - ipareq = {'method': 'dnszone_find', - 'params': [[], {'version': version, - 'all': True}]} - iparesp = ipabackend._call_and_handle_error(ipareq) - LOG.debug("Response: %s" % pprint.pformat(iparesp)) - return iparesp['result']['result'] - - -def getiparecords(ipabackend, zonename, version): - ipareq = {'method': 'dnsrecord_find', - 'params': [[zonename], {"version": version, - "all": True}]} - iparesp = ipabackend._call_and_handle_error(ipareq) - return iparesp['result']['result'] - - -def syncipaservers2des(servers, designatereq, designateurl): - # get existing servers from designate - dservers = {} - srvurl = designateurl + "/servers" - resp = designatereq.get(srvurl) - LOG.debug("Response: %s" % pprint.pformat(resp.json())) - if resp and resp.status_code == 200 and resp.json() and \ - 'servers' in resp.json(): - for srec in resp.json()['servers']: - dservers[srec['name']] = srec['id'] - else: - LOG.warning(_LW("No servers in designate")) - - # first - add servers from ipa not already in designate - for server in servers: - if server in dservers: - LOG.info(_LI("Skipping ipa server %s already in designate"), - server) - else: - desreq = {"name": server} - resp = designatereq.post(srvurl, data=json.dumps(desreq)) - LOG.debug("Response: %s" % pprint.pformat(resp.json())) - if resp.status_code == 200: - LOG.info(_LI("Added server %s to designate"), server) - else: - raise AddServerError("Unable to add %s: %s" % - (server, pprint.pformat(resp.json()))) - - # next - delete servers in designate not in ipa - for server, sid in list(dservers.items()): - if server not in servers: - delresp = designatereq.delete(srvurl + "/" + sid) - if delresp.status_code == 200: - LOG.info(_LI("Deleted server %s"), server) - else: - raise DeleteServerError("Unable to delete %s: %s" % - (server, - pprint.pformat(delresp.json()))) - - -def main(): - # HACK HACK HACK - allow required config params to be passed - # via the command line - cfg.CONF['service:api']._group._opts['api_base_uri']['cli'] = True - for optdict in cfg.CONF['backend:ipa']._group._opts.values(): - if 'cli' in optdict: - optdict['cli'] = True - # HACK HACK HACK - allow api url to be passed in the usual way - utils.read_config('designate', sys.argv) - if cfg.CONF['service:central'].backend_driver == 'ipa': - raise CannotUseIPABackend(cuiberrorstr) - if cfg.CONF.debug: - LOG.setLevel(logging.DEBUG) - else: - LOG.setLevel(logging.INFO) - ipabackend = impl_ipa.IPABackend(None) - ipabackend.start() - version = cfg.CONF['backend:ipa'].ipa_version - designateurl = cfg.CONF['service:api'].api_base_uri + "v1" - - # get the list of domains/zones from IPA - ipazones = getipadomains(ipabackend, version) - # get unique list of name servers - servers = {} - for zonerec in ipazones: - for nsrec in zonerec['nsrecord']: - servers[nsrec] = nsrec - if not servers: - raise NoNameServers("Error: no name servers found in IPA") - - # let's see if designate is using the IPA backend - # create a fake domain in IPA - # create a fake server in Designate - # try to create the same fake domain in Designate - # if we get a DuplicateZone error from Designate, then - # raise the CannotUseIPABackend error, after deleting - # the fake server and fake domain - # find the first non-reverse zone - zone = {} - for zrec in ipazones: - if not zrec['idnsname'][0].endswith("in-addr.arpa.") and \ - zrec['idnszoneactive'][0] == 'TRUE': - # ipa returns every data field as a list - # convert the list to a scalar - for n, v in list(zrec.items()): - if n in zoneskips: - continue - if isinstance(v, list): - zone[n] = v[0] - else: - zone[n] = v - break - - assert(zone) - - # create a fake subdomain of this zone - domname = "%s.%s" % (utils.generate_uuid(), zone['idnsname']) - args = copy.copy(zone) - del args['idnsname'] - args['version'] = version - ipareq = {'method': 'dnszone_add', - 'params': [[domname], args]} - iparesp = ipabackend._call_and_handle_error(ipareq) - LOG.debug("Response: %s" % pprint.pformat(iparesp)) - if iparesp['error']: - raise AddDomainError(pprint.pformat(iparesp)) - - # set up designate connection - designatereq = requests.Session() - xtra_hdrs = {'Content-Type': 'application/json'} - designatereq.headers.update(xtra_hdrs) - - # sync ipa name servers to designate - syncipaservers2des(servers, designatereq, designateurl) - - domainurl = designateurl + "/domains" - # next, try to add the fake domain to Designate - email = zone['idnssoarname'].rstrip(".").replace(".", "@", 1) - desreq = {"name": domname, - "ttl": int(zone['idnssoarefresh'][0]), - "email": email} - resp = designatereq.post(domainurl, data=json.dumps(desreq)) - exc = None - fakezoneid = None - if resp.status_code == 200: - LOG.info(_LI("Added domain %s"), domname) - fakezoneid = resp.json()['id'] - delresp = designatereq.delete(domainurl + "/" + fakezoneid) - if delresp.status_code != 200: - LOG.error(_LE("Unable to delete %(name)s: %(response)s") % - {'name': domname, 'response': pprint.pformat( - delresp.json())}) - else: - exc = CannotUseIPABackend(cuiberrorstr) - - # cleanup fake stuff - ipareq = {'method': 'dnszone_del', - 'params': [[domname], {'version': version}]} - iparesp = ipabackend._call_and_handle_error(ipareq) - LOG.debug("Response: %s" % pprint.pformat(iparesp)) - if iparesp['error']: - LOG.error(_LE("%s") % pprint.pformat(iparesp)) - - if exc: - raise exc - - # get and delete existing domains - resp = designatereq.get(domainurl) - LOG.debug("Response: %s" % pprint.pformat(resp.json())) - if resp and resp.status_code == 200 and resp.json() and \ - 'domains' in resp.json(): - # domains must be deleted in child/parent order i.e. delete - # sub-domains before parent domains - simple way to get this - # order is to sort the domains in reverse order of name len - dreclist = sorted(resp.json()['domains'], - key=lambda drec: len(drec['name']), - reverse=True) - for drec in dreclist: - delresp = designatereq.delete(domainurl + "/" + drec['id']) - if delresp.status_code != 200: - raise DeleteDomainError("Unable to delete %s: %s" % - (drec['name'], - pprint.pformat(delresp.json()))) - - # key is zonename, val is designate rec id - zonerecs = {} - for zonerec in ipazones: - desreq = zone2des(zonerec) - resp = designatereq.post(domainurl, data=json.dumps(desreq)) - if resp.status_code == 200: - LOG.info(_LI("Added domain %s"), desreq['name']) - else: - raise AddDomainError("Unable to add domain %s: %s" % - (desreq['name'], pprint.pformat(resp.json()))) - zonerecs[desreq['name']] = resp.json()['id'] - - # get the records for each zone - for zonename, domainid in list(zonerecs.items()): - recurl = designateurl + "/domains/" + domainid + "/records" - iparecs = getiparecords(ipabackend, zonename, version) - for rec in iparecs: - desreqs = rec2des(rec, zonename) - for desreq in desreqs: - resp = designatereq.post(recurl, data=json.dumps(desreq)) - if resp.status_code == 200: - LOG.info(_LI("Added record %(record)s " - "for domain %(domain)s"), - {'record': desreq['name'], 'domain': zonename}) - else: - raise AddRecordError("Could not add record %s: %s" % - (desreq['name'], - pprint.pformat(resp.json()))) - -if __name__ == '__main__': - sys.exit(main()) diff --git a/designate/api/__init__.py b/designate/api/__init__.py index 8e18c8d23..c0a60284f 100644 --- a/designate/api/__init__.py +++ b/designate/api/__init__.py @@ -49,11 +49,6 @@ api_opts = [ cfg.StrOpt('auth_strategy', default='keystone', help='The strategy to use for auth. Supports noauth or ' 'keystone'), - cfg.BoolOpt('enable-api-v1', default=False, - deprecated_for_removal=True, - deprecated_reason="V1 API is being removed in a future" - "release", - help='enable-api-v1 which removed in a future'), cfg.BoolOpt('enable-api-v2', default=True, help='enable-api-v2 which enable in a future'), cfg.BoolOpt('enable-api-admin', default=False, @@ -65,11 +60,6 @@ api_opts = [ "Keystone v3 API with big service catalogs)."), ] -api_v1_opts = [ - cfg.ListOpt('enabled-extensions-v1', default=[], - help='Enabled API Extensions'), -] - api_v2_opts = [ cfg.ListOpt('enabled-extensions-v2', default=[], help='Enabled API Extensions for the V2 API'), @@ -109,7 +99,6 @@ api_middleware_opts = [ cfg.CONF.register_group(api_group) cfg.CONF.register_opts(api_opts, group=api_group) -cfg.CONF.register_opts(api_v1_opts, group=api_group) cfg.CONF.register_opts(api_v2_opts, group=api_group) cfg.CONF.register_opts(api_admin_opts, group=api_group) cfg.CONF.register_opts(api_middleware_opts, group=api_group) @@ -117,7 +106,6 @@ cfg.CONF.register_opts(api_middleware_opts, group=api_group) def list_opts(): yield api_group, api_opts - yield api_group, api_v1_opts yield api_group, api_v2_opts yield api_group, api_admin_opts yield api_group, api_middleware_opts diff --git a/designate/api/middleware.py b/designate/api/middleware.py index 15acacc84..e39f8962b 100644 --- a/designate/api/middleware.py +++ b/designate/api/middleware.py @@ -308,17 +308,6 @@ class FaultWrapperMiddleware(base.Middleware): response=json.dumps(response)) -class FaultWrapperMiddlewareV1(FaultWrapperMiddleware): - def _format_error(self, data): - replace_map = [ - ("zone", "domain",) - ] - - for i in replace_map: - data["type"] = data["type"].replace(i[0], i[1]) - print(data) - - class ValidationErrorMiddleware(base.Middleware): def __init__(self, application): @@ -370,12 +359,6 @@ class ValidationErrorMiddleware(base.Middleware): response=json.dumps(response)) -class APIv1ValidationErrorMiddleware(ValidationErrorMiddleware): - def __init__(self, application): - super(APIv1ValidationErrorMiddleware, self).__init__(application) - self.api_version = 'API_v1' - - class APIv2ValidationErrorMiddleware(ValidationErrorMiddleware): def __init__(self, application): super(APIv2ValidationErrorMiddleware, self).__init__(application) diff --git a/designate/api/v1/__init__.py b/designate/api/v1/__init__.py deleted file mode 100644 index e76e17868..000000000 --- a/designate/api/v1/__init__.py +++ /dev/null @@ -1,149 +0,0 @@ -# Copyright 2012 Managed I.T. -# -# Author: Kiall Mac Innes -# -# 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 six -import flask -from stevedore import extension -from stevedore import named -from werkzeug import exceptions as wexceptions -from werkzeug import wrappers -from werkzeug.routing import BaseConverter -from werkzeug.routing import ValidationError -from oslo_config import cfg -from oslo_log import log as logging -from oslo_serialization import jsonutils - -from designate import exceptions -from designate import utils - - -LOG = logging.getLogger(__name__) - - -class DesignateRequest(flask.Request, wrappers.AcceptMixin, - wrappers.CommonRequestDescriptorsMixin): - def __init__(self, *args, **kwargs): - super(DesignateRequest, self).__init__(*args, **kwargs) - - self._validate_content_type() - self._validate_accept() - - def _validate_content_type(self): - if (self.method in ['POST', 'PUT', 'PATCH'] - and self.mimetype != 'application/json'): - - msg = 'Unsupported Content-Type: %s' % self.mimetype - raise exceptions.UnsupportedContentType(msg) - - def _validate_accept(self): - if 'accept' in self.headers and not self.accept_mimetypes.accept_json: - msg = 'Unsupported Accept: %s' % self.accept_mimetypes - raise exceptions.UnsupportedAccept(msg) - - -class JSONEncoder(flask.json.JSONEncoder): - @staticmethod - def default(o): - return jsonutils.to_primitive(o) - - -def factory(global_config, **local_conf): - if not cfg.CONF['service:api'].enable_api_v1: - def disabled_app(environ, start_response): - status = '404 Not Found' - start_response(status, []) - return [] - - return disabled_app - - app = flask.Flask('designate.api.v1') - app.request_class = DesignateRequest - app.json_encoder = JSONEncoder - app.config.update( - PROPAGATE_EXCEPTIONS=True - ) - - # Install custom converters (URL param varidators) - app.url_map.converters['uuid'] = UUIDConverter - - # Ensure all error responses are JSON - def _json_error(ex): - code = ex.code if isinstance(ex, wexceptions.HTTPException) else 500 - - response = { - 'code': code - } - - if code == 405: - response['type'] = 'invalid_method' - - response = flask.jsonify(**response) - response.status_code = code - - return response - - for code in six.iterkeys(wexceptions.default_exceptions): - app.register_error_handler(code, _json_error) - - # TODO(kiall): Ideally, we want to make use of the Plugin class here. - # This works for the moment though. - def _register_blueprint(ext): - app.register_blueprint(ext.plugin) - - # Add all in-built APIs - mgr = extension.ExtensionManager('designate.api.v1') - mgr.map(_register_blueprint) - - # Add any (enabled) optional extensions - extensions = cfg.CONF['service:api'].enabled_extensions_v1 - - if len(extensions) > 0: - extmgr = named.NamedExtensionManager('designate.api.v1.extensions', - names=extensions) - extmgr.map(_register_blueprint) - - return app - - -class UUIDConverter(BaseConverter): - """Validates UUID URL parameters""" - - def to_python(self, value): - if not utils.is_uuid_like(value): - raise ValidationError() - - return value - - def to_url(self, value): - return str(value) - - -def load_values(request, valid_keys): - """Load valid attributes from request""" - result = {} - error_keys = [] - values = request.json - for k in values: - if k in valid_keys: - result[k] = values[k] - else: - error_keys.append(k) - - if error_keys: - error_msg = 'Provided object does not match schema. Keys {0} are not \ - valid in the request body', error_keys - raise exceptions.InvalidObject(error_msg) - - return result diff --git a/designate/api/v1/domains.py b/designate/api/v1/domains.py deleted file mode 100644 index a2dfada73..000000000 --- a/designate/api/v1/domains.py +++ /dev/null @@ -1,173 +0,0 @@ -# Copyright 2012 Managed I.T. -# -# Author: Kiall Mac Innes -# -# 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 flask -from oslo_log import log as logging - -from designate import schema -from designate.api.v1 import load_values -from designate.central import rpcapi as central_rpcapi -from designate.i18n import _LI -from designate import objects - - -LOG = logging.getLogger(__name__) -blueprint = flask.Blueprint('domains', __name__) -domain_schema = schema.Schema('v1', 'domain') -domains_schema = schema.Schema('v1', 'domains') -servers_schema = schema.Schema('v1', 'servers') - - -def _pool_ns_record_to_server(pool_ns_record): - server_values = { - 'id': pool_ns_record.id, - 'created_at': pool_ns_record.created_at, - 'updated_at': pool_ns_record.updated_at, - 'version': pool_ns_record.version, - 'name': pool_ns_record.hostname - } - - return objects.Server.from_dict(server_values) - - -@blueprint.route('/schemas/domain', methods=['GET']) -def get_domain_schema(): - return flask.jsonify(domain_schema.raw) - - -@blueprint.route('/schemas/domains', methods=['GET']) -def get_domains_schema(): - return flask.jsonify(domains_schema.raw) - - -@blueprint.route('/domains', methods=['POST']) -def create_domain(): - valid_attributes = ['name', 'email', 'ttl', 'description'] - context = flask.request.environ.get('context') - - values = load_values(flask.request, valid_attributes) - - domain_schema.validate(values) - - central_api = central_rpcapi.CentralAPI.get_instance() - - # A V1 zone only supports being a primary (No notion of a type) - values['type'] = 'PRIMARY' - - domain = central_api.create_zone(context, objects.Zone(**values)) - - LOG.info(_LI("Created %(zone)s"), {'zone': domain}) - - response = flask.jsonify(domain_schema.filter(domain)) - response.status_int = 201 - response.location = flask.url_for('.get_domain', domain_id=domain['id']) - - return response - - -@blueprint.route('/domains', methods=['GET']) -def get_domains(): - """List existing zones except those flagged for deletion - """ - context = flask.request.environ.get('context') - - central_api = central_rpcapi.CentralAPI.get_instance() - - domains = central_api.find_zones(context, criterion={"type": "PRIMARY", - "action": "!DELETE"}) - - LOG.info(_LI("Retrieved %(zones)s"), {'zones': domains}) - - return flask.jsonify(domains_schema.filter({'domains': domains})) - - -@blueprint.route('/domains/', methods=['GET']) -def get_domain(domain_id): - """Return zone data unless the zone is flagged for purging - """ - context = flask.request.environ.get('context') - - central_api = central_rpcapi.CentralAPI.get_instance() - - criterion = {"id": domain_id, "type": "PRIMARY", "action": "!DELETE"} - domain = central_api.find_zone(context, criterion=criterion) - - LOG.info(_LI("Retrieved %(zone)s"), {'zone': domain}) - - return flask.jsonify(domain_schema.filter(domain)) - - -@blueprint.route('/domains/', methods=['PUT']) -def update_domain(domain_id): - context = flask.request.environ.get('context') - values = flask.request.json - - central_api = central_rpcapi.CentralAPI.get_instance() - - # Fetch the existing resource - criterion = {"id": domain_id, "type": "PRIMARY", "action": "!DELETE"} - domain = central_api.find_zone(context, criterion=criterion) - - # Prepare a dict of fields for validation - domain_data = domain_schema.filter(domain) - domain_data.update(values) - - # Validate the new set of data - domain_schema.validate(domain_data) - - # Update and persist the resource - domain.update(values) - domain = central_api.update_zone(context, domain) - - LOG.info(_LI("Updated %(zone)s"), {'zone': domain}) - - return flask.jsonify(domain_schema.filter(domain)) - - -@blueprint.route('/domains/', methods=['DELETE']) -def delete_domain(domain_id): - context = flask.request.environ.get('context') - - central_api = central_rpcapi.CentralAPI.get_instance() - - # TODO(ekarlso): Fix this to something better. - criterion = {"id": domain_id, "type": "PRIMARY", "action": "!DELETE"} - central_api.find_zone(context, criterion=criterion) - - domain = central_api.delete_zone(context, domain_id) - - LOG.info(_LI("Deleted %(zone)s"), {'zone': domain}) - - return flask.Response(status=200) - - -@blueprint.route('/domains//servers', methods=['GET']) -def get_domain_servers(domain_id): - context = flask.request.environ.get('context') - - central_api = central_rpcapi.CentralAPI.get_instance() - - # TODO(ekarlso): Fix this to something better. - criterion = {"id": domain_id, "type": "PRIMARY", "action": "!DELETE"} - central_api.find_zone(context, criterion=criterion) - - nameservers = central_api.get_zone_ns_records(context, domain_id) - - servers = objects.ServerList() - - for ns in nameservers: - servers.append(_pool_ns_record_to_server(ns)) - - return flask.jsonify(servers_schema.filter({'servers': servers})) diff --git a/designate/api/v1/extensions/__init__.py b/designate/api/v1/extensions/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/designate/api/v1/extensions/diagnostics.py b/designate/api/v1/extensions/diagnostics.py deleted file mode 100644 index ead4e0b80..000000000 --- a/designate/api/v1/extensions/diagnostics.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2012 Hewlett-Packard Development Company, L.P. All Rights Reserved. -# -# Author: Kiall Mac Innes -# -# 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 flask -import oslo_messaging as messaging - -from designate import rpc - - -blueprint = flask.Blueprint('diagnostics', __name__) - - -@blueprint.route('/diagnostics/ping//', methods=['GET']) -def ping_host(topic, host): - context = flask.request.environ.get('context') - - client = rpc.get_client(messaging.Target(topic=topic)) - cctxt = client.prepare(server=host, timeout=10) - - pong = cctxt.call(context, 'ping') - - return flask.jsonify(pong) diff --git a/designate/api/v1/extensions/quotas.py b/designate/api/v1/extensions/quotas.py deleted file mode 100644 index 2f23ff7cd..000000000 --- a/designate/api/v1/extensions/quotas.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2012 Hewlett-Packard Development Company, L.P. -# -# Author: Kiall Mac Innes -# -# 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 flask - -from designate.central import rpcapi as central_rpcapi - - -central_api = central_rpcapi.CentralAPI() -blueprint = flask.Blueprint('quotas', __name__) - -KEYS_TO_SWAP = { - 'zones': 'domains', - 'zone_records': 'domain_records', - 'zone_recordsets': 'domain_recordsets', - 'recordset_records': 'recordset_records', - 'api_export_size': 'api_export_size', -} - -KEYS_TO_SWAP_REVERSE = { - 'domains': 'zones', - 'domain_records': 'zone_records', - 'domain_recordsets': 'zone_recordsets', - 'recordset_records': 'recordset_records', - 'api_export_size': 'api_export_size', -} - - -def swap_keys(quotas, reverse=False): - - if reverse: - quotas = {KEYS_TO_SWAP_REVERSE[k]: quotas[k] for k in quotas} - else: - quotas = {KEYS_TO_SWAP[k]: quotas[k] for k in quotas} - return quotas - - -@blueprint.route('/quotas/', methods=['GET']) -def get_quotas(tenant_id): - context = flask.request.environ.get('context') - - quotas = central_api.get_quotas(context, tenant_id) - - quotas = swap_keys(quotas) - - return flask.jsonify(quotas) - - -@blueprint.route('/quotas/', methods=['PUT', 'POST']) -def set_quota(tenant_id): - context = flask.request.environ.get('context') - values = flask.request.json - - values = swap_keys(values, reverse=True) - - for resource, hard_limit in values.items(): - central_api.set_quota(context, tenant_id, resource, hard_limit) - - quotas = central_api.get_quotas(context, tenant_id) - quotas = swap_keys(quotas) - - return flask.jsonify(quotas) - - -@blueprint.route('/quotas/', methods=['DELETE']) -def reset_quotas(tenant_id): - context = flask.request.environ.get('context') - - central_api.reset_quotas(context, tenant_id) - - return flask.Response(status=200) diff --git a/designate/api/v1/extensions/reports.py b/designate/api/v1/extensions/reports.py deleted file mode 100644 index 8e830724c..000000000 --- a/designate/api/v1/extensions/reports.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2012 Hewlett-Packard Development Company, L.P. All Rights Reserved. -# -# Author: Simon McCartney -# -# 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 flask - -from designate.central import rpcapi as central_rpcapi - - -central_api = central_rpcapi.CentralAPI() -blueprint = flask.Blueprint('reports', __name__) - - -@blueprint.route('/reports/tenants', methods=['GET']) -def reports_tenants(): - context = flask.request.environ.get('context') - - tenants = central_api.find_tenants(context) - - return flask.jsonify(tenants=tenants) - - -@blueprint.route('/reports/tenants/', methods=['GET']) -def reports_tenant(tenant_id): - context = flask.request.environ.get('context') - - tenant = central_api.get_tenant(context, tenant_id) - - return flask.jsonify(tenant) - - -@blueprint.route('/reports/counts', methods=['GET']) -def reports_counts(): - context = flask.request.environ.get('context') - - tenants = central_api.count_tenants(context) - domains = central_api.count_zones(context) - records = central_api.count_records(context) - - return flask.jsonify(tenants=tenants, domains=domains, records=records) - - -@blueprint.route('/reports/counts/tenants', methods=['GET']) -def reports_counts_tenants(): - context = flask.request.environ.get('context') - - count = central_api.count_tenants(context) - - return flask.jsonify(tenants=count) - - -@blueprint.route('/reports/counts/domains', methods=['GET']) -def reports_counts_domains(): - context = flask.request.environ.get('context') - - count = central_api.count_zones(context) - - return flask.jsonify(domains=count) - - -@blueprint.route('/reports/counts/records', methods=['GET']) -def reports_counts_records(): - context = flask.request.environ.get('context') - - count = central_api.count_records(context) - - return flask.jsonify(records=count) diff --git a/designate/api/v1/extensions/sync.py b/designate/api/v1/extensions/sync.py deleted file mode 100644 index b90c51f7b..000000000 --- a/designate/api/v1/extensions/sync.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2012 Hewlett-Packard Development Company, L.P. All Rights Reserved. -# -# Author: Kiall Mac Innes -# -# 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 flask - -from designate.central import rpcapi as central_rpcapi - - -central_api = central_rpcapi.CentralAPI() -blueprint = flask.Blueprint('sync', __name__) - - -@blueprint.route('/domains/sync', methods=['POST']) -def sync_domains(): - context = flask.request.environ.get('context') - - central_api.sync_zones(context) - - return flask.Response(status=200) - - -@blueprint.route('/domains//sync', methods=['POST']) -def sync_domain(domain_id): - context = flask.request.environ.get('context') - - central_api.sync_zone(context, domain_id) - - return flask.Response(status=200) - - -@blueprint.route('/domains//records//sync', - methods=['POST']) -def sync_record(domain_id, record_id): - context = flask.request.environ.get('context') - - record = central_api.find_record(context, {'id': record_id}) - central_api.sync_record(context, domain_id, record['recordset_id'], - record_id) - - return flask.Response(status=200) diff --git a/designate/api/v1/extensions/touch.py b/designate/api/v1/extensions/touch.py deleted file mode 100644 index e81c5c57c..000000000 --- a/designate/api/v1/extensions/touch.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2013 Hewlett-Packard Development Company, L.P. -# -# Author: Kiall Mac Innes -# -# 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 flask - -from designate.central import rpcapi as central_rpcapi - - -central_api = central_rpcapi.CentralAPI() -blueprint = flask.Blueprint('touch', __name__) - - -@blueprint.route('/domains//touch', methods=['POST']) -def touch_domain(domain_id): - context = flask.request.environ.get('context') - - central_api.touch_zone(context, domain_id) - - return flask.Response(status=200) diff --git a/designate/api/v1/limits.py b/designate/api/v1/limits.py deleted file mode 100644 index ebeb483d2..000000000 --- a/designate/api/v1/limits.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2012 Managed I.T. -# -# Author: Kiall Mac Innes -# -# 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 flask - -from designate import schema -from designate.central import rpcapi as central_rpcapi - - -blueprint = flask.Blueprint('limits', __name__) -limits_schema = schema.Schema('v1', 'limits') - - -@blueprint.route('/schemas/limits', methods=['GET']) -def get_limits_schema(): - return flask.jsonify(limits_schema.raw) - - -@blueprint.route('/limits', methods=['GET']) -def get_limits(): - context = flask.request.environ.get('context') - - central_api = central_rpcapi.CentralAPI.get_instance() - - absolute_limits = central_api.get_absolute_limits(context) - - return flask.jsonify(limits_schema.filter({ - "limits": { - "absolute": { - "maxDomains": absolute_limits['zones'], - "maxDomainRecords": absolute_limits['zone_records'] - } - } - })) diff --git a/designate/api/v1/records.py b/designate/api/v1/records.py deleted file mode 100644 index 084d70a34..000000000 --- a/designate/api/v1/records.py +++ /dev/null @@ -1,277 +0,0 @@ -# Copyright 2012 Managed I.T. -# -# Author: Kiall Mac Innes -# -# 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 flask -from oslo_log import log as logging - -from designate.central import rpcapi as central_rpcapi -from designate import exceptions -from designate import objects -from designate import schema -from designate import utils -from designate.i18n import _LI - - -LOG = logging.getLogger(__name__) -blueprint = flask.Blueprint('records', __name__) -record_schema = schema.Schema('v1', 'record') -records_schema = schema.Schema('v1', 'records') - - -def _find_recordset(context, domain_id, name, type): - central_api = central_rpcapi.CentralAPI.get_instance() - - return central_api.find_recordset(context, { - 'zone_id': domain_id, - 'name': name, - 'type': type, - }) - - -def _find_or_create_recordset(context, domain_id, name, type, ttl): - central_api = central_rpcapi.CentralAPI.get_instance() - - criterion = {"id": domain_id, "type": "PRIMARY", "action": "!DELETE"} - central_api.find_zone(context, criterion=criterion) - - try: - # Attempt to create an empty recordset - values = { - 'name': name, - 'type': type, - 'ttl': ttl, - } - - recordset = central_api.create_recordset( - context, domain_id, objects.RecordSet(**values)) - - except exceptions.DuplicateRecordSet: - # Fetch the existing recordset - recordset = _find_recordset(context, domain_id, name, type) - - return recordset - - -def _extract_record_values(values): - record_values = dict((k, values[k]) for k in ('data', 'description',) - if k in values) - if values.get('priority', None) is not None: - record_values['data'] = '%d %s' % ( - values['priority'], record_values['data']) - return record_values - - -def _extract_recordset_values(values): - recordset_values = ('name', 'type', 'ttl',) - return dict((k, values[k]) for k in recordset_values if k in values) - - -def _format_record_v1(record, recordset): - record = dict(record) - - record['priority'], record['data'] = utils.extract_priority_from_data( - recordset.type, record) - - record['domain_id'] = record['zone_id'] - - del record['zone_id'] - - record.update({ - 'name': recordset['name'], - 'type': recordset['type'], - 'ttl': recordset['ttl'], - }) - - return record - - -@blueprint.route('/schemas/record', methods=['GET']) -def get_record_schema(): - return flask.jsonify(record_schema.raw) - - -@blueprint.route('/schemas/records', methods=['GET']) -def get_records_schema(): - return flask.jsonify(records_schema.raw) - - -@blueprint.route('/domains//records', methods=['POST']) -def create_record(domain_id): - context = flask.request.environ.get('context') - values = flask.request.json - - record_schema.validate(values) - - if values['type'] == 'SOA': - raise exceptions.BadRequest('SOA records cannot be manually created.') - - recordset = _find_or_create_recordset(context, - domain_id, - values['name'], - values['type'], - values.get('ttl', None)) - - record = objects.Record(**_extract_record_values(values)) - - central_api = central_rpcapi.CentralAPI.get_instance() - record = central_api.create_record(context, domain_id, - recordset['id'], - record) - LOG.info(_LI("Created %(record)s"), {'record': record}) - - record = _format_record_v1(record, recordset) - - response = flask.jsonify(record_schema.filter(record)) - response.status_int = 201 - response.location = flask.url_for('.get_record', domain_id=domain_id, - record_id=record['id']) - - return response - - -@blueprint.route('/domains//records', methods=['GET']) -def get_records(domain_id): - context = flask.request.environ.get('context') - - central_api = central_rpcapi.CentralAPI.get_instance() - - # NOTE: We need to ensure the domain actually exists, otherwise we may - # return an empty records array instead of a domain not found - central_api.get_zone(context, domain_id) - - recordsets = central_api.find_recordsets(context, {'zone_id': domain_id}) - LOG.info(_LI("Retrieved %(recordsets)s"), {'recordsets': recordsets}) - - records = [] - - for rrset in recordsets: - records.extend([_format_record_v1(r, rrset) for r in rrset.records]) - - return flask.jsonify(records_schema.filter({'records': records})) - - -@blueprint.route('/domains//records/', - methods=['GET']) -def get_record(domain_id, record_id): - context = flask.request.environ.get('context') - - central_api = central_rpcapi.CentralAPI.get_instance() - - # NOTE: We need to ensure the domain actually exists, otherwise we may - # return an record not found instead of a domain not found - central_api.get_zone(context, domain_id) - - criterion = {'zone_id': domain_id, 'id': record_id} - record = central_api.find_record(context, criterion) - - recordset = central_api.get_recordset( - context, domain_id, record['recordset_id']) - - LOG.info(_LI("Retrieved %(recordset)s"), {'recordset': recordset}) - - record = _format_record_v1(record, recordset) - - return flask.jsonify(record_schema.filter(record)) - - -@blueprint.route('/domains//records/', - methods=['PUT']) -def update_record(domain_id, record_id): - context = flask.request.environ.get('context') - values = flask.request.json - - central_api = central_rpcapi.CentralAPI.get_instance() - - # NOTE: We need to ensure the domain actually exists, otherwise we may - # return a record not found instead of a domain not found - criterion = {"id": domain_id, "type": "PRIMARY", "action": "!DELETE"} - central_api.find_zone(context, criterion) - - # Fetch the existing resource - # NOTE(kiall): We use "find_record" rather than "get_record" as we do not - # have the recordset_id. - criterion = {'zone_id': domain_id, 'id': record_id} - record = central_api.find_record(context, criterion) - - # TODO(graham): Move this further down the stack - if record.managed and not context.edit_managed_records: - raise exceptions.BadRequest('Managed records may not be updated') - - # Find the associated recordset - recordset = central_api.get_recordset( - context, domain_id, record.recordset_id) - - # Prepare a dict of fields for validation - record_data = record_schema.filter(_format_record_v1(record, recordset)) - record_data.update(values) - - # Validate the new set of data - record_schema.validate(record_data) - - # Update and persist the resource - record.update(_extract_record_values(values)) - record = central_api.update_record(context, record) - - # Update the recordset resource (if necessary) - recordset.update(_extract_recordset_values(values)) - if len(recordset.obj_what_changed()) > 0: - recordset = central_api.update_recordset(context, recordset) - LOG.info(_LI("Updated %(recordset)s"), {'recordset': recordset}) - - # Format and return the response - record = _format_record_v1(record, recordset) - - return flask.jsonify(record_schema.filter(record)) - - -def _delete_recordset_if_empty(context, domain_id, recordset_id): - central_api = central_rpcapi.CentralAPI.get_instance() - - recordset = central_api.find_recordset(context, { - 'id': recordset_id - }) - # Make sure it's the right recordset - if len(recordset.records) == 0: - recordset = central_api.delete_recordset( - context, domain_id, recordset_id) - LOG.info(_LI("Deleted %(recordset)s"), {'recordset': recordset}) - - -@blueprint.route('/domains//records/', - methods=['DELETE']) -def delete_record(domain_id, record_id): - context = flask.request.environ.get('context') - - central_api = central_rpcapi.CentralAPI.get_instance() - - # NOTE: We need to ensure the domain actually exists, otherwise we may - # return a record not found instead of a domain not found - criterion = {"id": domain_id, "type": "PRIMARY", "action": "!DELETE"} - central_api.find_zone(context, criterion=criterion) - - # Find the record - criterion = {'zone_id': domain_id, 'id': record_id} - record = central_api.find_record(context, criterion) - - # Cannot delete a managed record via the API. - if record['managed'] is True: - raise exceptions.BadRequest('Managed records may not be deleted') - - record = central_api.delete_record( - context, domain_id, record['recordset_id'], record_id) - LOG.info(_LI("Deleted %(record)s"), {'record': record}) - - _delete_recordset_if_empty(context, domain_id, record['recordset_id']) - return flask.Response(status=200) diff --git a/designate/api/v1/servers.py b/designate/api/v1/servers.py deleted file mode 100644 index 244e22303..000000000 --- a/designate/api/v1/servers.py +++ /dev/null @@ -1,226 +0,0 @@ -# Copyright 2012 Managed I.T. -# -# Author: Kiall Mac Innes -# -# 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 flask -from oslo_config import cfg -from oslo_log import log as logging - -from designate import exceptions -from designate import schema -from designate import objects -from designate.i18n import _LI -from designate.central import rpcapi as central_rpcapi - - -LOG = logging.getLogger(__name__) -blueprint = flask.Blueprint('servers', __name__) -server_schema = schema.Schema('v1', 'server') -servers_schema = schema.Schema('v1', 'servers') -default_pool_id = cfg.CONF['service:central'].default_pool_id - -# Servers are no longer used. They have been replaced by nameservers, which -# is stored as a PoolAttribute. However, the v1 server API calls still need -# to work - - -def _pool_ns_record_to_server(pool_ns_record): - server_values = { - 'id': pool_ns_record.id, - 'created_at': pool_ns_record.created_at, - 'updated_at': pool_ns_record.updated_at, - 'version': pool_ns_record.version, - 'name': pool_ns_record.hostname - } - - return objects.Server.from_dict(server_values) - - -@blueprint.route('/schemas/server', methods=['GET']) -def get_server_schema(): - return flask.jsonify(server_schema.raw) - - -@blueprint.route('/schemas/servers', methods=['GET']) -def get_servers_schema(): - return flask.jsonify(servers_schema.raw) - - -@blueprint.route('/servers', methods=['POST']) -def create_server(): - context = flask.request.environ.get('context') - values = flask.request.json - central_api = central_rpcapi.CentralAPI.get_instance() - # Validate against the original server schema - server_schema.validate(values) - - # Create a PoolNsRecord object - pns_values = { - 'priority': 10, - 'hostname': values['name'] - } - ns_record = objects.PoolNsRecord.from_dict(pns_values) - - # Get the default pool - pool = central_api.get_pool(context, default_pool_id) - - # Add the new PoolAttribute to the pool as a nameserver - pool.ns_records.append(ns_record) - - try: - # Update the pool - updated_pool = central_api.update_pool(context, pool) - LOG.info(_LI("Updated %(pool)s"), {'pool': pool}) - - except exceptions.DuplicatePoolAttribute: - raise exceptions.DuplicateServer() - - # Go through the pool.ns_records to find the right one to get the ID - for ns in updated_pool.ns_records: - if ns.hostname == pns_values['hostname']: - created_ns_record = ns - break - - # Convert the PoolAttribute to a Server so we can validate with the - # original schema and display - server = _pool_ns_record_to_server(created_ns_record) - - response = flask.jsonify(server_schema.filter(server)) - response.status_int = 201 - response.location = flask.url_for('.get_server', server_id=server['id']) - - return response - - -@blueprint.route('/servers', methods=['GET']) -def get_servers(): - context = flask.request.environ.get('context') - - central_api = central_rpcapi.CentralAPI.get_instance() - - # Get the default pool - pool = central_api.get_pool(context, default_pool_id) - LOG.info(_LI("Retrieved %(pool)s"), {'pool': pool}) - - servers = objects.ServerList() - - for ns in pool.ns_records: - servers.append(_pool_ns_record_to_server(ns)) - - LOG.info(_LI("Retrieved %(servers)s"), {'servers': servers}) - - return flask.jsonify(servers_schema.filter({'servers': servers})) - - -@blueprint.route('/servers/', methods=['GET']) -def get_server(server_id): - context = flask.request.environ.get('context') - - central_api = central_rpcapi.CentralAPI.get_instance() - - # Get the default pool - pool = central_api.get_pool(context, default_pool_id) - LOG.info(_LI("Retrieved %(pool)s"), {'pool': pool}) - - # Create an empty PoolNsRecord object - nameserver = objects.PoolNsRecord() - - # Get the desired nameserver from the pool - for ns in pool.ns_records: - if ns.id == server_id: - nameserver = ns - break - - # If the nameserver wasn't found, raise an exception - if nameserver.id != server_id: - raise exceptions.ServerNotFound - - LOG.info(_LI("Retrieved %(server)s"), {'server': nameserver}) - - server = _pool_ns_record_to_server(nameserver) - - return flask.jsonify(server_schema.filter(server)) - - -@blueprint.route('/servers/', methods=['PUT']) -def update_server(server_id): - context = flask.request.environ.get('context') - values = flask.request.json - - central_api = central_rpcapi.CentralAPI.get_instance() - - # Get the default pool - pool = central_api.get_pool(context, default_pool_id) - - # Get the Nameserver from the pool - index = -1 - ns_records = pool.ns_records - for ns in ns_records: - if ns.id == server_id: - index = ns_records.index(ns) - break - - if index == -1: - raise exceptions.ServerNotFound - - # Get the ns_record from the pool so we can update it - nameserver = ns_records.pop(index) - - # Update it with the new values - nameserver.update({'hostname': values['name']}) - - # Change it to a server, so we can use the original validation. We want - # to make sure we don't change anything in v1 - server = _pool_ns_record_to_server(nameserver) - server_data = server_schema.filter(server) - server_data.update(values) - # Validate the new set of data - server_schema.validate(server_data) - - # Now that it's been validated, add it back to the pool and persist it - pool.ns_records.append(nameserver) - pool = central_api.update_pool(context, pool) - LOG.info(_LI("Updated %(pool)s"), {'pool': pool}) - - return flask.jsonify(server_schema.filter(server)) - - -@blueprint.route('/servers/', methods=['DELETE']) -def delete_server(server_id): - context = flask.request.environ.get('context') - - central_api = central_rpcapi.CentralAPI.get_instance() - - # Get the default pool - pool = central_api.get_pool(context, default_pool_id) - - # Get the Nameserver from the pool - index = -1 - ns_records = pool.ns_records - for ns in ns_records: - if ns.id == server_id: - index = ns_records.index(ns) - break - - if index == -1: - raise exceptions.ServerNotFound - - # Remove the nameserver from the pool so it will be deleted - ns_records.pop(index) - - # Update the pool without the deleted server - pool = central_api.update_pool(context, pool) - LOG.info(_LI("Updated %(pool)s"), {'pool': pool}) - - return flask.Response(status=200) diff --git a/designate/api/v1/tsigkeys.py b/designate/api/v1/tsigkeys.py deleted file mode 100644 index dadd8d583..000000000 --- a/designate/api/v1/tsigkeys.py +++ /dev/null @@ -1,155 +0,0 @@ -# Copyright 2012 Managed I.T. -# -# Author: Kiall Mac Innes -# -# 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 flask -from oslo_log import log as logging -from oslo_config import cfg - -from designate import schema -from designate.central import rpcapi as central_rpcapi -from designate.objects import TsigKey -from designate.i18n import _LI - - -LOG = logging.getLogger(__name__) -blueprint = flask.Blueprint('tsigkeys', __name__) -tsigkey_schema = schema.Schema('v1', 'tsigkey') -tsigkeys_schema = schema.Schema('v1', 'tsigkeys') -default_pool_id = cfg.CONF['service:central'].default_pool_id - - -@blueprint.route('/schemas/tsigkey', methods=['GET']) -def get_tsigkey_schema(): - return flask.jsonify(tsigkey_schema.raw) - - -@blueprint.route('/schemas/tsigkeys', methods=['GET']) -def get_tsigkeys_schema(): - return flask.jsonify(tsigkeys_schema.raw) - - -@blueprint.route('/tsigkeys', methods=['POST']) -def create_tsigkey(): - context = flask.request.environ.get('context') - values = flask.request.json - - central_api = central_rpcapi.CentralAPI.get_instance() - - tsigkey_schema.validate(values) - - tsigkey = TsigKey.from_dict(values) - - # The V1 API only deals with the default pool, so we restrict the view - # of TSIG Keys to those scoped to the default pool. - tsigkey.scope = 'POOL' - tsigkey.resource_id = default_pool_id - - tsigkey = central_api.create_tsigkey(context, tsigkey) - - LOG.info(_LI("Created %(tsigkey)s"), {'tsigkey': tsigkey}) - - response = flask.jsonify(tsigkey_schema.filter(tsigkey)) - response.status_int = 201 - response.location = flask.url_for('.get_tsigkey', tsigkey_id=tsigkey['id']) - - return response - - -@blueprint.route('/tsigkeys', methods=['GET']) -def get_tsigkeys(): - context = flask.request.environ.get('context') - - central_api = central_rpcapi.CentralAPI.get_instance() - - criterion = {'scope': 'POOL', 'resource_id': default_pool_id} - tsigkeys = central_api.find_tsigkeys(context, criterion) - - LOG.info(_LI("Retrieved %(tsigkeys)s"), {'tsigkeys': tsigkeys}) - - return flask.jsonify(tsigkeys_schema.filter({'tsigkeys': tsigkeys})) - - -@blueprint.route('/tsigkeys/', methods=['GET']) -def get_tsigkey(tsigkey_id): - context = flask.request.environ.get('context') - - central_api = central_rpcapi.CentralAPI.get_instance() - - criterion = { - 'scope': 'POOL', - 'resource_id': default_pool_id, - 'id': tsigkey_id, - } - - tsigkey = central_api.find_tsigkeys(context, criterion) - - LOG.info(_LI("Retrieved %(tsigkey)s"), {'tsigkey': tsigkey}) - - return flask.jsonify(tsigkey_schema.filter(tsigkey)) - - -@blueprint.route('/tsigkeys/', methods=['PUT']) -def update_tsigkey(tsigkey_id): - context = flask.request.environ.get('context') - values = flask.request.json - - central_api = central_rpcapi.CentralAPI.get_instance() - - # Fetch the existing tsigkey - criterion = { - 'scope': 'POOL', - 'resource_id': default_pool_id, - 'id': tsigkey_id, - } - - tsigkey = central_api.find_tsigkey(context, criterion) - - # Prepare a dict of fields for validation - tsigkey_data = tsigkey_schema.filter(tsigkey) - tsigkey_data.update(values) - - # Validate the new set of data - tsigkey_schema.validate(tsigkey_data) - - # Update and persist the resource - tsigkey.update(values) - tsigkey = central_api.update_tsigkey(context, tsigkey) - - LOG.info(_LI("Updated %(tsigkey)s"), {'tsigkey': tsigkey}) - - return flask.jsonify(tsigkey_schema.filter(tsigkey)) - - -@blueprint.route('/tsigkeys/', methods=['DELETE']) -def delete_tsigkey(tsigkey_id): - context = flask.request.environ.get('context') - - central_api = central_rpcapi.CentralAPI.get_instance() - - # Fetch the existing resource, this ensures the key to be deleted has the - # correct scope/resource_id values, otherwise it will trigger a 404. - criterion = { - 'scope': 'POOL', - 'resource_id': default_pool_id, - 'id': tsigkey_id, - } - central_api.find_tsigkeys(context, criterion) - - # Delete the TSIG Key - tsigkey = central_api.delete_tsigkey(context, tsigkey_id) - - LOG.info(_LI("Deleted %(tsigkey)s"), {'tsigkey': tsigkey}) - - return flask.Response(status=200) diff --git a/designate/api/versions.py b/designate/api/versions.py index 5a299de2a..520e08f64 100644 --- a/designate/api/versions.py +++ b/designate/api/versions.py @@ -29,7 +29,6 @@ def factory(global_config, **local_conf): def _host_header_links(): del versions[:] host_url = flask.request.host_url.rstrip('/') - _version('v1', 'DEPRECATED', host_url) _version('v2', 'CURRENT', host_url) def _version(version, status, base_uri): @@ -42,9 +41,6 @@ def factory(global_config, **local_conf): }] }) - if cfg.CONF['service:api'].enable_api_v1: - _version('v1', 'DEPRECATED', base) - if cfg.CONF['service:api'].enable_api_v2: _version('v2', 'CURRENT', base) diff --git a/designate/common/policies/record.py b/designate/common/policies/record.py index 7e16d4cb4..86ccca543 100644 --- a/designate/common/policies/record.py +++ b/designate/common/policies/record.py @@ -18,39 +18,6 @@ from oslo_policy import policy from designate.common.policies import base rules = [ - policy.DocumentedRuleDefault( - name="create_record", - check_str=base.RULE_ADMIN_OR_OWNER, - description='Create record.', - operations=[ - { - 'path': '/v1/domains//records', - 'method': 'POST' - } - ] - ), - policy.DocumentedRuleDefault( - name="get_records", - check_str=base.RULE_ADMIN_OR_OWNER, - description='Get records.', - operations=[ - { - 'path': '/v1/domains//records', - 'method': 'GET' - } - ] - ), - policy.DocumentedRuleDefault( - name="get_record", - check_str=base.RULE_ADMIN_OR_OWNER, - description='Get record.', - operations=[ - { - 'path': '/v1/domains//records/', # noqa - 'method': 'GET' - } - ] - ), policy.DocumentedRuleDefault( name="find_records", check_str=base.RULE_ADMIN_OR_OWNER, @@ -65,45 +32,6 @@ rules = [ } ] ), - policy.DocumentedRuleDefault( - name="find_record", - check_str=base.RULE_ADMIN_OR_OWNER, - description='Find record.', - operations=[ - { - 'path': '/v1/domains//records/', # noqa - 'method': 'GET' - }, { - 'path': '/v1/domains//records/', # noqa - 'method': 'DELETE' - }, { - 'path': '/v1/domains//records/', # noqa - 'method': 'PUT' - } - ] - ), - policy.DocumentedRuleDefault( - name="update_record", - check_str=base.RULE_ADMIN_OR_OWNER, - description='Update record.', - operations=[ - { - 'path': '/v1/domains//records/', # noqa - 'method': 'PUT' - } - ] - ), - policy.DocumentedRuleDefault( - name="delete_record", - check_str=base.RULE_ADMIN_OR_OWNER, - description='Delete record.', - operations=[ - { - 'path': '/v1/domains//records/', # noqa - 'method': 'DELETE' - } - ] - ), policy.RuleDefault( name="count_records", check_str=base.RULE_ADMIN_OR_OWNER) diff --git a/designate/common/policies/recordset.py b/designate/common/policies/recordset.py index c61c2f88a..724225214 100644 --- a/designate/common/policies/recordset.py +++ b/designate/common/policies/recordset.py @@ -42,12 +42,6 @@ rules = [ description="Get recordset", operations=[ { - 'path': '/v1/domains//records/', # noqa - 'method': 'GET' - }, { - 'path': '/v1/domains//records/', # noqa - 'method': 'PUT' - }, { 'path': '/v2/zones/{zone_id}/recordsets/{recordset_id}', 'method': 'GET' }, { @@ -59,40 +53,12 @@ rules = [ } ] ), - policy.DocumentedRuleDefault( - name="find_recordsets", - check_str=base.RULE_ADMIN_OR_OWNER, - description="Find recordsets", - operations=[ - { - 'path': '/v1/domains//records', - 'method': 'GET' - } - ] - ), - policy.DocumentedRuleDefault( - name="find_recordset", - check_str=base.RULE_ADMIN_OR_OWNER, - description="Find recordset", - operations=[ - { - 'path': '/v1/domains//records', - 'method': 'POST' - }, { - 'path': '/v1/domains//records/', # noqa - 'method': 'DELETE' - } - ] - ), policy.DocumentedRuleDefault( name="update_recordset", check_str=base.RULE_ZONE_PRIMARY_OR_ADMIN, description="Update recordset", operations=[ { - 'path': '/v1/domains//records/', # noqa - 'method': 'PUT' - }, { 'path': '/v2/zones/{zone_id}/recordsets/{recordset_id}', 'method': 'PUT' }, { @@ -107,9 +73,6 @@ rules = [ description="Delete RecordSet", operations=[ { - 'path': '/v1/domains//records/', # noqa - 'method': 'DELETE' - }, { 'path': '/v2/zones/{zone_id}/recordsets/{recordset_id}', 'method': 'DELETE' } diff --git a/designate/common/policies/tsigkey.py b/designate/common/policies/tsigkey.py index 924306418..6f5a7d64e 100644 --- a/designate/common/policies/tsigkey.py +++ b/designate/common/policies/tsigkey.py @@ -24,9 +24,6 @@ rules = [ description="Create Tsigkey", operations=[ { - 'path': '/v1/tsigkeys', - 'method': 'POST' - }, { 'path': '/v2/tsigkeys', 'method': 'POST' } @@ -38,15 +35,6 @@ rules = [ description="List Tsigkeys", operations=[ { - 'path': '/v1/tsigkeys', - 'method': 'GET' - }, { - 'path': '/v1/tsigkeys/', - 'method': 'GET' - }, { - 'path': '/v1/tsigkeys/', - 'method': 'DELETE' - }, { 'path': '/v2/tsigkeys', 'method': 'GET' } @@ -72,9 +60,6 @@ rules = [ description="Update Tsigkey", operations=[ { - 'path': '/v1/tsigkeys/{tsigkey_id}', - 'method': 'PATCH' - }, { 'path': '/v2/tsigkeys/{tsigkey_id}', 'method': 'PATCH' } @@ -86,9 +71,6 @@ rules = [ description="Delete a Tsigkey", operations=[ { - 'path': '/v1/tsigkeys/{tsigkey_id}', - 'method': 'DELETE' - }, { 'path': '/v2/tsigkeys/{tsigkey_id}', 'method': 'DELETE' } diff --git a/designate/common/policies/zone.py b/designate/common/policies/zone.py index 0ebeaf162..c5c974c9d 100644 --- a/designate/common/policies/zone.py +++ b/designate/common/policies/zone.py @@ -24,9 +24,6 @@ rules = [ description="Create Zone", operations=[ { - 'path': '/v1//domains', - 'method': 'POST' - }, { 'path': '/v2/zones', 'method': 'POST' } @@ -42,12 +39,6 @@ rules = [ description="Get Zone", operations=[ { - 'path': '/v1/domains//records/', # noqa - 'method': 'GET' - }, { - 'path': '/v1/domains//records', - 'method': 'GET' - }, { 'path': '/v2/zones/{zone_id}', 'method': 'GET' }, { @@ -69,43 +60,17 @@ rules = [ description="List existing zones", operations=[ { - 'path': '/v1/domains', - 'method': 'GET' - }, { 'path': '/v2/zones', 'method': 'GET' } ] ), - policy.DocumentedRuleDefault( - name="find_zone", - check_str=base.RULE_ADMIN_OR_OWNER, - description="Find Zone", - operations=[ - { - 'path': '/v1/domains/', - 'method': 'GET' - }, { - 'path': '/v1/domains//servers', - 'method': 'GET' - }, { - 'path': '/v1/domains/', - 'method': 'PUT' - }, { - 'path': '/v1/domains/', - 'method': 'DELETE' - } - ] - ), policy.DocumentedRuleDefault( name="update_zone", check_str=base.RULE_ADMIN_OR_OWNER, description="Update Zone", operations=[ { - 'path': '/v1/domains/', - 'method': 'PUT' - }, { 'path': '/v2/zones/{zone_id}', 'method': 'PATCH' } @@ -117,9 +82,6 @@ rules = [ description="Delete Zone", operations=[ { - 'path': '/v1/domains/', - 'method': 'DELETE' - }, { 'path': '/v2/zones/{zone_id}', 'method': 'DELETE' } diff --git a/designate/objects/adapters/api_v1/__init__.py b/designate/objects/adapters/api_v1/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/designate/objects/adapters/api_v1/base.py b/designate/objects/adapters/api_v1/base.py deleted file mode 100644 index fc6056de9..000000000 --- a/designate/objects/adapters/api_v1/base.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2014 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 designate.objects.adapters import base - - -class APIv1Adapter(base.DesignateAdapter): - - ADAPTER_FORMAT = 'API_v1' diff --git a/designate/resources/schemas/v1/domain.json b/designate/resources/schemas/v1/domain.json deleted file mode 100644 index 51633b2cb..000000000 --- a/designate/resources/schemas/v1/domain.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "id": "domain", - - "$schema": "http://json-schema.org/draft-03/hyper-schema", - - "title": "domain", - "description": "Domain", - "additionalProperties": false, - - "properties": { - "id": { - "type": "string", - "description": "Domain Identifier", - "format": "uuid", - "readonly": true - }, - "name": { - "type": "string", - "description": "Domain name", - "format": "domain-name", - "maxLength": 255, - "required": true, - "readonly": true - }, - "email": { - "type": "string", - "description": "Hostmaster email address", - "format": "email", - "maxLength": 255, - "required": true - }, - "ttl": { - "type": "integer", - "description": "Time to live", - "minimum": 1, - "maximum": 2147483647 - }, - "serial": { - "type": "integer", - "description": "Serial Number", - "minimum": 1, - "maximum": 4294967295, - "readonly": true - }, - "description": { - "type": ["string", "null"], - "description": "Description for the Domain", - "maxLength": 160 - }, - "created_at": { - "type": "string", - "description": "Date and time of domain creation", - "format": "date-time", - "readonly": true - }, - "updated_at": { - "type": ["string", "null"], - "description": "Date and time of last domain update", - "format": "date-time", - "readonly": true - } - }, - "links": [{ - "rel": "self", - "href": "/domains/{id}" - }, { - "rel": "records", - "href": "/domains/{id}/records" - }, { - "rel": "servers", - "href": "/domains/{id}/servers" - }, { - "rel": "collection", - "href": "/domains" - }] -} diff --git a/designate/resources/schemas/v1/domains.json b/designate/resources/schemas/v1/domains.json deleted file mode 100644 index e65302429..000000000 --- a/designate/resources/schemas/v1/domains.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "id": "domains", - - "$schema": "http://json-schema.org/draft-03/hyper-schema", - - "title": "domains", - "description": "Domains", - "additionalProperties": false, - - "properties": { - "domains": { - "type": "array", - "description": "Domains", - "items": {"$ref": "domain#"} - } - } -} diff --git a/designate/resources/schemas/v1/fault.json b/designate/resources/schemas/v1/fault.json deleted file mode 100644 index b3b43caae..000000000 --- a/designate/resources/schemas/v1/fault.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "id": "fault", - - "$schema": "http://json-schema.org/draft-03/hyper-schema", - - "title": "fault", - "description": "Fault", - "additionalProperties": false, - - "properties": { - "code": { - "type": "integer", - "description": "Fault Code", - "required": true, - "readonly": true - }, - "type": { - "type": "string", - "description": "Fault Type", - "readonly": true - }, - "message": { - "type": "string", - "description": "Fault Message", - "readonly": true - }, - "errors": { - "type": "array", - "description": "List of Errors", - "readonly": true, - "items": { - "type": "object", - "properties": { - "path": { - "type": "string", - "description": "Error Path", - "readonly": true - }, - "type": { - "type": "string", - "description": "Error Type", - "readonly": true - } - } - } - }, - "request_id": { - "type": "string", - "description": "Request ID", - "readonly": true - } - } -} diff --git a/designate/resources/schemas/v1/limits.json b/designate/resources/schemas/v1/limits.json deleted file mode 100644 index 4b7bdd00e..000000000 --- a/designate/resources/schemas/v1/limits.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "id": "limits", - - "$schema": "http://json-schema.org/draft-03/hyper-schema", - - "title": "limits", - "description": "Limits", - "additionalProperties": false, - - "properties": { - "limits": { - "type": "object", - "description": "Limits", - "properties": { - "absolute": { - "type": "object", - "properties": { - "maxDomains": { - "type": "integer" - }, - "maxDomainRecords": { - "type": "integer" - } - } - } - } - } - } -} diff --git a/designate/resources/schemas/v1/record.json b/designate/resources/schemas/v1/record.json deleted file mode 100644 index fbf822019..000000000 --- a/designate/resources/schemas/v1/record.json +++ /dev/null @@ -1,246 +0,0 @@ -{ - "id": "record", - - "$schema": "http://json-schema.org/draft-03/hyper-schema", - - "title": "record", - "description": "Record", - "additionalProperties": false, - - "properties": { - "id": { - "type": "string", - "description": "Record Identifier", - "format": "uuid", - "readonly": true - }, - "domain_id": { - "type": "string", - "description": "Domain Identifier", - "format": "uuid", - "readonly": true - }, - "name": { - "type": "string", - "description": "DNS Record Name", - "format": "host-name", - "maxLength": 255, - "required": true - }, - "type": { - "type": "string", - "description": "DNS Record Type", - "enum": ["A", "AAAA", "CNAME", "MX", "SRV", "TXT", "SPF", "NS", "PTR", "SSHFP", "SOA"], - "required": true - }, - "data": { - "type": "string", - "description": "DNS Record Value", - "maxLength": 255, - "required": true - }, - "priority": { - "type": ["integer", "null"], - "description": "DNS Record Priority", - "minimum": 0, - "maximum": 65535 - }, - "ttl": { - "type": ["integer", "null"], - "description": "Time to live", - "minimum": 1, - "maximum": 2147483647 - }, - "description": { - "type": ["string", "null"], - "description": "Description for the record", - "maxLength": 160 - }, - "created_at": { - "type": "string", - "description": "Date and time of record creation", - "format": "date-time", - "readonly": true - }, - "updated_at": { - "type": ["string", "null"], - "description": "Date and time of last record update", - "format": "date-time", - "readonly": true - } - }, - "oneOf": [{ - "description": "An A Record", - "properties": { - "type": { - "type": "string", - "enum": ["A"] - }, - "data": { - "format": "ip-address", - "required": true - }, - "priority": { - "type": "null" - } - } - }, { - "description": "An AAAA Record", - "properties": { - "type": { - "type": "string", - "enum": ["AAAA"] - }, - "data": { - "format": "ipv6", - "required": true - }, - "priority": { - "type": "null" - } - } - }, { - "description": "A CNAME Record", - "properties": { - "type": { - "type": "string", - "enum": ["CNAME"] - }, - "data": { - "format": "host-name", - "required": true - }, - "priority": { - "type": "null" - } - } - }, { - "description": "A MX Record", - "properties": { - "type": { - "type": "string", - "enum": ["MX"] - }, - "data": { - "format": "host-name", - "required": true - }, - "priority": { - "type": "integer", - "required": true - } - } - }, { - "description": "A SRV Record", - "properties": { - "type": { - "type": "string", - "enum": ["SRV"] - }, - "name": { - "type": "string", - "pattern": "^(?:_[A-Za-z0-9_\\-]{1,62}\\.){2}" - }, - "data": { - "type": "string", - "pattern": "^(?:(?:6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[1-5][0-9]{4}|[1-9][0-9]{1,3}|[0-9])\\s){2}(?!.{255,})((?!\\-)[A-Za-z0-9_\\-]{1,63}(? -# -# 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_log import log as logging -from oslo_serialization import jsonutils as json - -from designate.api import v1 as api_v1 -from designate.api import middleware -from designate.tests.test_api import ApiTestCase - - -LOG = logging.getLogger(__name__) - - -class ApiV1Test(ApiTestCase): - def setUp(self): - super(ApiV1Test, self).setUp() - - # Ensure the v1 API is enabled - self.config(enable_api_v1=True, group='service:api') - - # Create the application - self.app = api_v1.factory({}) - - # Inject the NormalizeURIMiddleware middleware - self.app.wsgi_app = middleware.NormalizeURIMiddleware( - self.app.wsgi_app) - - # Inject the FaultWrapper middleware - self.app.wsgi_app = middleware.FaultWrapperMiddleware( - self.app.wsgi_app) - - # Inject the ValidationError middleware - self.app.wsgi_app = middleware.APIv1ValidationErrorMiddleware( - self.app.wsgi_app) - - # Inject the TestAuth middleware - self.app.wsgi_app = middleware.TestContextMiddleware( - self.app.wsgi_app, self.admin_context.tenant, - self.admin_context.user) - - # Obtain a test client - self.client = self.app.test_client() - - def get(self, path, **kw): - expected_status_code = kw.pop('status_code', 200) - - resp = self.client.get(path=path) - - LOG.debug('Response Body: %r' % resp.data) - - self.assertEqual(expected_status_code, resp.status_code) - - try: - resp.json = json.loads(resp.data) - except ValueError: - resp.json = None - - return resp - - def post(self, path, data, content_type="application/json", **kw): - expected_status_code = kw.pop('status_code', 200) - - content = json.dumps(data) - resp = self.client.post(path=path, content_type=content_type, - data=content) - - LOG.debug('Response Body: %r' % resp.data) - - self.assertEqual(expected_status_code, resp.status_code) - - try: - resp.json = json.loads(resp.data) - except ValueError: - resp.json = None - - return resp - - def put(self, path, data, content_type="application/json", **kw): - expected_status_code = kw.pop('status_code', 200) - - content = json.dumps(data) - resp = self.client.put(path=path, content_type=content_type, - data=content) - - LOG.debug('Response Body: %r' % resp.data) - - self.assertEqual(expected_status_code, resp.status_code) - - try: - resp.json = json.loads(resp.data) - except ValueError: - resp.json = None - - return resp - - def delete(self, path, **kw): - expected_status_code = kw.pop('status_code', 200) - - resp = self.client.delete(path=path) - - LOG.debug('Response Body: %r' % resp.data) - - self.assertEqual(expected_status_code, resp.status_code) - - return resp diff --git a/designate/tests/test_api/test_v1/test_domains.py b/designate/tests/test_api/test_v1/test_domains.py deleted file mode 100644 index e351ca79b..000000000 --- a/designate/tests/test_api/test_v1/test_domains.py +++ /dev/null @@ -1,522 +0,0 @@ -# coding=utf-8 -# Copyright 2012 Managed I.T. -# -# Author: Kiall Mac Innes -# -# 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 datetime - -import testtools -from mock import patch -import oslo_messaging as messaging -from oslo_config import cfg -from oslo_log import log as logging - -from designate import exceptions -from designate.central import service as central_service -from designate.tests.test_api.test_v1 import ApiV1Test - - -LOG = logging.getLogger(__name__) - - -class ApiV1zonesTest(ApiV1Test): - def test_get_zone_schema(self): - response = self.get('schemas/domain') - self.assertIn('description', response.json) - self.assertIn('links', response.json) - self.assertIn('title', response.json) - self.assertIn('id', response.json) - self.assertIn('additionalProperties', response.json) - self.assertIn('properties', response.json) - self.assertIn('description', response.json['properties']) - self.assertIn('created_at', response.json['properties']) - self.assertIn('updated_at', response.json['properties']) - self.assertIn('name', response.json['properties']) - self.assertIn('email', response.json['properties']) - self.assertIn('ttl', response.json['properties']) - self.assertIn('serial', response.json['properties']) - - def test_get_zones_schema(self): - response = self.get('schemas/domains') - self.assertIn('description', response.json) - self.assertIn('additionalProperties', response.json) - self.assertIn('properties', response.json) - self.assertIn('title', response.json) - self.assertIn('id', response.json) - - def test_create_zone(self): - # Create a zone - fixture = self.get_zone_fixture(0) - - # V1 doesn't have these - del fixture['type'] - - response = self.post('domains', data=fixture) - - self.assertIn('id', response.json) - self.assertIn('name', response.json) - self.assertEqual(response.json['name'], fixture['name']) - - def test_create_zone_junk(self): - # Create a zone - fixture = self.get_zone_fixture(0) - - # Add a junk property - fixture['junk'] = 'Junk Field' - - # Ensure it fails with a 400 - self.post('domains', data=fixture, status_code=400) - - @patch.object(central_service.Service, 'create_zone', - side_effect=messaging.MessagingTimeout()) - def test_create_zone_timeout(self, _): - # Create a zone - fixture = self.get_zone_fixture(0) - - # V1 doesn't have these - del fixture['type'] - - self.post('domains', data=fixture, status_code=504) - - @patch.object(central_service.Service, 'create_zone', - side_effect=exceptions.DuplicateZone()) - def test_create_zone_duplicate(self, _): - # Create a zone - fixture = self.get_zone_fixture(0) - - # V1 doesn't have these - del fixture['type'] - - self.post('domains', data=fixture, status_code=409) - - def test_create_zone_null_ttl(self): - # Create a zone - fixture = self.get_zone_fixture(0) - fixture['ttl'] = None - self.post('domains', data=fixture, status_code=400) - - def test_create_zone_negative_ttl(self): - # Create a zone - fixture = self.get_zone_fixture(0) - fixture['ttl'] = -1 - self.post('domains', data=fixture, status_code=400) - - def test_create_zone_zero_ttl(self): - # Create a zone - fixture = self.get_zone_fixture(0) - fixture['ttl'] = 0 - self.post('domains', data=fixture, status_code=400) - - def test_create_zone_invalid_ttl(self): - # Create a zone - fixture = self.get_zone_fixture(0) - fixture['ttl'] = "$?>&" - self.post('domains', data=fixture, status_code=400) - - def test_create_zone_ttl_greater_than_max(self): - fixture = self.get_zone_fixture(0) - fixture['ttl'] = 2147483648 - self.post('domains', data=fixture, status_code=400) - - def test_create_zone_utf_description(self): - # Create a zone - fixture = self.get_zone_fixture(0) - - # V1 doesn't have type - del fixture['type'] - - # Give it a UTF-8 filled description - fixture['description'] = "utf-8:2H₂+O₂⇌2H₂O,R=4.7kΩ,⌀200mm∮E⋅da=Q,n" \ - ",∑f(i)=∏g(i),∀x∈ℝ:⌈x⌉" - # Create the zone, ensuring it succeeds, thus UTF-8 is supported - self.post('domains', data=fixture) - - def test_create_zone_description_too_long(self): - # Create a zone - fixture = self.get_zone_fixture(0) - fixture['description'] = "x" * 161 - - # Create the zone, ensuring it fails with a 400 - self.post('domains', data=fixture, status_code=400) - - def test_create_zone_with_unwanted_attributes(self): - - zone_id = "2d1d1d1d-1324-4a80-aa32-1f69a91bf2c8" - created_at = datetime.datetime(2014, 6, 22, 21, 50, 0) - updated_at = datetime.datetime(2014, 6, 22, 21, 50, 0) - serial = 1234567 - - # Create a zone - fixture = self.get_zone_fixture(0) - fixture['id'] = zone_id - fixture['created_at'] = created_at - fixture['updated_at'] = updated_at - fixture['serial'] = serial - - self.post('domains', data=fixture, status_code=400) - - def test_create_invalid_name(self): - # Prepare a zone - fixture = self.get_zone_fixture(0) - - invalid_names = [ - 'org', - 'example.org', - 'example.321', - ] - - for invalid_name in invalid_names: - fixture['name'] = invalid_name - - # Create a record - response = self.post('domains', data=fixture, status_code=400) - - self.assertNotIn('id', response.json) - - def test_create_zone_name_too_long(self): - fixture = self.get_zone_fixture(0) - - long_name = 'a' * 255 + ".org." - fixture['name'] = long_name - - response = self.post('domains', data=fixture, status_code=400) - - self.assertNotIn('id', response.json) - - def test_create_zone_name_is_not_present(self): - fixture = self.get_zone_fixture(0) - del fixture['name'] - self.post('domains', data=fixture, status_code=400) - - def test_create_invalid_email(self): - # Prepare a zone - fixture = self.get_zone_fixture(0) - - invalid_emails = [ - 'org', - 'example.org', - 'bla.example.org', - 'org.', - 'example.org.', - 'bla.example.org.', - 'bla.example.org.', - ] - - for invalid_email in invalid_emails: - fixture['email'] = invalid_email - - # Create a record - response = self.post('domains', data=fixture, status_code=400) - - self.assertNotIn('id', response.json) - - def test_create_zone_email_too_long(self): - fixture = self.get_zone_fixture(0) - - long_email = 'a' * 255 + "@org.com" - fixture['email'] = long_email - - response = self.post('domains', data=fixture, status_code=400) - - self.assertNotIn('id', response.json) - - def test_create_zone_email_not_present(self): - fixture = self.get_zone_fixture(0) - del fixture['email'] - self.post('domains', data=fixture, status_code=400) - - def test_create_zone_twice(self): - self.create_zone() - with testtools.ExpectedException(exceptions.DuplicateZone): - self.create_zone() - - def test_create_zone_pending_deletion(self): - zone = self.create_zone() - self.delete('domains/%s' % zone['id']) - with testtools.ExpectedException(exceptions.DuplicateZone): - self.create_zone() - - def test_get_zones(self): - response = self.get('domains') - - self.assertIn('domains', response.json) - self.assertEqual(0, len(response.json['domains'])) - - # Create a zone - self.create_zone() - - response = self.get('domains') - - self.assertIn('domains', response.json) - self.assertEqual(1, len(response.json['domains'])) - - # Create a second zone - self.create_zone(fixture=1) - - response = self.get('domains') - - self.assertIn('domains', response.json) - self.assertEqual(2, len(response.json['domains'])) - - def test_get_zone_servers(self): - # Create a zone - zone = self.create_zone() - response = self.get('domains/%s/servers' % zone['id']) - # Verify length of zone servers - self.assertEqual(1, len(response.json['servers'])) - - @patch.object(central_service.Service, 'find_zones', - side_effect=messaging.MessagingTimeout()) - def test_get_zones_timeout(self, _): - self.get('domains', status_code=504) - - def test_get_zone(self): - # Create a zone - zone = self.create_zone() - - response = self.get('domains/%s' % zone['id']) - - self.assertIn('id', response.json) - self.assertEqual(response.json['id'], zone['id']) - - @patch.object(central_service.Service, 'find_zone', - side_effect=messaging.MessagingTimeout()) - def test_get_zone_timeout(self, _): - # Create a zone - zone = self.create_zone() - - self.get('domains/%s' % zone['id'], status_code=504) - - def test_get_zone_missing(self): - self.get('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', - status_code=404) - - def test_get_zone_invalid_id(self): - # The letter "G" is not valid in a UUID - self.get('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff9GG', - status_code=404) - - self.get('domains/2fdadfb1cf964259ac6bbb7b6d2ff980', status_code=404) - - def test_update_zone(self): - # Create a zone - zone = self.create_zone() - - data = {'email': 'prefix-%s' % zone['email']} - - response = self.put('domains/%s' % zone['id'], data=data) - - self.assertIn('id', response.json) - self.assertEqual(response.json['id'], zone['id']) - - self.assertIn('email', response.json) - self.assertEqual('prefix-%s' % zone['email'], response.json['email']) - - def test_update_zone_junk(self): - # Create a zone - zone = self.create_zone() - - data = {'email': 'prefix-%s' % zone['email'], 'junk': 'Junk Field'} - - self.put('domains/%s' % zone['id'], data=data, status_code=400) - - def test_update_zone_name_fail(self): - # Create a zone - zone = self.create_zone() - - data = {'name': 'renamed.com.'} - - self.put('domains/%s' % zone['id'], data=data, status_code=400) - - def test_update_zone_null_ttl(self): - # Create a zone - zone = self.create_zone() - - data = {'ttl': None} - - self.put('domains/%s' % zone['id'], data=data, status_code=400) - - def test_update_zone_negative_ttl(self): - # Create a zone - zone = self.create_zone() - - data = {'ttl': -1} - - self.put('domains/%s' % zone['id'], data=data, status_code=400) - - def test_update_zone_zero_ttl(self): - # Create a zone - zone = self.create_zone() - - data = {'ttl': 0} - - self.put('domains/%s' % zone['id'], data=data, status_code=400) - - @patch.object(central_service.Service, 'update_zone', - side_effect=messaging.MessagingTimeout()) - def test_update_zone_timeout(self, _): - # Create a zone - zone = self.create_zone() - - data = {'email': 'prefix-%s' % zone['email']} - - self.put('domains/%s' % zone['id'], data=data, status_code=504) - - @patch.object(central_service.Service, 'update_zone', - side_effect=exceptions.DuplicateZone()) - def test_update_zone_duplicate(self, _): - # Create a zone - zone = self.create_zone() - - data = {'email': 'prefix-%s' % zone['email']} - - self.put('domains/%s' % zone['id'], data=data, status_code=409) - - def test_update_zone_missing(self): - data = {'email': 'bla@bla.com'} - - self.put('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', data=data, - status_code=404) - - def test_update_zone_invalid_id(self): - data = {'email': 'bla@bla.com'} - - # The letter "G" is not valid in a UUID - self.put('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff9GG', data=data, - status_code=404) - - self.put('domains/2fdadfb1cf964259ac6bbb7b6d2ff980', data=data, - status_code=404) - - def test_update_zone_ttl_greter_than_max(self): - # Create a zone - zone = self.create_zone() - - data = {'ttl': 2147483648} - - self.put('domains/%s' % zone['id'], data=data, status_code=400) - - def test_update_zone_invalid_email(self): - # Create a zone - zone = self.create_zone() - - invalid_emails = [ - 'org', - 'example.org', - 'bla.example.org', - 'org.', - 'example.org.', - 'bla.example.org.', - 'bla.example.org.', - 'a' * 255 + "@com", - '' - ] - - for invalid_email in invalid_emails: - data = {'email': invalid_email} - self.put('domains/%s' % zone['id'], data=data, status_code=400) - - def test_update_zone_description_too_long(self): - # Create a zone - zone = self.create_zone() - - invalid_des = 'a' * 165 - - data = {'description': invalid_des} - self.put('domains/%s' % zone['id'], data=data, status_code=400) - - def test_update_zone_in_pending_deletion(self): - zone = self.create_zone() - self.delete('domains/%s' % zone['id']) - self.put('domains/%s' % zone['id'], data={}, status_code=404) - - def test_delete_zone(self): - # Create a zone - zone = self.create_zone() - - self.delete('domains/%s' % zone['id']) - - # Simulate the zone having been deleted on the backend - zone_serial = self.central_service.get_zone( - self.admin_context, zone['id']).serial - self.central_service.update_status( - self.admin_context, zone['id'], "SUCCESS", zone_serial) - - # Ensure we can no longer fetch the zone - self.get('domains/%s' % zone['id'], status_code=404) - - def test_zone_in_pending_deletion(self): - zone1 = self.create_zone() - self.create_zone(fixture=1) - response = self.get('domains') - self.assertEqual(2, len(response.json['domains'])) - - # Delete zone1 - self.delete('domains/%s' % zone1['id']) - - # Ensure we can no longer list nor fetch the deleted zone - response = self.get('domains') - self.assertEqual(1, len(response.json['domains'])) - - self.get('domains/%s' % zone1['id'], status_code=404) - - @patch.object(central_service.Service, 'delete_zone', - side_effect=messaging.MessagingTimeout()) - def test_delete_zone_timeout(self, _): - # Create a zone - zone = self.create_zone() - - self.delete('domains/%s' % zone['id'], status_code=504) - - def test_delete_zone_missing(self): - self.delete('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', - status_code=404) - - def test_delete_zone_invalid_id(self): - # The letter "G" is not valid in a UUID - self.delete('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff9GG', - status_code=404) - - self.delete('domains/2fdadfb1cf964259ac6bbb7b6d2ff980', - status_code=404) - - def test_get_secondary_missing(self): - fixture = self.get_zone_fixture('SECONDARY', 0) - fixture['email'] = cfg.CONF['service:central'].managed_resource_email - - zone = self.create_zone(**fixture) - - self.get('domains/%s' % zone.id, status_code=404) - - def test_update_secondary_missing(self): - fixture = self.get_zone_fixture('SECONDARY', 0) - fixture['email'] = cfg.CONF['service:central'].managed_resource_email - - zone = self.create_zone(**fixture) - - self.put('domains/%s' % zone.id, {}, status_code=404) - - def test_delete_secondary_missing(self): - fixture = self.get_zone_fixture('SECONDARY', 0) - fixture['email'] = cfg.CONF['service:central'].managed_resource_email - - zone = self.create_zone(**fixture) - self.delete('domains/%s' % zone.id, status_code=404) - - def test_get_zone_servers_from_secondary(self): - fixture = self.get_zone_fixture('SECONDARY', 0) - fixture['email'] = cfg.CONF['service:central'].managed_resource_email - - zone = self.create_zone(**fixture) - self.get('domains/%s/servers' % zone.id, status_code=404) diff --git a/designate/tests/test_api/test_v1/test_limits.py b/designate/tests/test_api/test_v1/test_limits.py deleted file mode 100644 index f133eaaee..000000000 --- a/designate/tests/test_api/test_v1/test_limits.py +++ /dev/null @@ -1,39 +0,0 @@ -# coding=utf-8 -# Copyright 2012 Managed I.T. -# -# Author: Kiall Mac Innes -# -# 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_log import log as logging - -from designate.tests.test_api.test_v1 import ApiV1Test - - -LOG = logging.getLogger(__name__) - - -class ApiV1LimitsTest(ApiV1Test): - def test_get_limits_schema(self): - response = self.get('/schemas/limits') - self.assertIn('id', response.json) - self.assertIn('description', response.json) - self.assertIn('title', response.json) - self.assertIn('additionalProperties', response.json) - self.assertIn('properties', response.json) - - def test_get_limits(self): - response = self.get('/limits') - self.assertIn('limits', response.json) - self.assertIn('absolute', response.json['limits']) - self.assertIn('maxDomains', response.json['limits']['absolute']) - self.assertIn('maxDomainRecords', response.json['limits']['absolute']) diff --git a/designate/tests/test_api/test_v1/test_records.py b/designate/tests/test_api/test_v1/test_records.py deleted file mode 100644 index 7f0d85504..000000000 --- a/designate/tests/test_api/test_v1/test_records.py +++ /dev/null @@ -1,862 +0,0 @@ -# coding=utf-8 -# Copyright 2012 Managed I.T. -# -# Author: Kiall Mac Innes -# -# 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 mock import patch -import oslo_messaging as messaging -from oslo_log import log as logging - -from designate.central import service as central_service -from designate.tests.test_api.test_v1 import ApiV1Test - - -LOG = logging.getLogger(__name__) - - -class ApiV1RecordsTest(ApiV1Test): - def setUp(self): - super(ApiV1RecordsTest, self).setUp() - - self.zone = self.create_zone() - self.recordset = self.create_recordset(self.zone, 'A') - - def test_get_record_schema(self): - response = self.get('schemas/record') - self.assertIn('description', response.json) - self.assertIn('links', response.json) - self.assertIn('title', response.json) - self.assertIn('id', response.json) - self.assertIn('additionalProperties', response.json) - self.assertIn('properties', response.json) - self.assertIn('id', response.json['properties']) - self.assertIn('domain_id', response.json['properties']) - self.assertIn('type', response.json['properties']) - self.assertIn('data', response.json['properties']) - self.assertIn('priority', response.json['properties']) - self.assertIn('description', response.json['properties']) - self.assertIn('created_at', response.json['properties']) - self.assertIn('updated_at', response.json['properties']) - self.assertIn('name', response.json['properties']) - self.assertIn('ttl', response.json['properties']) - self.assertIn('oneOf', response.json) - - def test_get_records_schema(self): - response = self.get('schemas/records') - self.assertIn('description', response.json) - self.assertIn('additionalProperties', response.json) - self.assertIn('properties', response.json) - self.assertIn('title', response.json) - self.assertIn('id', response.json) - - def test_create_record(self): - recordset_fixture = self.get_recordset_fixture( - self.zone['name']) - - fixture = self.get_record_fixture(recordset_fixture['type']) - fixture.update({ - 'name': recordset_fixture['name'], - 'type': recordset_fixture['type'], - }) - - # Create a record - response = self.post('domains/%s/records' % self.zone['id'], - data=fixture) - - self.assertIn('id', response.json) - self.assertIn('name', response.json) - self.assertEqual(response.json['name'], fixture['name']) - - def test_create_record_existing_recordset(self): - fixture = self.get_record_fixture(self.recordset['type']) - fixture.update({ - 'name': self.recordset['name'], - 'type': self.recordset['type'], - }) - - # Create a record - response = self.post('domains/%s/records' % self.zone['id'], - data=fixture) - - self.assertIn('id', response.json) - self.assertIn('name', response.json) - self.assertEqual(response.json['name'], fixture['name']) - - def test_create_record_name_reuse(self): - fixture_1 = self.get_record_fixture(self.recordset['type']) - fixture_1.update({ - 'name': self.recordset['name'], - 'type': self.recordset['type'], - }) - - fixture_2 = self.get_record_fixture(self.recordset['type'], fixture=1) - fixture_2.update({ - 'name': self.recordset['name'], - 'type': self.recordset['type'], - }) - - # Create 2 records - record_1 = self.post('domains/%s/records' % self.zone['id'], - data=fixture_1) - record_2 = self.post('domains/%s/records' % self.zone['id'], - data=fixture_2) - - # Delete record 1, this should not have any side effects - self.delete('domains/%s/records/%s' % (self.zone['id'], - record_1.json['id'])) - - # Simulate the record 1 having been deleted on the backend - zone_serial = self.central_service.get_zone( - self.admin_context, self.zone['id']).serial - self.central_service.update_status( - self.admin_context, self.zone['id'], "SUCCESS", zone_serial) - - # Get the record 2 to ensure recordset did not get deleted - rec_2_get_response = self.get('domains/%s/records/%s' % - (self.zone['id'], record_2.json['id'])) - - self.assertIn('id', rec_2_get_response.json) - self.assertIn('name', rec_2_get_response.json) - self.assertEqual(rec_2_get_response.json['name'], fixture_1['name']) - - # Delete record 2, this should delete the null recordset too - self.delete('domains/%s/records/%s' % (self.zone['id'], - record_2.json['id'])) - - # Simulate the record 2 having been deleted on the backend - zone_serial = self.central_service.get_zone( - self.admin_context, self.zone['id']).serial - self.central_service.update_status( - self.admin_context, self.zone['id'], "SUCCESS", zone_serial) - - # Re-create as a different type, but use the same name - fixture = self.get_record_fixture('CNAME') - fixture.update({ - 'name': self.recordset['name'], - 'type': 'CNAME' - }) - - response = self.post('domains/%s/records' % self.zone['id'], - data=fixture) - - self.assertIn('id', response.json) - self.assertIn('name', response.json) - self.assertEqual(response.json['name'], fixture['name']) - - def test_create_record_junk(self): - fixture = self.get_record_fixture(self.recordset['type']) - fixture.update({ - 'name': self.recordset['name'], - 'type': self.recordset['type'], - }) - - # Add a junk property - fixture['junk'] = 'Junk Field' - - # Create a record, ensuring it fails with a 400 - self.post('domains/%s/records' % self.zone['id'], data=fixture, - status_code=400) - - def test_create_wildcard_record_after_named(self): - # We want to test that a wildcard record rs does not use the - # previous one - # https://bugs.launchpad.net/designate/+bug/1391426 - - name = "foo.%s" % self.zone.name - fixture = { - "name": name, - "type": "A", - "data": "10.0.0.1" - } - - self.post('domains/%s/records' % self.zone['id'], - data=fixture) - - wildcard_name = '*.%s' % self.zone["name"] - - fixture['name'] = wildcard_name - self.post('domains/%s/records' % self.zone['id'], - data=fixture) - - named_rs = self.central_service.find_recordset( - self.admin_context, {"name": name}) - wildcard_rs = self.central_service.find_recordset( - self.admin_context, {"name": wildcard_name}) - - self.assertNotEqual(named_rs.name, wildcard_rs.name) - self.assertNotEqual(named_rs.id, wildcard_rs.id) - - def test_create_record_utf_description(self): - fixture = self.get_record_fixture(self.recordset['type']) - fixture.update({ - 'name': self.recordset['name'], - 'type': self.recordset['type'], - }) - - # Add a UTF-8 riddled description - fixture['description'] = "utf-8:2H₂+O₂⇌2H₂O,R=4.7kΩ,⌀200mm∮E⋅da=Q,n" \ - ",∑f(i)=∏g(i),∀x∈ℝ:⌈x⌉" - - # Create a record, ensuring it succeeds - self.post('domains/%s/records' % self.zone['id'], data=fixture) - - def test_create_record_description_too_long(self): - fixture = self.get_record_fixture(self.recordset['type']) - fixture.update({ - 'name': self.recordset['name'], - 'type': self.recordset['type'], - }) - - # Add a description that is too long - fixture['description'] = "x" * 161 - - # Create a record, ensuring it fails with a 400 - self.post('domains/%s/records' % self.zone['id'], data=fixture, - status_code=400) - - def test_create_record_name_too_long(self): - fixture = self.get_record_fixture(self.recordset['type']) - fixture.update({'type': self.recordset['type']}) - fixture['name'] = 'w' * 255 + ".%s" % self.zone.name - self.post('domains/%s/records' % self.zone['id'], data=fixture, - status_code=400) - - def test_create_record_name_is_missing(self): - fixture = self.get_record_fixture(self.recordset['type']) - fixture.update({'type': self.recordset['type']}) - self.post('domains/%s/records' % self.zone['id'], data=fixture, - status_code=400) - - def test_create_record_type_is_missing(self): - fixture = self.get_record_fixture(self.recordset['type']) - fixture['name'] = "www.%s" % self.zone.name - self.post('domains/%s/records' % self.zone['id'], data=fixture, - status_code=400) - - def test_create_record_invalid_type(self): - fixture = self.get_record_fixture(self.recordset['type']) - fixture.update({'type': "ABC", 'name': self.recordset['name']}) - self.post('domains/%s/records' % self.zone['id'], data=fixture, - status_code=400) - - def test_create_record_data_is_missing(self): - fixture = self.get_record_fixture(self.recordset['type']) - fixture.update({'type': self.recordset['type'], - 'name': self.recordset['name']}) - del fixture['data'] - self.post('domains/%s/records' % self.zone['id'], data=fixture, - status_code=400) - - def test_create_record_ttl_greater_than_max(self): - fixture = self.get_record_fixture(self.recordset['type']) - fixture.update({ - 'name': self.recordset['name'], - 'type': self.recordset['type'], - }) - - fixture['ttl'] = 2174483648 - self.post('domains/%s/records' % self.zone['id'], data=fixture, - status_code=400) - - def test_create_record_negative_ttl(self): - fixture = self.get_record_fixture(self.recordset['type']) - fixture.update({ - 'name': self.recordset['name'], - 'type': self.recordset['type'], - }) - - # Set the TTL to a negative value - fixture['ttl'] = -1 - - # Create a record, ensuring it fails with a 400 - self.post('domains/%s/records' % self.zone['id'], data=fixture, - status_code=400) - - def test_create_record_zero_ttl(self): - fixture = self.get_record_fixture(self.recordset['type']) - fixture.update({ - 'name': self.recordset['name'], - 'type': self.recordset['type'], - }) - - # Set the TTL to a value zero - fixture['ttl'] = 0 - - # Create a record, ensuring it fails with a 400 - self.post('domains/%s/records' % self.zone['id'], data=fixture, - status_code=400) - - def test_create_record_invalid_ttl(self): - fixture = self.get_record_fixture(self.recordset['type']) - fixture.update({ - 'name': self.recordset['name'], - 'type': self.recordset['type'], - }) - - # Set the TTL to an invalid value - fixture['ttl'] = "$?!." - - # Create a record, ensuring it fails with a 400 - self.post('domains/%s/records' % self.zone['id'], data=fixture, - status_code=400) - - def test_create_record_invalid_priority(self): - fixture = self.get_record_fixture(self.recordset['type']) - fixture.update({ - 'name': self.recordset['name'], - 'type': self.recordset['type'], - }) - fixture['priority'] = "$?!." - self.post('domains/%s/records' % self.zone['id'], data=fixture, - status_code=400) - - def test_create_record_negative_priority(self): - fixture = self.get_record_fixture(self.recordset['type']) - fixture.update({ - 'name': self.recordset['name'], - 'type': self.recordset['type'], - }) - fixture['priority'] = -1 - self.post('domains/%s/records' % self.zone['id'], data=fixture, - status_code=400) - - def test_create_record_priority_greater_than_max(self): - fixture = self.get_record_fixture(self.recordset['type']) - fixture.update({ - 'name': self.recordset['name'], - 'type': self.recordset['type'], - }) - fixture['priority'] = 65536 - self.post('domains/%s/records' % self.zone['id'], data=fixture, - status_code=400) - - @patch.object(central_service.Service, 'create_record', - side_effect=messaging.MessagingTimeout()) - def test_create_record_timeout(self, _): - fixture = self.get_record_fixture(self.recordset['type']) - fixture.update({ - 'name': self.recordset['name'], - 'type': self.recordset['type'], - }) - - # Create a record - self.post('domains/%s/records' % self.zone['id'], data=fixture, - status_code=504) - - def test_create_wildcard_record(self): - # Prepare a record - fixture = self.get_record_fixture(self.recordset['type']) - fixture.update({ - 'name': '*.%s' % self.recordset['name'], - 'type': self.recordset['type'], - }) - - # Create a record - response = self.post('domains/%s/records' % self.zone['id'], - data=fixture) - - self.assertIn('id', response.json) - self.assertIn('name', response.json) - self.assertEqual(response.json['name'], fixture['name']) - - def test_create_srv_record(self): - recordset_fixture = self.get_recordset_fixture( - self.zone['name'], 'SRV') - - fixture = self.get_record_fixture(recordset_fixture['type']) - priority, _, data = fixture['data'].partition(" ") - - fixture.update({ - 'data': data, - 'priority': int(priority), - 'name': recordset_fixture['name'], - 'type': recordset_fixture['type'], - }) - - # Create a record - response = self.post('domains/%s/records' % self.zone['id'], - data=fixture) - - self.assertIn('id', response.json) - self.assertEqual(fixture['type'], response.json['type']) - self.assertEqual(fixture['name'], response.json['name']) - - self.assertEqual(fixture['priority'], response.json['priority']) - self.assertEqual(fixture['data'], response.json['data']) - - def test_create_invalid_data_srv_record(self): - recordset_fixture = self.get_recordset_fixture( - self.zone['name'], 'SRV') - - fixture = self.get_record_fixture(recordset_fixture['type']) - fixture.update({ - 'name': recordset_fixture['name'], - 'type': recordset_fixture['type'], - }) - - invalid_datas = [ - 'I 5060 sip.%s' % self.zone['name'], - '5060 sip.%s' % self.zone['name'], - '5060 I sip.%s' % self.zone['name'], - '0 5060 sip', - 'sip', - 'sip.%s' % self.zone['name'], - ] - - for invalid_data in invalid_datas: - fixture['data'] = invalid_data - # Attempt to create the record - self.post('domains/%s/records' % self.zone['id'], data=fixture, - status_code=400) - - def test_create_invalid_name_srv_record(self): - recordset_fixture = self.get_recordset_fixture( - self.zone['name'], 'SRV') - - fixture = self.get_record_fixture(recordset_fixture['type']) - fixture.update({ - 'name': recordset_fixture['name'], - 'type': recordset_fixture['type'], - }) - - invalid_names = [ - '%s' % self.zone['name'], - '_udp.%s' % self.zone['name'], - 'sip._udp.%s' % self.zone['name'], - '_sip.udp.%s' % self.zone['name'], - ] - - for invalid_name in invalid_names: - fixture['name'] = invalid_name - - # Attempt to create the record - self.post('domains/%s/records' % self.zone['id'], data=fixture, - status_code=400) - - def test_create_invalid_name(self): - # Prepare a record - fixture = self.get_record_fixture(self.recordset['type']) - fixture.update({ - 'name': self.recordset['name'], - 'type': self.recordset['type'], - }) - - invalid_names = [ - 'org', - 'example.org', - '$$.example.org', - '*example.org.', - '*.*.example.org.', - 'abc.*.example.org.', - ] - - for invalid_name in invalid_names: - fixture['name'] = invalid_name - - # Create a record - response = self.post('domains/%s/records' % self.zone['id'], - data=fixture, status_code=400) - - self.assertNotIn('id', response.json) - - def test_get_records(self): - response = self.get('domains/%s/records' % self.zone['id']) - - # Verify that the SOA & NS records are already created - self.assertIn('records', response.json) - self.assertEqual(2, len(response.json['records'])) - - # Create a record - self.create_record(self.zone, self.recordset) - - response = self.get('domains/%s/records' % self.zone['id']) - - # Verify that one more record has been added - self.assertIn('records', response.json) - self.assertEqual(3, len(response.json['records'])) - - # Create a second record - self.create_record(self.zone, self.recordset, fixture=1) - - response = self.get('domains/%s/records' % self.zone['id']) - - # Verfiy that all 4 records are there - self.assertIn('records', response.json) - self.assertEqual(4, len(response.json['records'])) - - @patch.object(central_service.Service, 'get_zone', - side_effect=messaging.MessagingTimeout()) - def test_get_records_timeout(self, _): - self.get('domains/%s/records' % self.zone['id'], - status_code=504) - - def test_get_records_missing_zone(self): - self.get('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980/records', - status_code=404) - - def test_get_records_invalid_zone_id(self): - self.get('domains/2fdadfb1cf964259ac6bbb7b6d2ff980/records', - status_code=404) - - def test_get_record_missing(self): - self.get('domains/%s/records/2fdadfb1-cf96-4259-ac6b-' - 'bb7b6d2ff980' % self.zone['id'], - status_code=404) - - def test_get_record_with_invalid_id(self): - self.get('domains/%s/records/2fdadfb1-cf96-4259-ac6b-' - 'bb7b6d2ff980GH' % self.zone['id'], - status_code=404) - - def test_get_record(self): - # Create a record - record = self.create_record(self.zone, self.recordset) - - response = self.get('domains/%s/records/%s' % (self.zone['id'], - record['id'])) - - self.assertIn('id', response.json) - self.assertEqual(response.json['id'], record['id']) - self.assertEqual(response.json['name'], self.recordset['name']) - self.assertEqual(response.json['type'], self.recordset['type']) - - def test_update_record(self): - # Create a record - record = self.create_record(self.zone, self.recordset) - - # Fetch another fixture to use in the update - fixture = self.get_record_fixture(self.recordset['type'], fixture=1) - - # Update the record - data = {'data': fixture['data']} - response = self.put('domains/%s/records/%s' % (self.zone['id'], - record['id']), - data=data) - - self.assertIn('id', response.json) - self.assertEqual(response.json['id'], record['id']) - self.assertEqual(response.json['data'], fixture['data']) - self.assertEqual(response.json['type'], self.recordset['type']) - - def test_update_record_ttl(self): - # Create a record - record = self.create_record(self.zone, self.recordset) - - # Update the record - data = {'ttl': 100} - response = self.put('domains/%s/records/%s' % (self.zone['id'], - record['id']), - data=data) - - self.assertIn('id', response.json) - self.assertEqual(record['id'], response.json['id']) - self.assertEqual(record['data'], response.json['data']) - self.assertEqual(self.recordset['type'], response.json['type']) - self.assertEqual(100, response.json['ttl']) - - def test_update_record_junk(self): - # Create a record - record = self.create_record(self.zone, self.recordset) - - data = {'ttl': 100, 'junk': 'Junk Field'} - - self.put('domains/%s/records/%s' % (self.zone['id'], record['id']), - data=data, status_code=400) - - def test_update_record_negative_ttl(self): - # Create a record - record = self.create_record(self.zone, self.recordset) - - data = {'ttl': -1} - - self.put('domains/%s/records/%s' % (self.zone['id'], record['id']), - data=data, status_code=400) - - def test_update_record_ttl_greater_than_max(self): - record = self.create_record(self.zone, self.recordset) - data = {'ttl': 2174483648} - self.put('domains/%s/records/%s' % (self.zone['id'], record['id']), - data=data, status_code=400) - - def test_update_record_zero_ttl(self): - # Create a record - record = self.create_record(self.zone, self.recordset) - - data = {'ttl': 0} - - self.put('domains/%s/records/%s' % (self.zone['id'], record['id']), - data=data, status_code=400) - - def test_update_record_invalid_ttl(self): - # Create a record - record = self.create_record(self.zone, self.recordset) - - data = {'ttl': "$?>%"} - - self.put('domains/%s/records/%s' % (self.zone['id'], record['id']), - data=data, status_code=400) - - def test_update_record_description_too_long(self): - record = self.create_record(self.zone, self.recordset) - data = {'description': 'x' * 165} - self.put('domains/%s/records/%s' % (self.zone['id'], record['id']), - data=data, status_code=400) - - def test_update_record_negative_priority(self): - record = self.create_record(self.zone, self.recordset) - data = {'priority': -1} - self.put('domains/%s/records/%s' % (self.zone['id'], record['id']), - data=data, status_code=400) - - def test_update_record_invalid_priority(self): - record = self.create_record(self.zone, self.recordset) - data = {'priority': "?!:>"} - self.put('domains/%s/records/%s' % (self.zone['id'], record['id']), - data=data, status_code=400) - - def test_update_record_priority_greater_than_max(self): - record = self.create_record(self.zone, self.recordset) - data = {'priority': 65536} - self.put('domains/%s/records/%s' % (self.zone['id'], record['id']), - data=data, status_code=400) - - def test_update_record_name_too_long(self): - record = self.create_record(self.zone, self.recordset) - data = {'name': 'w' * 256 + ".%s" % self.zone.name} - self.put('domains/%s/records/%s' % (self.zone['id'], record['id']), - data=data, status_code=400) - - def test_update_record_invalid_type(self): - record = self.create_record(self.zone, self.recordset) - data = {'type': 'ABC'} - self.put('domains/%s/records/%s' % (self.zone['id'], record['id']), - data=data, status_code=400) - - def test_update_record_data_too_long(self): - record = self.create_record(self.zone, self.recordset) - data = {'data': '1' * 255 + '.2.3.4'} - self.put('domains/%s/records/%s' % (self.zone['id'], record['id']), - data=data, status_code=400) - - def test_update_record_outside_zone_fail(self): - # Create a record - record = self.create_record(self.zone, self.recordset) - - data = {'name': 'test.someotherzone.com.'} - - self.put('domains/%s/records/%s' % (self.zone['id'], record['id']), - data=data, status_code=400) - - @patch.object(central_service.Service, 'find_zone', - side_effect=messaging.MessagingTimeout()) - def test_update_record_timeout(self, _): - # Create a record - record = self.create_record(self.zone, self.recordset) - - data = {'name': 'test.example.org.'} - - self.put('domains/%s/records/%s' % (self.zone['id'], record['id']), - data=data, status_code=504) - - def test_update_record_missing(self): - data = {'name': 'test.example.org.'} - - self.put('domains/%s/records/2fdadfb1-cf96-4259-ac6b-' - 'bb7b6d2ff980' % self.zone['id'], - data=data, - status_code=404) - - def test_update_record_invalid_id(self): - data = {'name': 'test.example.org.'} - - self.put('domains/%s/records/2fdadfb1cf964259ac6bbb7b6d2ff980' % - self.zone['id'], - data=data, - status_code=404) - - def test_update_record_missing_zone(self): - data = {'name': 'test.example.org.'} - - self.put('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980/records/' - '2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', - data=data, - status_code=404) - - def test_update_record_invalid_zone_id(self): - data = {'name': 'test.example.org.'} - - self.put('domains/2fdadfb1cf964259ac6bbb7b6d2ff980/records/' - '2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', - data=data, - status_code=404) - - def test_delete_record(self): - # Create a record - record = self.create_record(self.zone, self.recordset) - - self.delete('domains/%s/records/%s' % (self.zone['id'], - record['id'])) - - # Simulate the record having been deleted on the backend - zone_serial = self.central_service.get_zone( - self.admin_context, self.zone['id']).serial - self.central_service.update_status( - self.admin_context, self.zone['id'], "SUCCESS", zone_serial) - - # Ensure we can no longer fetch the record - self.get('domains/%s/records/%s' % (self.zone['id'], - record['id']), - status_code=404) - - @patch.object(central_service.Service, 'find_zone', - side_effect=messaging.MessagingTimeout()) - def test_delete_record_timeout(self, _): - # Create a record - record = self.create_record(self.zone, self.recordset) - - self.delete('domains/%s/records/%s' % (self.zone['id'], - record['id']), - status_code=504) - - def test_delete_record_missing(self): - self.delete('domains/%s/records/2fdadfb1-cf96-4259-ac6b-' - 'bb7b6d2ff980' % self.zone['id'], - status_code=404) - - def test_delete_record_missing_zone(self): - self.delete('domains/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980/records/' - '2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', - status_code=404) - - def test_delete_record_invalid_zone_id(self): - self.delete('domains/2fdadfb1cf964259ac6bbb7b6d2ff980/records/' - '2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', - status_code=404) - - def test_delete_record_invalid_id(self): - self.delete('domains/%s/records/2fdadfb1-cf96-4259-ac6b-' - 'bb7b6d2ff980GH' % self.zone['id'], - status_code=404) - - def test_get_record_in_secondary(self): - fixture = self.get_zone_fixture('SECONDARY', 1) - fixture['email'] = "root@example.com" - - zone = self.create_zone(**fixture) - - record = self.create_record(zone, self.recordset) - - url = 'zones/%s/records/%s' % (zone.id, record.id) - self.get(url, status_code=404) - - def test_create_record_in_secondary(self): - fixture = self.get_zone_fixture('SECONDARY', 1) - fixture['email'] = "root@example.com" - - zone = self.create_zone(**fixture) - - record = { - "name": "foo.%s" % zone.name, - "type": "A", - "data": "10.0.0.1" - } - - url = 'zones/%s/records' % zone.id - self.post(url, record, status_code=404) - - def test_update_record_in_secondary(self): - fixture = self.get_zone_fixture('SECONDARY', 1) - fixture['email'] = "root@example.com" - - zone = self.create_zone(**fixture) - - record = self.create_record(zone, self.recordset) - - url = 'zones/%s/records/%s' % (zone.id, record.id) - self.put(url, {"data": "10.0.0.1"}, status_code=404) - - def test_delete_record_in_secondary(self): - fixture = self.get_zone_fixture('SECONDARY', 1) - fixture['email'] = "root@example.com" - - zone = self.create_zone(**fixture) - - record = self.create_record(zone, self.recordset) - - url = 'zones/%s/records/%s' % (zone.id, record.id) - self.delete(url, status_code=404) - - def test_create_record_deleting_zone(self): - recordset_fixture = self.get_recordset_fixture( - self.zone['name']) - - fixture = self.get_record_fixture(recordset_fixture['type']) - fixture.update({ - 'name': recordset_fixture['name'], - 'type': recordset_fixture['type'], - }) - - self.delete('/domains/%s' % self.zone['id']) - self.post('domains/%s/records' % self.zone['id'], - data=fixture, status_code=404) - - def test_update_record_deleting_zone(self): - # Create a record - record = self.create_record(self.zone, self.recordset) - - # Fetch another fixture to use in the update - fixture = self.get_record_fixture(self.recordset['type'], fixture=1) - - # Update the record - data = {'data': fixture['data']} - self.delete('/domains/%s' % self.zone['id']) - self.put('domains/%s/records/%s' % (self.zone['id'], - record['id']), - data=data, status_code=404) - - def test_delete_record_deleting_zone(self): - # Create a record - record = self.create_record(self.zone, self.recordset) - - self.delete('/domains/%s' % self.zone['id']) - self.delete('domains/%s/records/%s' % (self.zone['id'], - record['id']), - status_code=404) - - -class ApiV1TxtRecordsTest(ApiV1Test): - def setUp(self): - super(ApiV1TxtRecordsTest, self).setUp() - - self.zone = self.create_zone() - self.recordset = self.create_recordset(self.zone, 'TXT') - - def test_create_txt_record(self): - # See bug #1474012 - record = self.create_record(self.zone, self.recordset) - data = {'data': 'a' * 255} - self.put( - 'domains/%s/records/%s' % (self.zone['id'], record['id']), - data=data - ) - - def test_create_txt_record_too_long(self): - # See bug #1474012 - record = self.create_record(self.zone, self.recordset) - data = {'data': 'a' * 256} - self.put( - 'domains/%s/records/%s' % (self.zone['id'], record['id']), - data=data, - status_code=400 - ) diff --git a/designate/tests/test_api/test_v1/test_servers.py b/designate/tests/test_api/test_v1/test_servers.py deleted file mode 100644 index ebe4101b1..000000000 --- a/designate/tests/test_api/test_v1/test_servers.py +++ /dev/null @@ -1,244 +0,0 @@ -# Copyright 2012 Managed I.T. -# -# Author: Kiall Mac Innes -# -# 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 mock import patch -import oslo_messaging as messaging -from oslo_config import cfg -from oslo_log import log as logging - -from designate import exceptions -from designate import objects -from designate.central import service as central_service -from designate.tests.test_api.test_v1 import ApiV1Test - -cfg.CONF.import_opt('default_pool_id', - 'designate.central', - group='service:central') -default_pool_id = cfg.CONF['service:central'].default_pool_id - -LOG = logging.getLogger(__name__) - - -class ApiV1ServersTest(ApiV1Test): - def setUp(self): - super(ApiV1ServersTest, self).setUp() - - # All Server Checks should be performed as an admin, so.. - # Override to policy to make everyone an admin. - - self.policy({'admin': '@'}) - - def test_get_server_schema(self): - response = self.get('schemas/server') - self.assertIn('description', response.json) - self.assertIn('id', response.json) - self.assertIn('title', response.json) - self.assertIn('additionalProperties', response.json) - self.assertIn('properties', response.json) - self.assertIn('name', response.json['properties']) - self.assertIn('links', response.json) - self.assertIn('created_at', response.json['properties']) - self.assertIn('updated_at', response.json['properties']) - - def test_get_servers_schema(self): - response = self.get('schemas/servers') - self.assertIn('description', response.json) - self.assertIn('id', response.json) - self.assertIn('title', response.json) - self.assertIn('additionalProperties', response.json) - self.assertIn('properties', response.json) - - def test_create_server(self): - # Create a server - # In a base somewhere, we create the default / 0 server fixture - # automatically, so this would trigger a duplicate otherwise. - fixture = self.get_server_fixture(1) - - response = self.post('servers', data=fixture) - - self.assertIn('id', response.json) - self.assertIn('name', response.json) - self.assertEqual(response.json['name'], fixture['name']) - - def test_create_server_junk(self): - # Create a server - fixture = self.get_server_fixture(0) - - # Add a junk property - fixture['junk'] = 'Junk Field' - - # Ensure it fails with a 400 - self.post('servers', data=fixture, status_code=400) - - def test_create_server_with_invalid_name(self): - # Create a server - fixture = self.get_server_fixture(0) - - # Add an invalid name - fixture['name'] = '$#$%^^' - - # Ensure it fails with a 400 - self.post('servers', data=fixture, status_code=400) - - def test_create_server_name_missing(self): - fixture = self.get_server_fixture(0) - del fixture['name'] - self.post('servers', data=fixture, status_code=400) - - def test_create_server_name_too_long(self): - fixture = self.get_server_fixture(0) - fixture['name'] = 'a' * 255 + '.example.org.' - self.post('servers', data=fixture, status_code=400) - - @patch.object(central_service.Service, 'update_pool', - side_effect=messaging.MessagingTimeout()) - def test_create_server_timeout(self, _): - # Create a server - fixture = self.get_server_fixture(0) - - self.post('servers', data=fixture, status_code=504) - - @patch.object(central_service.Service, 'update_pool', - side_effect=exceptions.DuplicateServer()) - def test_create_server_duplicate(self, _): - # Create a server - fixture = self.get_server_fixture(0) - - self.post('servers', data=fixture, status_code=409) - - def test_get_servers(self): - # Fetch the default pool - pool = self.storage.get_pool(self.admin_context, default_pool_id) - - # Fetch the list of servers - response = self.get('servers') - - self.assertIn('servers', response.json) - self.assertEqual(len(pool.ns_records), len(response.json['servers'])) - - # Add a new NS record to the pool - pool.ns_records.append( - objects.PoolNsRecord(priority=1, hostname='new-ns1.example.org.')) - - # Save the pool to add a new nameserver - self.storage.update_pool(self.admin_context, pool) - - # Fetch the list of servers - response = self.get('servers') - - self.assertIn('servers', response.json) - self.assertEqual(len(pool.ns_records), len(response.json['servers'])) - - # Add a new NS record to the pool - pool.ns_records.append( - objects.PoolNsRecord(priority=1, hostname='new-ns2.example.org.')) - - # Save the pool to add a new nameserver - self.storage.update_pool(self.admin_context, pool) - - response = self.get('servers') - - self.assertIn('servers', response.json) - self.assertEqual(len(pool.ns_records), len(response.json['servers'])) - - @patch.object(central_service.Service, 'get_pool', - side_effect=messaging.MessagingTimeout()) - def test_get_servers_timeout(self, _): - self.get('servers', status_code=504) - - def test_get_server(self): - # Fetch the default pool - pool = self.storage.get_pool(self.admin_context, default_pool_id) - - # Fetch the Server from the pool - response = self.get('servers/%s' % pool.ns_records[0].id) - - self.assertIn('id', response.json) - self.assertEqual(response.json['id'], pool.ns_records[0]['id']) - - @patch.object(central_service.Service, 'get_pool', - side_effect=messaging.MessagingTimeout()) - def test_get_server_timeout(self, _): - # Fetch the default pool - pool = self.storage.get_pool(self.admin_context, default_pool_id) - - self.get('servers/%s' % pool.ns_records[0].id, status_code=504) - - def test_get_server_with_invalid_id(self): - self.get('servers/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff98GH', - status_code=404) - - def test_get_server_missing(self): - self.get('servers/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', - status_code=404) - - def test_update_server(self): - # Fetch the default pool - pool = self.storage.get_pool(self.admin_context, default_pool_id) - - data = {'name': 'new-ns1.example.org.'} - - response = self.put('servers/%s' % pool.ns_records[0].id, - data=data) - - self.assertIn('id', response.json) - self.assertEqual(response.json['id'], pool.ns_records[0].id) - - self.assertIn('name', response.json) - self.assertEqual(response.json['name'], 'new-ns1.example.org.') - - def test_update_server_missing(self): - data = {'name': 'test.example.org.'} - self.put('servers/2fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', data=data, - status_code=404) - - def test_update_server_junk(self): - # Fetch the default pool - pool = self.storage.get_pool(self.admin_context, default_pool_id) - - data = {'name': 'test.example.org.', 'junk': 'Junk Field'} - - self.put('servers/%s' % pool.ns_records[0].id, data=data, - status_code=400) - - def test_delete_server(self): - # Fetch the default pool - pool = self.storage.get_pool(self.admin_context, default_pool_id) - - # Create a second server so that we can delete the first - # because the last remaining server is not allowed to be deleted - # Add a new NS record to the pool - pool.ns_records.append( - objects.PoolNsRecord(priority=1, hostname='new-ns2.example.org.')) - - # Save the pool to add a new nameserver - self.storage.update_pool(self.admin_context, pool) - - # Now delete the server - self.delete('servers/%s' % pool.ns_records[1].id) - - # Ensure we can no longer fetch the deleted server - self.get('servers/%s' % pool.ns_records[1].id, status_code=404) - - # Also, verify we cannot delete last remaining server - self.delete('servers/%s' % pool.ns_records[0].id, status_code=400) - - def test_delete_server_with_invalid_id(self): - self.delete('servers/9fdadfb1-cf96-4259-ac6b-bb7b6d2ff98GH', - status_code=404) - - def test_delete_server_missing(self): - self.delete('servers/9fdadfb1-cf96-4259-ac6b-bb7b6d2ff980', - status_code=404) diff --git a/designate/tests/test_api/test_v1/test_tsigkeys.py b/designate/tests/test_api/test_v1/test_tsigkeys.py deleted file mode 100644 index 189a132a4..000000000 --- a/designate/tests/test_api/test_v1/test_tsigkeys.py +++ /dev/null @@ -1,136 +0,0 @@ -# Copyright 2015 NEC Corporation. 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. - -from mock import patch -import oslo_messaging as messaging -from oslo_log import log as logging - -from designate.central import service as central_service -from designate.tests.test_api.test_v1 import ApiV1Test - - -LOG = logging.getLogger(__name__) - - -class ApiV1TsigkeysTest(ApiV1Test): - def setUp(self): - super(ApiV1TsigkeysTest, self).setUp() - - # Set the policy to accept everyone as an admin, as this is an - # admin-only API - self.policy({'admin': '@'}) - - def test_get_tsigkey_schema(self): - response = self.get('schemas/tsigkey') - self.assertIn('description', response.json) - self.assertIn('links', response.json) - self.assertIn('title', response.json) - self.assertIn('id', response.json) - self.assertIn('additionalProperties', response.json) - self.assertIn('properties', response.json) - self.assertIn('name', response.json['properties']) - self.assertIn('algorithm', response.json['properties']) - self.assertIn('secret', response.json['properties']) - - def test_get_tsigkeys_schema(self): - response = self.get('schemas/tsigkeys') - self.assertIn('description', response.json) - self.assertIn('title', response.json) - self.assertIn('id', response.json) - self.assertIn('additionalProperties', response.json) - self.assertIn('properties', response.json) - self.assertIn('tsigkeys', response.json['properties']) - - def test_create_tsigkeys(self): - # Create a Tsigkey - fixture = self.get_tsigkey_fixture(0) - - # V1 doesn't have these - del fixture['scope'] - del fixture['resource_id'] - - response = self.post('tsigkeys', data=fixture) - self.assertIn('id', response.json) - - self.assertIn('name', response.json) - self.assertEqual(response.json['name'], fixture['name']) - - def test_create_tsigkeys_junk(self): - # Create a tsigkey - fixture = self.get_tsigkey_fixture(0) - - # Add a junk property - fixture['junk'] = 'Junk Field' - - # Ensure it fails with a 400 - self.post('tsigkeys', data=fixture, status_code=400) - - def test_create_tsigkey_name_missing(self): - # Create tsigkey - fixture = self.get_tsigkey_fixture(0) - - del fixture['name'] - - self.post('tsigkeys', data=fixture, status_code=400) - - def test_create_tsigkey_algorithm_missing(self): - # Create tsigkey - fixture = self.get_tsigkey_fixture(0) - - del fixture['algorithm'] - - self.post('tsigkeys', data=fixture, status_code=400) - - def test_create_tsigkey_secret_missing(self): - # Create tsigkey - fixture = self.get_tsigkey_fixture(0) - - del fixture['secret'] - - self.post('tsigkeys', data=fixture, status_code=400) - - def test_create_tsigkey_name_too_long(self): - # Create a tsigkey - fixture = self.get_tsigkey_fixture(0) - - fixture['name'] = 'x' * 300 - - self.post('tsigkeys', data=fixture, status_code=400) - - def test_create_tsigkey_secret_too_long(self): - # Create a tsigkey - fixture = self.get_tsigkey_fixture(0) - - fixture['secret'] = 'x' * 300 - - self.post('tsigkeys', data=fixture, status_code=400) - - def test_delete_tsigkey(self): - # Delete a tsigkey - tsigkey = self.create_tsigkey() - - self.delete('/tsigkeys/%s' % tsigkey['id'], status=200) - - @patch.object(central_service.Service, 'find_tsigkeys', - side_effect=messaging.MessagingTimeout()) - def test_get_tsigkeys_timeout(self, _): - self.get('tsigkeys', status_code=504) - - @patch.object(central_service.Service, 'find_tsigkeys', - side_effect=messaging.MessagingTimeout()) - def test_get_tsigkey_timeout(self, _): - # Create a tsigkey - tsigkey = self.create_tsigkey() - - self.get('tsigkeys/%s' % tsigkey['id'], status_code=504) diff --git a/designate/tests/test_schema/__init__.py b/designate/tests/test_schema/__init__.py index efd3d63cd..c78503f9a 100644 --- a/designate/tests/test_schema/__init__.py +++ b/designate/tests/test_schema/__init__.py @@ -19,6 +19,6 @@ from designate import schema class TestSchema(TestCase): def test_constructor(self): - zone = schema.Schema('v1', 'domain') + quota = schema.Schema('admin', 'quota') - self.assertIsInstance(zone, schema.Schema) + self.assertIsInstance(quota, schema.Schema) diff --git a/designate/tests/test_utils.py b/designate/tests/test_utils.py index f6e2880ad..6127442b0 100644 --- a/designate/tests/test_utils.py +++ b/designate/tests/test_utils.py @@ -47,11 +47,6 @@ class TestUtils(TestCase): with testtools.ExpectedException(ValueError): utils.resource_string() - def test_load_schema(self): - schema = utils.load_schema('v1', 'domain') - - self.assertIsInstance(schema, dict) - def test_load_schema_missing(self): with testtools.ExpectedException(exceptions.ResourceNotFound): utils.load_schema('v1', 'missing') diff --git a/devstack/gate/run_tempest_tests.sh b/devstack/gate/run_tempest_tests.sh index 002311360..ca6911e18 100755 --- a/devstack/gate/run_tempest_tests.sh +++ b/devstack/gate/run_tempest_tests.sh @@ -15,7 +15,7 @@ # 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 +if ! timeout ${API_RESPONDING_TIMEOUT} sh -c "while ! curl -s http://127.0.0.1:9001/ 2>/dev/null | grep -q 'v2' ; do sleep 1; done"; then echo "The Designate API failed to respond within ${API_RESPONDING_TIMEOUT} seconds" exit 1 fi diff --git a/devstack/plugin.sh b/devstack/plugin.sh index 6bbd291b8..c9d43491e 100755 --- a/devstack/plugin.sh +++ b/devstack/plugin.sh @@ -83,11 +83,9 @@ function configure_designate { # 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_base_uri $DESIGNATE_SERVICE_PROTOCOL://$DESIGNATE_SERVICE_HOST:$DESIGNATE_SERVICE_PORT/ - iniset $DESIGNATE_CONF service:api enable_api_v1 $DESIGNATE_ENABLE_API_V1 iniset $DESIGNATE_CONF service:api enable_api_v2 $DESIGNATE_ENABLE_API_V2 iniset $DESIGNATE_CONF service:api enable_api_admin $DESIGNATE_ENABLE_API_ADMIN @@ -163,7 +161,6 @@ function configure_designate_tempest() { iniset $TEMPEST_CONFIG service_available designate True # Tell tempest which APIs are available - iniset $TEMPEST_CONFIG dns_feature_enabled api_v1 $DESIGNATE_ENABLE_API_V1 iniset $TEMPEST_CONFIG dns_feature_enabled api_v2 $DESIGNATE_ENABLE_API_V2 iniset $TEMPEST_CONFIG dns_feature_enabled api_admin $DESIGNATE_ENABLE_API_ADMIN iniset $TEMPEST_CONFIG dns_feature_enabled api_v2_root_recordsets True diff --git a/devstack/settings b/devstack/settings index 1ed3f3f6a..6f77ddb5a 100644 --- a/devstack/settings +++ b/devstack/settings @@ -20,10 +20,8 @@ DESIGNATE_QUOTA_RECORDSET_RECORDS=${DESIGNATE_QUOTA_RECORDSET_RECORDS:-20} DESIGNATE_QUOTA_API_EXPORT_SIZE=${DESIGNATE_QUOTA_API_EXPORT_SIZE:-1000} # Default APIs and Extensions -DESIGNATE_ENABLE_API_V1=${DESIGNATE_ENABLE_API_V1:-"True"} DESIGNATE_ENABLE_API_V2=${DESIGNATE_ENABLE_API_V2:-"True"} DESIGNATE_ENABLE_API_ADMIN=${DESIGNATE_ENABLE_API_ADMIN:-"True"} -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"} diff --git a/doc/source/configuration/index.rst b/doc/source/configuration/index.rst index b4b5b56a2..238044d76 100644 --- a/doc/source/configuration/index.rst +++ b/doc/source/configuration/index.rst @@ -28,17 +28,6 @@ directory. .. index:: double: configure; designate -#. Create the designate.conf file - - :: - - $ editor designate.conf - -#. Copy or mirror the configuration from this sample file here: - - .. literalinclude:: ../examples/basic-config-sample.conf - :language: ini - #. You can generate full sample *designate.conf* (if it does not already exist):: $ oslo-config-generator --config-file etc/designate/designate-config-generator.conf --output-file /etc/designate/designate.conf diff --git a/doc/source/examples/basic-config-sample.conf b/doc/source/examples/basic-config-sample.conf deleted file mode 100644 index 4f1c864fd..000000000 --- a/doc/source/examples/basic-config-sample.conf +++ /dev/null @@ -1,130 +0,0 @@ -[DEFAULT] -######################## -## General Configuration -######################## -# Show debugging output in logs (sets DEBUG log level output) -debug = True - -# Top-level directory for maintaining designate's state. -state_path = $pybasedir/state - -# 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 -transport_url = rabbit://designate:designate@127.0.0.1// - -[oslo_messaging_notifications] -# Driver used for issuing notifications -driver = messaging - -######################## -## 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] -# API host:port pairs to listen on -listen = 0.0.0.0: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 - -#----------------------- -# Worker Service -#----------------------- -[service:worker] -# Whether to send events to worker instead of Pool Manager -enabled = True -#workers = None -#threads = 1000 -#threshold_percentage = 100 -#poll_timeout = 30 -#poll_retry_interval = 15 -#poll_max_retries = 10 -#poll_delay = 5 -#notify = True - -#----------------------- -# Producer Service -#----------------------- -[service:producer] -#workers = None -#threads = 1000 -#enabled_tasks = None -#export_synchronous = True - -#------------------------ -# Deleted domains purging -#------------------------ -[producer_task:domain_purge] -#interval = 3600 # 1h -#batch_size = 100 -#time_threshold = 604800 # 7 days - -#------------------------ -# Delayed zones NOTIFY -#------------------------ -[producer_task:delayed_notify] -#interval = 5 - -#------------------------ -# Worker Periodic Recovery -#------------------------ -[producer_task:worker_periodic_recovery] -#interval = 120 - -######################## -## 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 - diff --git a/doc/source/install/install-obs.rst b/doc/source/install/install-obs.rst index 8115ab3f7..ed3d2c6e7 100644 --- a/doc/source/install/install-obs.rst +++ b/doc/source/install/install-obs.rst @@ -93,9 +93,7 @@ Install and configure components [service:api] listen = 0.0.0.0:9001 auth_strategy = keystone - enable_api_v1 = True api_base_uri = http://controller:9001/ - enabled_extensions_v1 = quotas, reports enable_api_v2 = True enabled_extensions_v2 = quotas, reports diff --git a/doc/source/install/install-rdo.rst b/doc/source/install/install-rdo.rst index c797c9bdc..af6bc17ad 100644 --- a/doc/source/install/install-rdo.rst +++ b/doc/source/install/install-rdo.rst @@ -93,9 +93,7 @@ Install and configure components [service:api] listen = 0.0.0.0:9001 auth_strategy = keystone - enable_api_v1 = True api_base_uri = http://controller:9001/ - enabled_extensions_v1 = quotas, reports enable_api_v2 = True enabled_extensions_v2 = quotas, reports diff --git a/doc/source/install/install-ubuntu.rst b/doc/source/install/install-ubuntu.rst index 51fddfc3d..d8e1b022c 100644 --- a/doc/source/install/install-ubuntu.rst +++ b/doc/source/install/install-ubuntu.rst @@ -86,9 +86,7 @@ Install and configure components [service:api] listen = 0.0.0.0:9001 auth_strategy = keystone - enable_api_v1 = True api_base_uri = http://controller:9001/ - enabled_extensions_v1 = quotas, reports enable_api_v2 = True enabled_extensions_v2 = quotas, reports diff --git a/doc/source/user/manage-ptr-records.rst b/doc/source/user/manage-ptr-records.rst index b395ade2f..fac0499b9 100644 --- a/doc/source/user/manage-ptr-records.rst +++ b/doc/source/user/manage-ptr-records.rst @@ -336,138 +336,3 @@ for more information. 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 let's 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. - -Let's 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! diff --git a/doc/source/user/rest.rst b/doc/source/user/rest.rst index e464cfec9..4e4a733a8 100644 --- a/doc/source/user/rest.rst +++ b/doc/source/user/rest.rst @@ -12,18 +12,13 @@ example: .. code-block:: http - POST /v2/pools HTTP/1.1 + POST /v2/zones HTTP/1.1 Accept: application/json Content-Type: application/json { - "name": "Example Pool", - "ns_records": [ - { - "hostname": "ns1.example.org.", - "priority": 1 - } - ] + "name": "example.org.", + "email": "hostmaster@example.org" } With this info we can make this request using the cURL_ tool. We'll @@ -34,8 +29,8 @@ assume we are running Designate on `localhost`. curl -X POST -i \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ - -d '{"name": "ns1.example.org."}' \ - http://localhost:9001/v1/servers + -d '{"name": "example.org.", "email": "hostmaster@example.org"}' \ + http://localhost:9001/v2/zones The `-i` flag is used to dump the response headers as well as the response body. @@ -64,24 +59,6 @@ These headers work for all APIs 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 ------ diff --git a/doc/source/user/rest/v1/diagnostics.rst b/doc/source/user/rest/v1/diagnostics.rst deleted file mode 100644 index a3b51a95e..000000000 --- a/doc/source/user/rest/v1/diagnostics.rst +++ /dev/null @@ -1,66 +0,0 @@ -.. - 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 Denied diff --git a/doc/source/user/rest/v1/domains.rst b/doc/source/user/rest/v1/domains.rst deleted file mode 100644 index 2b1625eac..000000000 --- a/doc/source/user/rest/v1/domains.rst +++ /dev/null @@ -1,293 +0,0 @@ -Domains -======= - -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 - diff --git a/doc/source/user/rest/v1/quotas.rst b/doc/source/user/rest/v1/quotas.rst deleted file mode 100644 index a42c27ab9..000000000 --- a/doc/source/user/rest/v1/quotas.rst +++ /dev/null @@ -1,141 +0,0 @@ -.. - 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 - diff --git a/doc/source/user/rest/v1/records.rst b/doc/source/user/rest/v1/records.rst deleted file mode 100644 index c4077c751..000000000 --- a/doc/source/user/rest/v1/records.rst +++ /dev/null @@ -1,832 +0,0 @@ -Records -======= - -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 HTTP/1.1 - 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:: guess - - 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 diff --git a/doc/source/user/rest/v1/reports.rst b/doc/source/user/rest/v1/reports.rst deleted file mode 100644 index a490fa423..000000000 --- a/doc/source/user/rest/v1/reports.rst +++ /dev/null @@ -1,238 +0,0 @@ -.. - 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 Denied diff --git a/doc/source/user/rest/v1/servers.rst b/doc/source/user/rest/v1/servers.rst deleted file mode 100644 index 90e218233..000000000 --- a/doc/source/user/rest/v1/servers.rst +++ /dev/null @@ -1,205 +0,0 @@ -Servers -======= - -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:: guess - - 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 - diff --git a/doc/source/user/rest/v1/sync.rst b/doc/source/user/rest/v1/sync.rst deleted file mode 100644 index 8b7e58e14..000000000 --- a/doc/source/user/rest/v1/sync.rst +++ /dev/null @@ -1,112 +0,0 @@ -.. - 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 Denied diff --git a/etc/designate/api-paste.ini b/etc/designate/api-paste.ini index b899d46c2..41e840d41 100644 --- a/etc/designate/api-paste.ini +++ b/etc/designate/api-paste.ini @@ -1,7 +1,6 @@ [composite:osapi_dns] use = egg:Paste#urlmap /: osapi_dns_versions -/v1: osapi_dns_v1 /v2: osapi_dns_v2 /admin: osapi_dns_admin @@ -13,14 +12,6 @@ keystone = http_proxy_to_wsgi cors maintenance faultwrapper osapi_dns_app_versio [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 @@ -66,11 +57,5 @@ 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 diff --git a/etc/designate/policy.yaml.sample b/etc/designate/policy.yaml.sample index 5123b1e33..c73680fa0 100644 --- a/etc/designate/policy.yaml.sample +++ b/etc/designate/policy.yaml.sample @@ -26,7 +26,7 @@ #"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)" +#"zone_primary_or_admin": "('PRIMARY':%(zone_type)s and rule:admin_or_owner) OR ('SECONDARY':%(zone_type)s AND is_admin:True)" # Create blacklist. # POST /v2/blacklists @@ -120,75 +120,36 @@ # DELETE /v2/quotas/{project_id} #"reset_quotas": "rule:admin" -# Create record. -# POST /v1/domains//records -#"create_record": "rule:admin_or_owner" - -# Get records. -# GET /v1/domains//records -#"get_records": "rule:admin_or_owner" - -# Get record. -# GET /v1/domains//records/ -#"get_record": "rule:admin_or_owner" - # Find records. # GET /v2/reverse/floatingips/{region}:{floatingip_id} # GET /v2/reverse/floatingips #"find_records": "rule:admin_or_owner" -# Find record. -# GET /v1/domains//records/ -# DELETE /v1/domains//records/ -# PUT /v1/domains//records/ -#"find_record": "rule:admin_or_owner" - -# Update record. -# PUT /v1/domains//records/ -#"update_record": "rule:admin_or_owner" - -# Delete record. -# DELETE /v1/domains//records/ -#"delete_record": "rule:admin_or_owner" - # #"count_records": "rule:admin_or_owner" # Create Recordset # POST /v2/zones/{zone_id}/recordsets # PATCH /v2/reverse/floatingips/{region}:{floatingip_id} -#"create_recordset": "('PRIMARY':%(zone_type)s and rule:admin_or_owner) OR ('SECONDARY':%(zone_type)s AND is_admin:True)" +#"create_recordset": "('PRIMARY':%(zone_type)s and rule:admin_or_owner) OR ('SECONDARY':%(zone_type)s AND is_admin:True)" # #"get_recordsets": "rule:admin_or_owner" # Get recordset -# GET /v1/domains//records/ -# PUT /v1/domains//records/ # GET /v2/zones/{zone_id}/recordsets/{recordset_id} # DELETE /v2/zones/{zone_id}/recordsets/{recordset_id} # PUT /v2/zones/{zone_id}/recordsets/{recordset_id} #"get_recordset": "rule:admin_or_owner" -# Find recordsets -# GET /v1/domains//records -#"find_recordsets": "rule:admin_or_owner" - -# Find recordset -# POST /v1/domains//records -# DELETE /v1/domains//records/ -#"find_recordset": "rule:admin_or_owner" - # Update recordset -# PUT /v1/domains//records/ # PUT /v2/zones/{zone_id}/recordsets/{recordset_id} # PATCH /v2/reverse/floatingips/{region}:{floatingip_id} -#"update_recordset": "('PRIMARY':%(zone_type)s and rule:admin_or_owner) OR ('SECONDARY':%(zone_type)s AND is_admin:True)" +#"update_recordset": "('PRIMARY':%(zone_type)s and rule:admin_or_owner) OR ('SECONDARY':%(zone_type)s AND is_admin:True)" # Delete RecordSet -# DELETE /v1/domains//records/ # DELETE /v2/zones/{zone_id}/recordsets/{recordset_id} -#"delete_recordset": "('PRIMARY':%(zone_type)s and rule:admin_or_owner) OR ('SECONDARY':%(zone_type)s AND is_admin:True)" +#"delete_recordset": "('PRIMARY':%(zone_type)s and rule:admin_or_owner) OR ('SECONDARY':%(zone_type)s AND is_admin:True)" # Count recordsets #"count_recordset": "rule:admin_or_owner" @@ -234,14 +195,10 @@ #"delete_tld": "rule:admin" # Create Tsigkey -# POST /v1/tsigkeys # POST /v2/tsigkeys #"create_tsigkey": "rule:admin" # List Tsigkeys -# GET /v1/tsigkeys -# GET /v1/tsigkeys/ -# DELETE /v1/tsigkeys/ # GET /v2/tsigkeys #"find_tsigkeys": "rule:admin" @@ -251,17 +208,14 @@ #"get_tsigkey": "rule:admin" # Update Tsigkey -# PATCH /v1/tsigkeys/{tsigkey_id} # PATCH /v2/tsigkeys/{tsigkey_id} #"update_tsigkey": "rule:admin" # Delete a Tsigkey -# DELETE /v1/tsigkeys/{tsigkey_id} # DELETE /v2/tsigkeys/{tsigkey_id} #"delete_tsigkey": "rule:admin" # Create Zone -# POST /v1//domains # POST /v2/zones #"create_zone": "rule:admin_or_owner" @@ -269,8 +223,6 @@ #"get_zones": "rule:admin_or_owner" # Get Zone -# GET /v1/domains//records/ -# GET /v1/domains//records # GET /v2/zones/{zone_id} # PATCH /v2/zones/{zone_id} # PUT /v2/zones/{zone_id}/recordsets/{recordset_id} @@ -280,24 +232,14 @@ #"get_zone_servers": "rule:admin_or_owner" # List existing zones -# GET /v1/domains # GET /v2/zones #"find_zones": "rule:admin_or_owner" -# Find Zone -# GET /v1/domains/ -# GET /v1/domains//servers -# PUT /v1/domains/ -# DELETE /v1/domains/ -#"find_zone": "rule:admin_or_owner" - # Update Zone -# PUT /v1/domains/ # PATCH /v2/zones/{zone_id} #"update_zone": "rule:admin_or_owner" # Delete Zone -# DELETE /v1/domains/ # DELETE /v2/zones/{zone_id} #"delete_zone": "rule:admin_or_owner" @@ -364,7 +306,7 @@ # Create Zone Transfer Accept # POST /v2/zones/tasks/transfer_accepts -#"create_zone_transfer_accept": "rule:admin_or_owner or tenant:%(target_tenant_id)s or None:%(target_tenant_id)s" +#"create_zone_transfer_accept": "rule:admin_or_owner OR tenant:%(target_tenant_id)s OR None:%(target_tenant_id)s" # Get Zone Transfer Accept # GET /v2/zones/tasks/transfer_requests/{zone_transfer_accept_id} @@ -391,7 +333,7 @@ # Show a Zone Transfer Request # GET /v2/zones/tasks/transfer_requests/{zone_transfer_request_id} # PATCH /v2/zones/tasks/transfer_requests/{zone_transfer_request_id} -#"get_zone_transfer_request": "rule:admin_or_owner or tenant:%(target_tenant_id)s or None:%(target_tenant_id)s" +#"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" diff --git a/playbooks/legacy/grenade-devstack-designate-pdns4/run.yaml b/playbooks/legacy/grenade-devstack-designate-pdns4/run.yaml index 9e0b9c952..e0cfbd18c 100644 --- a/playbooks/legacy/grenade-devstack-designate-pdns4/run.yaml +++ b/playbooks/legacy/grenade-devstack-designate-pdns4/run.yaml @@ -46,7 +46,7 @@ export DEVSTACK_GATE_TEMPEST=1 export DEVSTACK_GATE_TEMPEST_ALL_PLUGINS=1 export DEVSTACK_GATE_GRENADE=pullup - export DEVSTACK_GATE_TEMPEST_REGEX=designate + export DEVSTACK_GATE_TEMPEST_REGEX="designate_tempest_plugin(?!\.tests.api.v1).*" export DEVSTACK_GATE_HORIZON=1 export PROJECTS="openstack/designate $PROJECTS" diff --git a/releasenotes/notes/remove-v1-api-e38de408c6454de2.yaml b/releasenotes/notes/remove-v1-api-e38de408c6454de2.yaml new file mode 100644 index 000000000..749528f0b --- /dev/null +++ b/releasenotes/notes/remove-v1-api-e38de408c6454de2.yaml @@ -0,0 +1,9 @@ +--- +prelude: > + V1 API removal is complete in this version of designate. +upgrade: + - | + Any tooling using the V1 API needs to be reworked to use the v2 API +critical: + - | + V1 API has been removed diff --git a/setup.cfg b/setup.cfg index 06ba8a152..ace7694fe 100644 --- a/setup.cfg +++ b/setup.cfg @@ -64,19 +64,6 @@ console_scripts = designate-worker = designate.cmd.worker:main designate-producer = designate.cmd.producer: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