diff options
author | Graham Hayes <gr@ham.ie> | 2017-11-17 17:17:38 +0000 |
---|---|---|
committer | Dai Dang Van <daidv@vn.fujitsu.com> | 2018-01-11 14:13:43 +0000 |
commit | c318106c01b2b3976049f2c3ba0c8502a874242b (patch) | |
tree | 38845cce3cd24fe2cfc86887d23bd6a22fbbff61 /designate/api | |
parent | 11ab86e320860c0ba07b5b62d11cd1acfd8b4ab6 (diff) | |
download | designate-c318106c01b2b3976049f2c3ba0c8502a874242b.tar.gz |
Remove v1 API
This completes the long awaited removal of the V1 API.
Change-Id: I30c8a5e8569b1b86286c5e3cb07856c06ebe5803
Diffstat (limited to 'designate/api')
-rw-r--r-- | designate/api/__init__.py | 12 | ||||
-rw-r--r-- | designate/api/middleware.py | 17 | ||||
-rw-r--r-- | designate/api/v1/__init__.py | 149 | ||||
-rw-r--r-- | designate/api/v1/domains.py | 173 | ||||
-rw-r--r-- | designate/api/v1/extensions/__init__.py | 0 | ||||
-rw-r--r-- | designate/api/v1/extensions/diagnostics.py | 34 | ||||
-rw-r--r-- | designate/api/v1/extensions/quotas.py | 83 | ||||
-rw-r--r-- | designate/api/v1/extensions/reports.py | 78 | ||||
-rw-r--r-- | designate/api/v1/extensions/sync.py | 52 | ||||
-rw-r--r-- | designate/api/v1/extensions/touch.py | 31 | ||||
-rw-r--r-- | designate/api/v1/limits.py | 46 | ||||
-rw-r--r-- | designate/api/v1/records.py | 277 | ||||
-rw-r--r-- | designate/api/v1/servers.py | 226 | ||||
-rw-r--r-- | designate/api/v1/tsigkeys.py | 155 | ||||
-rw-r--r-- | designate/api/versions.py | 4 |
15 files changed, 0 insertions, 1337 deletions
diff --git a/designate/api/__init__.py b/designate/api/__init__.py index 8e18c8d2..c0a60284 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 15acacc8..e39f8962 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 e76e1786..00000000 --- a/designate/api/v1/__init__.py +++ /dev/null @@ -1,149 +0,0 @@ -# Copyright 2012 Managed I.T. -# -# Author: Kiall Mac Innes <kiall@managedit.ie> -# -# 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 a2dfada7..00000000 --- a/designate/api/v1/domains.py +++ /dev/null @@ -1,173 +0,0 @@ -# Copyright 2012 Managed I.T. -# -# Author: Kiall Mac Innes <kiall@managedit.ie> -# -# 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/<uuid:domain_id>', 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/<uuid:domain_id>', 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/<uuid:domain_id>', 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/<uuid:domain_id>/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 e69de29b..00000000 --- a/designate/api/v1/extensions/__init__.py +++ /dev/null diff --git a/designate/api/v1/extensions/diagnostics.py b/designate/api/v1/extensions/diagnostics.py deleted file mode 100644 index ead4e0b8..00000000 --- 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 <kiall@hpe.com> -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -import flask -import oslo_messaging as messaging - -from designate import rpc - - -blueprint = flask.Blueprint('diagnostics', __name__) - - -@blueprint.route('/diagnostics/ping/<topic>/<host>', 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 2f23ff7c..00000000 --- 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 <kiall@hpe.com> -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -import 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/<tenant_id>', 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/<tenant_id>', 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/<tenant_id>', 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 8e830724..00000000 --- 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 <simon.mccartney@hpe.com> -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -import 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/<tenant_id>', 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 b90c51f7..00000000 --- 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 <kiall@hpe.com> -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -import 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/<uuid:domain_id>/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/<uuid:domain_id>/records/<uuid:record_id>/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 e81c5c57..00000000 --- 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 <kiall@hpe.com> -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -import flask - -from designate.central import rpcapi as central_rpcapi - - -central_api = central_rpcapi.CentralAPI() -blueprint = flask.Blueprint('touch', __name__) - - -@blueprint.route('/domains/<uuid:domain_id>/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 ebeb483d..00000000 --- a/designate/api/v1/limits.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2012 Managed I.T. -# -# Author: Kiall Mac Innes <kiall@managedit.ie> -# -# 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 084d70a3..00000000 --- a/designate/api/v1/records.py +++ /dev/null @@ -1,277 +0,0 @@ -# Copyright 2012 Managed I.T. -# -# Author: Kiall Mac Innes <kiall@managedit.ie> -# -# 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/<uuid:domain_id>/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/<uuid:domain_id>/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/<uuid:domain_id>/records/<uuid:record_id>', - 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/<uuid:domain_id>/records/<uuid:record_id>', - 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/<uuid:domain_id>/records/<uuid:record_id>', - 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 244e2230..00000000 --- a/designate/api/v1/servers.py +++ /dev/null @@ -1,226 +0,0 @@ -# Copyright 2012 Managed I.T. -# -# Author: Kiall Mac Innes <kiall@managedit.ie> -# -# 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/<uuid:server_id>', 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/<uuid:server_id>', 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/<uuid:server_id>', 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 dadd8d58..00000000 --- a/designate/api/v1/tsigkeys.py +++ /dev/null @@ -1,155 +0,0 @@ -# Copyright 2012 Managed I.T. -# -# Author: Kiall Mac Innes <kiall@managedit.ie> -# -# 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/<uuid:tsigkey_id>', 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/<uuid:tsigkey_id>', 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/<uuid:tsigkey_id>', 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 5a299de2..520e08f6 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) |