Jump to: navigation, search

Designate/Blueprints/Recordset Record API Redesign

< Designate‎ | Blueprints
Revision as of 23:14, 19 May 2014 by Betsy (talk | contribs) (Create a Recordset (POST))

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, get, update and delete recordsets. When the user creates a recordset the code will determine if it should be a new recordset. If all data is the same except for the record, a Duplicate error will be returned and the user will then add the Record by modifying the Recordset. The record will no longer be accessible as a separate resource; only as part of the recordset. Currently, CNAME and DNAME record types cannot technically be a Recordset, because they cannot contain more than one record; however, in order to maintain consistency, we will be treating them as a 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.

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
PUT /zones/{zone id}/recordsets/{recordset id} Replaces the current Recordset with data in the request
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/"
       }
 }

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. If the name and type are the same as an existing RecordSet, the return code will be 204 Duplicate, even if the data (record) being sent is different. The user must use PUT to change the record information. It cannot be changed implicitly through a CREATE.

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.