deb-designate/designate/api/v1/records.py
Graham Hayes c5949ccb28 Rename all references of Domain to Zone
This is a pretty invasive change :)

A non complete list of changes:

* Database Tables
* Database Columns
* Designate Objects and fields on Objects
* Designate Objects Adaptors stop doing some of the renames
* All RPCAPI versions are bumped - totally backward
  incompatable (function names have changed)

Change-Id: Ib99e918998a3909fa4aa92bf1ee0475f8a519196
2015-11-17 15:22:16 +00:00

265 lines
8.6 KiB
Python

# 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
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"}
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)
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})
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'])
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"}
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)
# 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:
central_api.delete_recordset(context, domain_id, recordset_id)
@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"}
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)
central_api.delete_record(
context, domain_id, record['recordset_id'], record_id)
_delete_recordset_if_empty(context, domain_id, record['recordset_id'])
return flask.Response(status=200)