Difference between revisions of "Designate/Blueprints/Recordset Record API Redesign"
(→A_Record) |
(→Update a RecordSet (PATCH)) |
||
Line 181: | Line 181: | ||
} | } | ||
− | ==== | + | ==== Modify a RecordSet / Add a Record(PATCH) ==== |
− | |||
'''Request''' | '''Request''' | ||
Line 189: | Line 188: | ||
"recordset" : { | "recordset" : { | ||
"ttl" : 3000 | "ttl" : 3000 | ||
− | "records" : | + | "records" : [ |
"10.1.0.5" | "10.1.0.5" | ||
− | + | ] | |
} | } | ||
} | } | ||
+ | |||
+ | |||
+ | ''''Request (JSON Patch /RFC6902):''' | ||
+ | |||
+ | { | ||
+ | "op": "add", "path": "/records", "value": "10.1.0.5" | ||
+ | } | ||
'''Response''' | '''Response''' | ||
Line 212: | Line 218: | ||
"id" : "06c3a2de-4e23-4143-98ab-6bf6d41ded12", | "id" : "06c3a2de-4e23-4143-98ab-6bf6d41ded12", | ||
"name" : "foo.example.com.", | "name" : "foo.example.com.", | ||
− | "records" : | + | "records" : [ |
"10.1.0.1", | "10.1.0.1", | ||
"10.1.0.3", | "10.1.0.3", | ||
"10.1.0.5" | "10.1.0.5" | ||
− | + | ] | |
} | } | ||
Revision as of 13:58, 13 May 2014
WIP
Overview
Gerrit Patch | [] |
---|---|
Launchpad Blueprint | [1] |
This blueprint proposes to eliminate the Records resource and only keep the RecordSets resource.
The API for recordsets and records is too complicated. Currently, a user is forced to create a recordset before creating a record. This leads to a confusing user experience. Users will create, update and delete recordsets. When the user creates a recordset the code will determine if it should be a new recordset or a record under an existing recordset. However, the record will no longer be accessible as a separate resource; only as part of the recordset.
The concept of a Resource Record Set is defined in RFC 2181, Section 5. To summarize, it says, each DNS Resource Record (RR) has four parts: label, class, type and data. Any records that have all four equal, should be rejected as duplicates. However, it is possible for most record types to exist with the same label, class and type, but with different data. Such a group of records is defined to be a Resource Record Set (RRSet). A query for a specific label, class and type, should always return all records in the associated RRSet. It further states that all RRs in a RRSet should have the same ttl.
Discussion
This blueprint was discussed in the Designate weekly meetings: IRC Meeting logs and several options were discussed: Options. Unfortunately, I was on vacation during those discussions, so I still have some questions listed in this document.
API Resource
Current API
/zones/{zone id}/recordsets/{recordset id}/records/{record id}
New API
/zones/{zone id}/recordsets/{recordset id}
API Details: Create / List / Patch / Delete Recordset
Verb | Resource | Description |
---|---|---|
GET | /zones/{zone id}/recordsets | Returns all recordsets for a zone |
GET | /zones/{zone id}/recordsets/{recordset id} | Returns a specific recordset for a zone |
POST | /zones/{zone id}/recordsets | Creates a new recordset or adds a new record to an existing recordset |
PATCH | /zones/{zone id}/recordsets/{recordset id} | Adds, Removes or Modifies the records specified in the message body to a recordset |
DELETE | /zones/{zone id}/recordsets/{recordset id} | Delete the recordset and all records associated with it. |
List Recordset(s) (GET)
When no id is specified all recordsets for the specified zone are returned. No body is provided in the request. When a recordset id is provided, only that recordset is returned. No body is provided in the request
Response
{ "recordset" : [ { "created_at" : "2014-04-29T19:34:21.819615", "version" : 1, "zone_id" : "766d7605-4c48-41fa-a9de-76692ed8051c", "links" : { "self" : "http://192.168.33.8:9001/v2/zones/766d7605-4c48-41fa-a9de-76692ed8051c/recordsets/06c3a2de-4e23-4143-98ab-6bf6d41ded26" }, "ttl" : 3600, "updated_at" : null, "description" : null, "type" : "A", "id" : "06c3a2de-4e23-4143-98ab-6bf6d41ded26", "name" : "example.com.", "records" : [ "192.0.1.2", "192.0.1.3" ], { "created_at" : "2014-04-29T22:04:41.000000", "version" : 1, "zone_id":"766d7605-4c48-41fa-a9de-76692ed8051c", "links":{ "self":"http://192.168.33.8:9001/v2/zones/766d7605-4c48-41fa-a9de-76692ed8051c/recordsets/e862ddb2-58ee-431a-a3b5-6881a5e26465" }, "ttl":null, "updated_at":null, "description":null, "type":"CNAME", "id":"e862ddb2-58ee-431a-a3b5-6881a5e26465", "name":"www.example.com.", "records": [ "example.com." ] } ], "links" : { "self" : "http://192.168.33.8:9001/v2/zones/766d7605-4c48-41fa-a9de-76692ed8051c/recordsets/" } }
Questions:
1. In the above response, if there is only one item in the data field, do we want to display it like the second RecordSet or do we want to display it like the first RecordSet, but with a set of one? 2. Not all record types can technically be recordsets. For instance, I don't believe a CNAME can be a Recordset because you can have the same name set to more than on CNAME. Are we going to treat them as a Recordset of one?
'Discussion:'
I think in both instances, there is a case for consistency and that we should always treat it as a set of records, even if it is just one.
Create a Recordset (POST)
When a new Recordset is created, the caller must supply the name, type and data, which varies depending on the type.
Major Change
In this redesign, when a RecordSet POST is sent, the code will query the database looking for an existing RecordSet for the zone that has the same name and type. If one is NOT found, then a new RecordSet is created. If one IS found, then the data from the request is added as a new record to the existing RecordSet. If the ttl differs, an error will NOT be sent. The ttl with the lower value will be kept and the other will be discarded.
'Question' 1. Should the new Record be created implicitly, as described above, or should an error be generated and the user forced to explicitly modify the existing RecordSet to create a new record?
Request
{ "recordset" : { "name" : "foo.example.com.", "type" : "A", "ttl" : 3600 "records" : [ "10.1.0.1" ] } }
Response
{ "recordset" : [ { "created_at" : "2014-05-01T19:34:21.819615", "version" : 1, "zone_id" : "766d7605-4c48-41fa-a9de-76692ed8051c", "links" : { "self" : "http://192.168.33.8:9001/v2/zones/766d7605-4c48-41fa-a9de-76692ed8051c/recordsets/06c3a2de-4e23-4143-98ab-6bf6d41ded12" }, "ttl" : 3600, "updated_at" : null, "description" : null, "type" : "A", "id" : "06c3a2de-4e23-4143-98ab-6bf6d41ded12", "name" : "foo.example.com.", "records" : [ "10.1.0.1" ] }
If another POST request is sent at a later time, with the same name and type, then it is added to the existing record.
Request
{ "recordset" : { "name" : "foo.example.com.", "type" : "A", "ttl" : 3600 "records" : [ "10.1.0.3" ] } }
Response
{ "recordset" : [ { "created_at" : "2014-05-01T19:34:21.819615", "version" : 1, "zone_id" : "766d7605-4c48-41fa-a9de-76692ed8051c", "links" : { "self" : "http://192.168.33.8:9001/v2/zones/766d7605-4c48-41fa-a9de-76692ed8051c/recordsets/06c3a2de-4e23-4143-98ab-6bf6d41ded12" }, "ttl" : 3600, "updated_at" : 2014-05-02T19:34:21.819615, "description" : null, "type" : "A", "id" : "06c3a2de-4e23-4143-98ab-6bf6d41ded12", "name" : "foo.example.com.", "records" : [ "10.1.0.1", "10.1.0.3" ] }
Modify a RecordSet / Add a Record(PATCH)
Request
{ "recordset" : { "ttl" : 3000 "records" : [ "10.1.0.5" ] } }
'Request (JSON Patch /RFC6902):
{ "op": "add", "path": "/records", "value": "10.1.0.5" }
Response
{ "recordset" : [ { "created_at" : "2014-05-01T19:34:21.819615", "version" : 1, "zone_id" : "766d7605-4c48-41fa-a9de-76692ed8051c", "links" : { "self" : "http://192.168.33.8:9001/v2/zones/766d7605-4c48-41fa-a9de-76692ed8051c/recordsets/06c3a2de-4e23-4143-98ab-6bf6d41ded12" }, "ttl" : 3000, "updated_at" : 2014-05-04T19:34:21.819615, "description" : null, "type" : "A", "id" : "06c3a2de-4e23-4143-98ab-6bf6d41ded12", "name" : "foo.example.com.", "records" : [ "10.1.0.1", "10.1.0.3", "10.1.0.5" ] }
Delete a RecordSet (DELETE)
When deleting a RecordSet, the user must supply the id in the url. All records associated with a RecordSet are, also, deleted. The request body and return body are empty. A 204 is returned.
Database Schema
There are several changes being done to the database. Even though these changes will be done by a separate blueprint, I'm describing them here so all the changes can be seen in one place. I think that will make it easier to understand them.
The RecordSet table will be divided up into a table per record type. The RecordSets table for each type will combine most of the data currently in the recordsets and records tables. The Record table associated with a type will only contain the RecordSet id and data associated with that recordset.
Questions: 1. Not every record type can be a RecordSet, should be treat them all the same anyway? 2. How does "version" get set? 3. In the current RecordSets and Records table is says that created_at can be null. Is that accurate?
A_RecordSet
Name | Data Type | Length | Nullable | Details |
---|---|---|---|---|
id | CHAR | 32 | False | Primary Key, Generated UUID |
created_at | DATETIME | - | False | UTC time of creation |
updated_at | DATETIME | - | True | UTC time of last update |
version | INTEGER | 11 | False | Designate API version |
tenant_id | VARCHAR | 36 | True | The tenant_id to which the record belongs |
domain_id | VARCHAR | 32 | False | Non-Unique Key; the domain_id to which the record belongs |
name | VARCHAR | 255 | False | The zone to which the A record belongs |
ttl | INTEGER | 11 | True | The time-to-live assigned to the record |
description | VARCHAR | 160 | True | A description of the record |
status | ENUM | 'Active', 'Pending', 'Deleted' | False | Current status of RecordSet |
hash | VARCHAR | 32 | False | Unique Key |
managed | TINYINT | 1 | True | Indicates whether it is managed or not |
managed_resource_type | VARCHAR | 50 | True | |
managed_resource_id | CHAR | 32 | True | |
managed_plugin_name | VARCHAR | 50 | True | |
managed_plugin_type | VARCHAR | 50 | True | |
managed_tenant_id | VARCHAR | 36 | True | |
managed_resource_region | VARCHAR | 100 | True | |
managed_extra | VARCHAR | 100 | True |
A_Record
Name | Data Type | Length | Nullable | Details |
---|---|---|---|---|
recordset_id | VARCHAR | 32 | False | UUID, Unique Key |
record | VARCHAR | 15 | False | iPv4 |
'Question'
1. Should it be VARCHAR 15 or INT 4 bytes?
And So On
There would be a recordset and record table for each record type. The record table would be customized for each record type's data.