diff --git a/api/approve-batchchange.html b/api/approve-batchchange.html deleted file mode 100644 index a1fa793b9..000000000 --- a/api/approve-batchchange.html +++ /dev/null @@ -1,210 +0,0 @@ -VinylDNS: Approve Batch Change

Approve Batch Change

- -

Manually approves a batch change in pending review status given the batch change ID, resulting in revalidation and -submission for backend processing. Only system administrators (ie. support or super user) can manually review a batch -change. In the event that a batch change is approved and still encounters non-fatal errors, it will remain in manual -review state until a successful approval (202 Accepted) or rejection (200 OK).

- -

Note: If manual review is disabled in the VinylDNS instance, -users trying to access this endpoint will encounter a 404 Not Found response since it will not exist.

- -

HTTP REQUEST

- -
-

POST /zones/batchrecordchanges/{id}/approve

-
- -

HTTP REQUEST PARAMS

- - - - - - - - - - - - - - - - - - - - - - - - -
nametyperequired?description
idstringyesUnique identifier assigned to each created batch change.
reviewCommentstringnoOptional approval explanation.
- -

EXAMPLE HTTP REQUEST

-
{
-    "reviewComment": "Comments are optional."
-}
-
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - - - - - -
Codedescription
202OK Batch change is approved and is returned in response body. Batch change is submitted for backend processing.
400BadRequest Batch change is not in pending approval status.
403Forbidden User is not a system administrator (ie. support or super user) or is attempting to approve a scheduled batch prior to its scheduled due date.
404NotFound Batch change does not exist.
- -

Since we re-run validations upon successful approval, the create batch error codes still hold, so it is possible to see them as well.

- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
userIdstringThe unique identifier of the user that created the batch change.
userNamestringThe username of the user that created the batch change.
commentsstringConditional: comments about the batch change, if provided.
createdTimestampdate-timeThe timestamp (UTC) when the batch change was created.
changesArray of SingleChangeArray of single changes within a batch change. A SingleChange can either be a SingleAddChange or a SingleDeleteRRSetChange.
statusBatchChangeStatusStatus of the batch change.
idstringThe unique identifier for this batch change.
ownerGroupIdstringConditional: Record ownership assignment, if provided.
approvalStatusBatchChangeApprovalStatusWhether the batch change is currently awaiting manual review. Will be ManuallyApproved status when approving.
reviewerIdstringUnique identifier for the reviewer of the batch change.
reviewerUserNamestringUser name for the reviewer of the batch change.
reviewCommentstringConditional: Comment from the reviewer of the batch change, if provided.
reviewTimestampdate-timeThe timestamp (UTC) of when the batch change was manually reviewed.
- -

EXAMPLE RESPONSE

- -
{
-    "userId": "vinyl",
-    "userName": "vinyl201",
-    "comments": "",
-    "createdTimestamp": "2019-07-25T20:08:17Z",
-    "changes": [
-        {
-            "changeType": "Add",
-            "inputName": "approve.parent.com.",
-            "type": "A",
-            "ttl": 7200,
-            "record": {
-                "address": "1.1.1.1"
-            },
-            "status": "Pending",
-            "recordName": "approve",
-            "zoneName": "parent.com.",
-            "zoneId": "876879e5-293d-4092-99ab-9cbdf50c1636",
-            "validationErrors": [],
-            "id": "a69cad97-994d-41e3-aed2-ec8c86a30ac5"
-        }
-    ],
-    "status": "PendingProcessing",
-    "id": "2343fa88-d4da-4377-986a-34ba4e8ca628",
-    "ownerGroupId": "159a41c5-e67e-4951-b539-05f5ac788139",
-    "reviewerId": "90c11ffc-5a71-4794-97c6-74d19c81af7d ",
-    "reviewComment": "Good to go!",
-    "reviewTimestamp": "2019-07-25T20:10:28Z",
-    "approvalStatus": "ManuallyApproved"
-}
-
-
\ No newline at end of file diff --git a/api/auth-mechanism.html b/api/auth-mechanism.html deleted file mode 100644 index 1480b52ac..000000000 --- a/api/auth-mechanism.html +++ /dev/null @@ -1,67 +0,0 @@ -VinylDNS: Authentication

API Authentication

- -

The API Authentication for VinylDNS is modeled after the AWS Signature Version 4 Signing process. The AWS documentation -for it can be found -here. Similar to how the AWS Signature Version -4 signing process adds authentication information to AWS requests, VinylDNS’s API Authenticator also adds authentication -information to every API request.

- -

VinylDNS API Authentication Process

- -
    -
  1. Retrieve the Authorization HTTP Header (Auth Header) from the HTTP Request Context.
  2. -
  3. Parse the retrieved Auth Header into an -AWS String to Sign structure -which should be in the form:
  4. -
- -
StringToSign =
-    Algorithm + \n +
-    RequestDateTime + \n +
-    CredentialScope + \n +
-    HashedCanonicalRequest
-
- -

String to Sign Example:

- -
AWS4-HMAC-SHA256
-20150830T123600Z
-20150830/us-east-1/iam/aws4_request
-f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59
-
- -
    -
  1. Extract the access key from the Auth Header and search for the account associated with the access key.
  2. -
  3. Validate the signature of the request.
  4. -
  5. Build the authentication information, which essentially contains all the authorized accounts for the signed in user.
  6. -
- -

Authentication Failure Response

- -

If any these validations fail, a 401 (Unauthorized) or a 403 (Forbidden) error will be thrown; otherwise unanticipated -exceptions will simply bubble out and result as 500s or 503s.

- -
    -
  1. If the Auth Header is not found, then a 401 (Unauthorized) error is returned.
  2. -
  3. If the Auth Header cannot be parsed, then a 403 (Forbidden) error is returned.
  4. -
  5. If the access key cannot be found, then a 401 (Unauthorized) error is returned.
  6. -
  7. If the request signature cannot be validated, then a 403 (Forbidden) error is returned.
  8. -
-
\ No newline at end of file diff --git a/api/batchchange-errors.html b/api/batchchange-errors.html deleted file mode 100644 index 06658d133..000000000 --- a/api/batchchange-errors.html +++ /dev/null @@ -1,571 +0,0 @@ -VinylDNS: Batch Change Errors

Batch Change Errors

- - -

SINGLE CHANGE ERRORS

-

Single change errors are errors that get collected at different validation stages and correspond to individual -change inputs. Each change can have its own list of one or more errors. Single change errors are grouped into the following stages:

- -
    -
  • Independent input validations: Validate invalid data input formats and values.
  • -
  • Record and zone discovery: Resolve record and zone from fully-qualified input name.
  • -
  • Dependent context validations: Check for sufficient user access and conflicts with existing records or other submissions within the batch.
  • -
- -

Since single change errors are collected at different stages, errors at later stages may exist but will not -appear unless errors at earlier stages are addressed. An example is that a user may initially get an error about required data -missing from the DNS request, and then after correcting the data encounter an issue about a conflicting record already existing -in the DNS backend.

- -

EXAMPLE ERROR RESPONSE BY CHANGE

- -
[
-   {
-      "changeType": "Add",
-      "inputName": "good-A.another.example.com.",
-      "type": "A",
-      "ttl": 200,
-      "record": {
-        "address": "1.2.3.4"
-      }
-   },
-   {
-      "changeType": "Add",
-      "inputName": "duplicate.example.com",
-      "type": "CNAME",
-      "ttl": 200,
-      "record": {
-         "cname": "test.example.com."
-      },
-      "errors": [
-         "Record with name \"duplicate.example.com.\" is not unique in the batch change. CNAME record cannot use duplicate name."
-      ]
-   },
-   {
-      "changeType": "Add",
-      "inputName": "duplicate.example.com",
-      "type": "A",
-      "ttl": 300,
-      "record": {
-         "address": "1.2.3.4"
-      }
-   },
-   {
-      "changeType": "Add",
-      "inputName": "bad-ttl-and-invalid-name$.sample.com.",
-      "type": "A",
-      "ttl": 29,
-      "record": {
-         "address": "1.2.3.4"
-      },
-      "errors": [
-         "Failed validation 29, TTL must be between 30 and 2147483647.",
-         "Failed validation bad-ttl-and-invalid-name$.sample.com., valid domain names are a series of one or more labels joined by dots and terminate on a dot."
-      ]
-   }
-]
-
- -

Single Change Errors

-

Single change errors can be further classified as non-fatal or fatal errors. The presence of one or more fatal -errors will result in an immediate failure (ie. hard stop) and no changes in the batch will be accepted. The behavior of non-fatal errors depends -on whether manual review is configured on: if manual review -is disabled, non-fatal errors are treated as fatal errors; if manual review is enabled, batches with only non-fatal errors will enter -a pending review state.

- -

When non-fatal errors are encountered with manual review enabled, the errors will be saved on the corresponding SingleChanges. -The SingleChanges will also have a status of NeedsReview.

- -

The following chart provides a breakdown of batch change status outcome based on a combination of manual review -configuration and error types present in the batch change:

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Manual Review Enabled?Errors in Batch?Status Outcome
YesBoth fatal and non-fatalHard stop
YesFatal onlyHard stop
YesNon-fatal onlyPendingReview
YesNoPendingProcessing (will be or is being auto-processed)
NoBoth fatal and non-fatalHard stop
NoFatal onlyHard stop
NoNon-fatal onlyFailed
NoNoPendingProcessing (will be or is being auto-processed)
- -

Note: if a user submits a batch change with allowManualReview set to false, the request will treat the request as though -the VinylDNS instance is configured to have manual review disabled.

- -
Non-Fatal Errors
- - - -
Fatal Errors
- - - -

Non-Fatal Errors

-

Zone Discovery Failed

- -
Error Message:
- -
Zone Discovery Failed: zone for "<input>" does not exist in VinylDNS. If zone exists, then it must be connected to in VinylDNS.
-
- -
Details:
- -

Given an inputName, VinylDNS will determine the record and zone name for the requested change. For most records, the record -names are the same as the zone name (apex), or split at at the first ‘.’, so the inputName ‘rname.zone.name.com’ will be split -into record name ‘rname’ and zone name ‘zone.name.com’ (or ‘rname.zone.name.com’ for both the record and zone name if it’s an apex record). -For PTR records, there is logic to determine the appropriate reverse zone from the given IP address.

- -

If this logic cannot find a matching zone in VinylDNS, you will see this error. -In that case, you need to connect to the zone in VinylDNS. -Even if the zone already exists outside of VinylDNS, it has to be added to VinylDNS to modify records. -VinylDNS also does not support dotted records for forward zones (eg. record baz.foo.bar. in zone bar.), so encountering -this error could indicate that a zone needs to be created outside of VinylDNS and then connected to within VinylDNS.

- -

Record Requires Manual Review

- -
Error Message:
- -
Record set with name <input> requires manual review.
-
- -
Details:
- -

Based on a configurable list, VinylDNS will determine if the given inputName requires manual review before it can be processed.

- -

Fatal Errors

-

Invalid Domain Name

- -
Error Message:
- -
Invalid domain name: "<input>", valid domain names must be letters, numbers, underscores, and hyphens, joined by dots, and terminate with a dot.
-
- -
Details:
- -

Fully qualified domain names, must be comprised of labels, separated by dots. -A label is a combination of letters, digits, underscores, and hyphens. -They must also be absolute, which means they end with a dot.

- -

Syntax:

- -
<domain> ::= <subdomain> | " "
-
-<subdomain> ::= <label> | <subdomain> "." <label>
-
-<label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
-
-<ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
-
-<let-dig-hyp> ::= <let-dig> | "-"
-
-<let-dig> ::= <letter> | <digit>
-
-<letter> ::= any one of the 52 alphabetic characters A through Z in
-upper case and a through z in lower case
-
-<digit> ::= any one of the ten digits 0 through 9
-
- -

More info can be found at:

- -

RFC 1035, DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION, Section 2.3.1. Preferred name syntax

- -

Invalid Length

- -
Error Message:
- -
Invalid length: "<input>", length needs to be between <minLengthInclusive> and <maxLengthInclusive> characters.
-
- -
Details:
- -

The length of the input did not fit in the range in [minLengthInclusive, maxLengthInclusive].

- -

Invalid Record Type

- -
Error Message:
- -
Invalid record type: "<input>", valid record types include <valid record types>.
-
- -
Details:
- -

The record type input must match one of the valid record types. Not all DNS record types are currently supported.

- -

Invalid IPv4 Address

- -
Error Message:
- -
Invalid IPv4 address: "<input>"
-
- -
Details:
- -

The IPv4 address input is not a valid IPv4 address. Accepted inputs must be in dotted-decimal notation, with four -groups of three decimal digits, separated by periods. Leading zeros in groups can be omitted.

- -

Range: 0.0.0.0 - 255.255.255.255

- -

Examples:

- -
    -
  • 1.1.1.1
  • -
  • 10.234.0.62
  • -
- -

Invalid IPv6 Address

- -
Error Message:
- -
Invalid IPv6 address: "<input>".
-
- -
Details:
- -

The IPv6 address input is not a valid IPv6 address. Accepted inputs must be eight groups of four hexadecimal digits, -separated by colons. Leading zeros in groups can be emitted. Consecutive groups of all zeros can be replaced by a double colon.

- -

Range: 0000:0000:0000:0000:0000:0000:0000:0000 - ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff

- -

Examples:

- -
    -
  • 2001:0db8:0000:0000:0000:ff00:0042:8329
  • -
  • 2001:0db8::ff00:0042:8329
  • -
  • 2001:db8::ff00:42:8329
  • -
- -

Invalid IP Address

- -
Error Message:
- -
Invalid IP address: "<input>".
-
- -
Details:
- -

The IP address input is not a valid IPv4 or IPv6 address.

- -

Invalid TTL

- -
Error Message:
- -
Invalid TTL: "<input>", must be a number between 30 and 2147483647.
-
- -
Details:
- -

Time-to-live must be a number in the range [30, 2147483647].

- -

Invalid Batch Record Type

- -
Error Message:
- -
Invalid Batch Record Type: "<input>", valid record types for batch changes include <valid record types>.
-
- -
Details:
- -

The DNS record type is not currently supported for batch changes.

- -

Record Already Exists

- -
Error Message:
- -
Record "<input>" Already Exists: cannot add an existing record; to update it, issue a DeleteRecordSet then an Add.
-
- -
Details:
- -

A record with the given name already exists, and cannot be duplicated for the given type.

- -

Record Does Not Exist

- -
Error Message:
- -
Record "<input>" Does Not Exist: cannot delete a record that does not exist.
-
- -
Details:
- -

A record with the given name could not be found in VinylDNS. -If the record exists in DNS, then you should sync the zone for that record to bring VinylDNS up to date with what is in the DNS backend.

- -

CNAME Conflict

- -
Error Message:
- -
CNAME conflict: CNAME record names must be unique. Existing record with name "<name>" and type "<type>" conflicts with this record.
-
- -
Details:
- -

A CNAME record with the given name already exists. CNAME records must have unique names.

- -

User Is Not Authorized

- -
Error Message:
- -
User "<user>" is not authorized.
-
- -
Details:
- -

User must either be in the admin group for the zone being changed, or have an ACL rule.

- -

Record Name Not Unique In Batch Change

- -
Error Message:
- -
Record "<name>" Name Not Unique In Batch Change: cannot have multiple "<type>" records with the same name.
-
- -
Details:
- -

Certain record types do not allow multiple records with the same name. If you get this error, it means you have -illegally input two or more records with the same name and one of these types.

- -

Invalid Record Type In Reverse Zone

- -
Error Message:
- -
Invalid Record Type In Reverse Zone: record with name "<name>" and type "<type>" is not allowed in a reverse zone.
-
- -
Details:
- -

Not all record types are allowed in a DNS reverse zone. The given type is not supported.

- -

Missing Owner Group Id

- -
Error Message:
- -
Zone "<zone name>" is a shared zone, so owner group ID must be specified for record "<record name>".
-
- -
Details:
- -

You are trying to create a new record or update an existing unowned record in a shared zone. This requires a record owner group ID in the batch change.

- -

Not a Member of Owner Group

- -
Error Message:
- -
User "<user name>" must be a member of group "<group ID>" to apply this group to batch changes.
-
- -
Details:
- -

You must be a member of the group you are assigning for record ownership in the batch change.

- -

High Value Domain

- -
Error Message:
- -
Record Name "<record name>" is configured as a High Value Domain, so it cannot be modified.
-
- -
Details:
- -

You are trying to create a record with a name that is not permitted in VinylDNS. -The list of high value domains is specific to each VinylDNS instance. -You should reach out to your VinylDNS administrators for more information.

- -

CNAME at the Zone Apex is not Allowed

- -
Error Message:
- -
CNAME cannot be the same name as zone "<zone_name>".
-
- -
Details:
- -

CNAME records cannot be @ or the same name as the zone.

- -

FULL-REQUEST ERRORS

- -

Fail-request errors cause the batch change processing to abort immediately upon encounter.

- - - -

1. INVALID BATCH CHANGE INPUT

- -
HTTP RESPONSE CODE
- - - - - - - - - - - - - - -
Codedescription
400Bad Request - There is a top-level issue with batch change, aborting batch processing.
- -

There are a series of different error messages that can be returned with this error code.

- -
EXAMPLE ERROR MESSAGES:
- -
Batch change contained no changes. Batch change must have at least one change, up to a maximum of <limit> changes.
-
-Cannot request more than <limit> changes in a single batch change request
-
- -
DETAILS:
- -

If there are issues with the batch change input data provided in the batch change request, errors will be returned and batch change validations will abort processing.

- -

BATCH CHANGE NOT FOUND

- -
HTTP RESPONSE CODE
- - - - - - - - - - - - - - -
Codedescription
404Not Found - batch change not found for specified ID in get batch change request.
- -
ERROR MESSAGE:
- -
Batch change with id <id> cannot be found
-
- -
DETAILS:
- -

The batch ID specified in the get batch change request does not exist.

- -

MALFORMED JSON ERRORS

- -
DETAILS:
- -

If there are issues with the JSON provided in a batch change request, errors will be returned (not in a single change format) and none of the batch change validations will run.

- -
EXAMPLE ERROR MESSAGES:
- -
{
-   "errors": [
-      "Missing BatchChangeInput.changes"
-   ]
-}
-
-{
-   "errors": [
-      "Missing BatchChangeInput.changes.inputName",
-      "Missing BatchChangeInput.changes.type",
-      "Missing BatchChangeInput.changes.ttl"
-   ]
-}
-
-{
-   "errors": [
-      "Invalid RecordType""
-   ]
-}
-
-
\ No newline at end of file diff --git a/api/batchchange-model.html b/api/batchchange-model.html deleted file mode 100644 index 8ab72ea94..000000000 --- a/api/batchchange-model.html +++ /dev/null @@ -1,391 +0,0 @@ -VinylDNS: Batch Change Model

Batch Change Model

- -

Table of Contents

- - - -

BATCH CHANGE INFORMATION

- -

Batch change is an alternative to submitting individual RecordSet changes and provides the following:

- -
    -
  • The ability to accept multiple changes in a single API call.
  • -
  • The ability to include records of multiple record types across multiple zones.
  • -
  • Input names are entered as fully-qualified domain names (or IP addresses for PTR records), so users don’t have to think in record/zone context.
  • -
  • All record validations are processed simultaneously. Fatal errors for any -change in the batch will result in a 400 response and none will be applied.
  • -
  • Support for manual review if enabled in your VinylDNS instance. -Batch change will remain in limbo until a system administrator (ie. support or super user) either rejects it resulting in -an immediate failure or approves it resulting in revalidation and submission for processing.
  • -
  • Support for notifications when a batch change is rejected or implemented.
  • -
- -

A batch change consists of multiple single changes which can be a combination of SingleAddChanges and SingleDeleteRRSetChanges.

- -

Note: In the portal batch change is referred to as DNS Change.

- -

To update an existing record, you must delete the record first and add the record again with the updated changes.

- -

Batch changes are also susceptible to the following restrictions:

-
    -
  • Current supported record types for batch change are: A, AAAA, CNAME, and PTR.
  • -
  • Batch change requests must contain at least one change.
  • -
  • The maximum number of single changes within a batch change depends on the instance of VinylDNS. Contact your VinylDNS administrators to find the batch change limit for your instance.
  • -
  • Access permissions will follow existing rules (admin group or ACL access). Note that an update (delete and add of the same record name, zone and record type combination) requires Write access.
  • -
- -

BATCH CHANGE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
userIdstringThe unique identifier of the user that created the batch change.
userNamestringThe username of the user that created the batch change.
commentsstringOptional comments about the batch change.
createdTimestampdate-timeThe timestamp (UTC) when the batch change was created.
changesArray of SingleChangeArray of single changes within a batch change. A SingleChange can either be a SingleAddChange or a SingleDeleteRRSetChange.
statusBatchChangeStatus- PendingProcessing - at least one change in batch has not finished processing
- Complete - all changes have been processed successfully
- Failed - all changes failed during processing
- PartialFailure - some changes have failed and the rest were successful
- PendingReview - one or more changes requires manual approval/rejection by a system administrator (ie. super or support user) to proceed
- Rejected - the batch change was rejected by a system administrator (ie. super or support user) and no changes were applied
- Scheduled - the batch change is scheduled for a later date at which time it needs to be approved to proceed.
- Cancelled - the PendingReview batch change was cancelled by its creator before review.
idstringThe unique identifier for this batch change.
ownerGroupIdstringRecord ownership assignment. Required if any records in the batch change are in shared zones and are new or unowned.
approvalStatusBatchChangeApprovalStatusWhether the batch change is currently awaiting manual review. Can be one of AutoApproved, PendingReview, ManuallyApproved, Rejected, or Cancelled.
reviewerIdstringOptional unique identifier for the reviewer of the batch change. Required if batch change was manually rejected or approved.
reviewerUserNamestringOptional user name for the reviewer of the batch change. Required if batch change was manually rejected or approved.
reviewCommentstringOptional comment for the reviewer of the batch change. Only applicable if batch change was manually rejected or approved.
reviewTimestampdate-timeOptional timestamp (UTC) of when the batch change was manually reviewed. Required if batch change was manually rejected or approved.
scheduledTimedate-timeOptional requested date and time to process the batch change.
cancelledTimestampdate-timeOptional date and time a batch change was cancelled by its creator.
- -

SINGLE CHANGE ATTRIBUTES

- -

A successful batch change response consists of a corresponding SingleAddChange or SingleDeleteRRSetChange for each batch change input. See the batch change create page for details on constructing a batch change request.

- -

SingleAddChange

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
changeTypeChangeInputTypeType of change input. Can either be an Add or DeleteRecordSet. See more details about behavior of changeType interaction.
inputNamestringThe fully-qualified domain name of the record which was provided in the create batch request.
typeRecordTypeType of DNS record, supported records for batch changes are currently: A, AAAA, CNAME, and PTR.
ttllongThe time-to-live in seconds.
recordRecordDataThe data added for this record, which varies by record type.
statusSingleChangeStatusStatus for this change. Can be one of: Pending, Complete, Failed, NeedsReview or Rejected.
recordNamestringThe name of the record. Record names for the apex will be match the zone name (including terminating dot).
zoneNamestringThe name of the zone.
zoneIdstringThe unique identifier for the zone.
systemMessagestringConditional: Returns system message relevant to corresponding batch change input.
recordChangeIdstringConditional: The unique identifier for the record change; only returned on successful batch creation.
recordSetIdstringConditional: The unique identifier for the record set; only returned on successful batch creation,
validationErrorsArray of BatchChangeErrorArray containing any validation errors associated with this SingleAddChange. Note: These will only exist on NeedsReview or Rejected SingleChanges
idstringThe unique identifier for this change.
- -

SingleDeleteRRSetChange

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
changeTypeChangeInputTypeType of change input. Can either be an Add or DeleteRecordSet. See more details about behavior of changeType interaction.
inputNamestringThe fully-qualified domain name of the record which was provided in the create batch request.
typeRecordTypeType of DNS record, supported records for batch changes are currently: A, AAAA, CNAME, and PTR.
recordRecordDataOptional. The data deleted for this record, which varies by record type. If not provided, the entire DNS recordset was deleted.
statusSingleChangeStatusStatus for this change. Can be one of: Pending, Complete, Failed, NeedsReview or Rejected.
recordNamestringThe name of the record. Record names for the apex will be match the zone name (including terminating dot).
zoneNamestringThe name of the zone.
zoneIdstringThe unique identifier for the zone.
systemMessagestringConditional: Returns system message relevant to corresponding batch change input.
recordChangeIdstringConditional: The unique identifier for the record change; only returned on successful batch creation.
recordSetIdstringConditional: The unique identifier for the record set; only returned on successful batch creation,
validationErrorsArray of BatchChangeErrorArray containing any validation errors associated with this SingleDeleteRRSetChange. Note: These will only exist on NeedsReview or Rejected SingleChanges
idstringThe unique identifier for this change.
- -

ChangeType Values

- -

There are two valid changeTypes for a SingleChange: Add and DeleteRecordSet

- -

changeTypes can be used independently or combined to achieve the desired behavior described below.

- -
    -
  • Create a new DNS record: Add with record data
  • -
  • Delete an entire record set: 1. DeleteRecordSet without specifying existing record data or 2. DeleteRecordSet for each entry of the DNS record
  • -
  • Delete a single entry from DNS record with multiple entries: DeleteRecordSet specifying existing record data
  • -
  • Update an existing record set: 1. DeleteRecordSet specifying existing record data (single entry delete) or not specifying record data (full delete) and 2. Add with record data
  • -
- -

BATCH CHANGE EXAMPLE

- -

Successful batch change response example with a SingleAddChange and a SingleDeleteRRSetChange.

- -
{
-    "userId": "vinyl", 
-    "userName": "vinyl201", 
-    "comments": "this is optional", 
-    "createdTimestamp": "2018-05-08T18:46:34Z", 
-    "ownerGroupId": "f42385e4-5675-38c0-b42f-64105e743bfe"
-    "changes": [
-        {
-            "changeType": "Add",
-            "inputName": "recordName.zoneName.", 
-            "type": "A", 
-            "ttl": 3600,  
-            "record": {
-                "address": "1.1.1.1"
-            },
-            "status": "Complete", 
-            "recordName": "recordName", 
-            "zoneName": "zoneName.", 
-            "zoneId": "8f8f649f-998e-4428-a029-b4ba5f5bd4ca",
-            "recordChangeId": "4754ac4c-5f81-11e8-9c2d-fa7ae01bbebc",
-            "recordSetId": "4754b084-5f81-11e8-9c2d-fa7ae01bbebc",
-            "validationErrors": [],
-            "id": "17350028-b2b8-428d-9f10-dbb518a0364d"
-        }, 
-        {
-            "changeType": "DeleteRecordSet",
-            "inputName": "recordName.zoneName.", 
-            "type": "AAAA", 
-            "status": "Complete", 
-            "recordName": "recordName", 
-            "zoneName": "zoneName.", 
-            "zoneId": "9cbdd3ac-9752-4d56-9ca0-6a1a14fc5562",
-            "recordChangeId": "4754b322-5f81-11e8-9c2d-fa7ae01bbebc",
-            "recordSetId": "4754b084-5f81-11e8-9c2d-fa7ae01bbebc",
-            "validationErrors": [],
-            "id": "c29d33e4-9bee-4417-a99b-6e815fdeb748"
-        },
-        {
-            "changeType": "DeleteRecordSet",
-            "inputName": "anotherRecordName.zoneName.",
-            "type": "A",
-            "record": {
-                "address": "1.1.1.1"
-            },
-            "status": "Complete",
-            "recordName": "recordName",
-            "zoneName": "zoneName.",
-            "zoneId": "9cbdd3ac-9752-4d56-9ca0-6a1a14fc5562",
-            "recordChangeId": "9c449026-cffe-4379-beb7-217b8a31aadd",
-            "recordSetId": "e68776ab-f56f-41bf-a03e-c288b9469b53",
-            "validationErrors": [],
-            "id": "e68776ab-f56f-41bf-a03e-c288b9469b53"
-        }
-    ], 
-    "status": "Complete", 
-    "id": "937191c4-b1fd-4ab5-abb4-9553a65b44ab",
-    "approvalStatus": "AutoApproved"
-}
-
-
\ No newline at end of file diff --git a/api/cancel-batchchange.html b/api/cancel-batchchange.html deleted file mode 100644 index 34a13af0d..000000000 --- a/api/cancel-batchchange.html +++ /dev/null @@ -1,80 +0,0 @@ -VinylDNS: Cancel Batch Change

Cancel Batch Change

- -

Cancels a batch change that is PendingReview. Only the user who created the batch change can cancel it.

- -

Note: If manual review is disabled in the VinylDNS instance, -users trying to access this endpoint will encounter a 404 Not Found response since it will not exist.

- -

HTTP REQUEST

- -
-

POST /zones/batchrecordchanges/{id}/cancel

-
- -

HTTP REQUEST PARAMS

- - - - - - - - - - - - - - - - - - -
nametyperequired?description
idstringyesUnique identifier assigned to each created batch change.
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - -
Codedescription
200OK - The batch change is returned in response body.
403Forbidden - The user does not have the access required to perform the action.
404Not Found - Batch change not found.
- -

HTTP RESPONSE ATTRIBUTES

- -

See Batch Change Model attributes

-
\ No newline at end of file diff --git a/api/create-batchchange.html b/api/create-batchchange.html deleted file mode 100644 index 7c1baf263..000000000 --- a/api/create-batchchange.html +++ /dev/null @@ -1,334 +0,0 @@ -VinylDNS: Create Batch Change

Create Batch Change

- -

Creates a batch change with SingleAddChanges and/or SingleDeleteRRSetChanges across different zones. A delete and add of the same record will be treated as an update on that record set. Regardless of the input order in the batch change, all deletes for the same recordset will be logically applied before the adds.

- -

Current supported record types for creating a batch change are: A, AAAA, CNAME, MX, PTR, TXT. A batch must contain at least one change and no more than 20 changes. -Supported record types for records in shared zones may vary. Contact your VinylDNS administrators to find the allowed record types. -This does not apply to zone administrators or users with specific ACL access rules.

- -

HTTP REQUEST

- -
-

POST /zones/batchrecordchanges?allowManualReview={true | false}

-
- -

Note that the batch change request inputs are a subset of the full batch change model.

- -

HTTP REQUEST PARAMS

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametyperequired?description
commentsstringnoOptional comments about the batch change.
changesArray of ChangeInputyesSet of ChangeInputs in the batch change. A ChangeInput is an AddChangeInput or DeleteChangeInput. Type is inferred from specified changeType.
ownerGroupIdstringsometimesRecord ownership assignment. Required if any records in the batch change are in shared zones and are new or unowned.
scheduledTimedate-timenoOptional datetime. Stored as UTC. Batch change will not be processed until after the scheduled time. Required format is an ISO 8601 date time string.
allowManualReviewbooleannoOptional override to control whether manual review is enabled for the batch change request. Default value is true. Must be passed in as a query parameter, not in the request body.
- -
AddChangeInput
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametyperequired?description
changeTypeChangeInputTypeyesType of change input. Must be set to Add for AddChangeInput.
inputNamestringyesThe fully qualified domain name of the record being added. For PTR, the input name is a valid IPv4 or IPv6 address.
typeRecordTypeyesType of DNS record. Supported records for batch changes are currently: A, AAAA, CNAME, and PTR.
ttllongnoThe time-to-live in seconds. The minimum and maximum values are 30 and 2147483647, respectively. If excluded, this will be set to the system default for new adds, or the existing TTL for updates
recordRecordDatayesThe data for the record.
- -
DeleteChangeInput
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametyperequired?description
changeTypeChangeInputTypeyesType of change input. Must be DeleteRecordSet for DeleteChangeInput.
inputNamestringyesThe fully qualified domain name of the record being deleted.
typeRecordTypeyesType of DNS record. Supported records for batch changes are currently: A, AAAA, CNAME, and PTR.
recordRecordDatanoThe data for the record. If specified, only this DNS entry for the existing DNS recordset will be deleted; if unspecified, the entire DNS recordset will be deleted.
- -

EXAMPLE HTTP REQUEST

-
{
-    "comments": "this is optional",
-    "ownerGroupId": "f42385e4-5675-38c0-b42f-64105e743bfe",
-    "changes": [
-        {
-            "inputName": "example.com.",
-            "changeType": "Add",
-            "type": "A",  
-            "ttl": 3600, 
-            "record": {
-                "address": "1.1.1.1"
-            } 
-        }, 
-        {
-            "inputName": "192.0.2.195",
-            "changeType": "Add",
-            "type": "PTR", 
-            "ttl": 3600,
-            "record": {
-                "ptrdname": "ptrdata.data."
-            }
-        }, 
-        {
-            "inputName": "cname.example.com.",
-            "changeType": "DeleteRecordSet",
-            "type": "CNAME"
-        }, 
-        {
-            "inputName": "update.another.example.com.",
-            "changeType": "DeleteRecordSet",
-            "type": "AAAA",
-            "record": {
-              "address": "2:3:4:5:6:7:8:9" 
-            }
-        }, 
-        {
-            "inputName": "update.another.example.com.",
-            "changeType": "Add",
-            "type": "AAAA", 
-            "ttl": 4000,
-            "record": {
-                "address": "1:2:3:4:5:6:7:8"
-            }
-        }
-    ]
-}
-
- -

The first two items in the changes list are SingleAddChanges of an A record and a PTR record. Note that for the PTR record, the inputName is a valid IP address. The third item is a delete of a CNAME record. The last two items represent an update (delete & add) of an AAAA record with the fully qualified domain name “update.another.example.com.”.

- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Codedescription
202Accepted - The batch change is validated and is returned in the response body. Based on status, the batch will either be sent for immediate backend processing (PendingProcessing) or pending manual review (PendingReview).
400Bad Request - Error in the batch change. See Batch Change Errors page.
403Forbidden - The user does not have the access required to perform the action.
413Request Entity Too Large - Cannot request more than changes in a single batch change request.
422Unprocessable Entity - the batch does not contain any changes, thus cannot be processed.
- -

A batch change goes through numerous validations before it is processed. This results in corresponding BadRequest or error responses. View the full list of batch change errors here.

- -

HTTP RESPONSE ATTRIBUTES

- -

On success, the response from create batch change includes the fields the user input, as well as some additional information provided by the system. This response is the same as that of get batch change.

- -

EXAMPLE RESPONSE

- -
{
-    "userId": "vinyl", 
-    "userName": "vinyl201", 
-    "comments": "this is optional", 
-    "createdTimestamp": "2018-05-09T14:19:34Z",
-    "ownerGroupId": "f42385e4-5675-38c0-b42f-64105e743bfe" 
-    "changes": [
-        {
-            "changeType": "Add",
-            "inputName": "example.com.", 
-            "type": "A", 
-            "ttl": 3600, 
-            "record": {
-                "address": "1.1.1.1"
-            }, 
-            "status": "Pending", 
-            "recordName": "example.com.", 
-            "zoneName": "example.com.", 
-            "zoneId": "74e93bfc-7296-4b86-83d3-1ffcb0eb3d13",
-            "validationErrors": [],
-            "id": "7573ca11-3e30-45a8-9ba5-791f7d6ae7a7"
-        }, 
-        {
-            "changeType": "Add",
-            "inputName": "192.0.2.195", 
-            "type": "PTR", 
-            "ttl": 3600, 
-            "record": {
-                "ptrdname": "ptrdata.data."
-            }, 
-            "status": "Pending", 
-            "recordName": "195", 
-            "zoneName": "2.0.192.in-addr.arpa.", 
-            "zoneId": "7fd52634-5a0c-11e8-9c2d-fa7ae01bbebc",
-            "validationErrors": [],
-            "id": "bece5338-5a0c-11e8-9c2d-fa7ae01bbebc"
-        }, 
-        {
-            "changeType": "DeleteRecordSet", 
-            "inputName": "cname.example.com.", 
-            "type": "CNAME", 
-            "status": "Pending",
-            "recordName": "cname", 
-            "zoneName": "example.com.", 
-            "zoneId": "74e93bfc-7296-4b86-83d3-1ffcb0eb3d13",
-            "validationErrors": [],
-            "id": "02048500-5a0d-11e8-a10f-fa7ae01bbebc" 
-        }, 
-        {
-            "changeType": "DeleteRecordSet",
-            "inputName": "update.example.com.", 
-            "type": "AAAA", 
-            "status": "Pending",
-            "recordName": "update", 
-            "zoneName": "example.com.", 
-            "zoneId": "74e93bfc-7296-4b86-83d3-1ffcb0eb3d13",
-            "validationErrors": [],
-            "id": "1cee1c78-5a0d-11e8-9c2d-fa7ae01bbebc" 
-        }, 
-        {
-            "changeType": "Add",
-            "inputName": "update.another.example.com.", 
-            "type": "AAAA", 
-            "ttl": 3600, 
-            "record": {
-                "address": "1:2:3:4:5:6:7:8"
-            }, 
-            "status": "Pending", 
-            "recordName": "update", 
-            "zoneName": "another.example.com.", 
-            "zoneId": "7fd52634-5a0c-11e8-9c2d-fa7ae01bbebc",
-            "validationErrors": [],
-            "id": "43dd1226-5a0d-11e8-9c2d-fa7ae01bbebc"
-        }
-    ], 
-    "status": "PendingProcessing", 
-    "id": "02bd95f4-a32c-443b-82eb-54dbaa55b31a"
-}
-
-
\ No newline at end of file diff --git a/api/create-group.html b/api/create-group.html deleted file mode 100644 index 514fbf1b1..000000000 --- a/api/create-group.html +++ /dev/null @@ -1,200 +0,0 @@ -VinylDNS: Create Group

Create Group

- -

Creates a Group in VinylDNS

- -

HTTP REQUEST

- -
-

POST /groups

-
- -

HTTP REQUEST PARAMS

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametyperequired?description
namestringyesThe name of the group. Should be one word, use hyphens if needed but no spaces
emailstringyesThe email distribution list for the group
descriptionstringnoA short description of the group if more info is needed other than the name
membersArray of User id objectsyesSet of User ids in the group
adminsArray of User id objectsyesSet of User ids that are admins of the group. All admin user ids should also be in the members array
- -

EXAMPLE HTTP REQUEST

- -
{
-  "name": "some-group",
-  "email": "test@example.com",
-  "description": "an example group", 
-  "members": [
-    {
-      "id": "2764183c-5e75-4ae6-8833-503cd5f4dcb0"
-    }
-  ],
-  "admins": [
-    {
-      "id": "2764183c-5e75-4ae6-8833-503cd5f4dcb0"
-    }
-  ]
-}
-
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Codedescription
200OK - The group has been created and the group info is returned in the response body
400Bad Request - The group was invalid
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
404Not Found - A user id was not found
409Conflict - A group with the same name already exists
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
idstringUnique UUID of the group
namestringThe name of the group
emailstringThe email distribution list of the group
descriptionstringThe group description, the group will not have this attribute if it was not included in the create request
createdstringThe timestamp (UTC) the group was created
statusstringActive or Deleted, in this case Active
membersArray of User ID objectsIDs of members of the group including admins
adminsArray of User ID objectsIDs of admins of the group
- -

EXAMPLE RESPONSE

- -
{
-  "id": "6f8afcda-7529-4cad-9f2d-76903f4b1aca",
-  "name": "some-group",
-  "email": "test@example.com",
-  "description": "an example group",
-  "created": "2017-03-02T15:29:21Z",
-  "status": "Active",
-  "members": [
-    {
-      "id": "2764183c-5e75-4ae6-8833-503cd5f4dcb0"
-    }
-  ],
-  "admins": [
-    {
-      "id": "2764183c-5e75-4ae6-8833-503cd5f4dcb0"
-    }
-  ]
-}
-
-
\ No newline at end of file diff --git a/api/create-recordset.html b/api/create-recordset.html deleted file mode 100644 index bfb3259da..000000000 --- a/api/create-recordset.html +++ /dev/null @@ -1,232 +0,0 @@ -VinylDNS: Create RecordSet

Create RecordSet

- -

Creates a RecordSet in a specified zone

- -

HTTP REQUEST

- -
-

POST /zones/{zoneId}/recordsets

-
- -

HTTP REQUEST PARAMS

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametyperequired?description
zoneIdstringyesid of the zone where the recordset belongs
namestringyesthe name of the recordset being updated
typestringyesthe type of recordset
ttlintegeryesthe TTL in seconds
recordsarray of record datayesrecord data for recordset, see RecordSet Model
ownerGroupIdstringnoRecord ownership assignment, applicable if the recordset is in a shared zone
- -

EXAMPLE HTTP REQUEST

-
{
-  "name": "foo",
-  "type": "A",
-  "ttl": 300,
-  "records": [
-    {
-      "address": "10.10.10.10"
-    }
-  ],
-  "zoneId": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-  "ownerGroupId": "f42385e4-5675-38c0-b42f-64105e743bfe"
-}
-
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Codedescription
202Accepted - The record set is valid and has been accepted for processing; the record set change resource is returned
400Bad Request - The zone specified is not Active; typically because the zone has no connection information
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
403Forbidden - The user does not have the access required to perform the action
404Not Found - the zone with the id specified was not found
409Conflict - A record set with the same name and type already exists in the zone
422Unprocessable Entity
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
zonemapContains information about the zone when the change was created
recordSetmapContains the recordset model
userIdstringThe user id that initiated the change
changeTypestringType of change requested (Create, Update, Delete); in this case Create
createdstringThe timestamp (UTC) the change was initiated
idstringThe ID of the change. This is not the ID of the recordset
statusRecordSetChangeStatusThe status of the change (Pending, Complete, or Failed)
singleBatchChangeIdsarray of SingleBatchChange Id objectsIf the recordset change was part of a batch change, the IDs of the single changes that comprise the recordset change
- -

EXAMPLE RESPONSE

- -
{
-  "zone": {
-    "name": "vinyl.",
-    "email": "test@test.com",
-    "status": "Active",
-    "created": "2017-02-23T14:52:44Z",
-    "id": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-    "account": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae",
-    "shared": false,
-    "acl": {
-      "rules": [
-
-      ]
-    },
-    "adminGroupId": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae"
-  },
-  "recordSet": {
-    "type": "A",
-    "zoneId": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-    "name": "foo",
-    "ttl": 300,
-    "status": "Pending",
-    "created": "2017-02-23T14:58:54Z",
-    "records": [
-      {
-        "address": "10.10.10.10"
-      }
-    ],
-    "id": "9a41b99c-8e67-445f-bcf3-f9c7cd1f2357",
-    "account": "0215d410-9b7e-4636-89fd-b6b948a06347",
-    "ownerGroupId": "f42385e4-5675-38c0-b42f-64105e743bfe",
-    "ownerGroupName": "Shared Group"
-  },
-  "userId": "0215d410-9b7e-4636-89fd-b6b948a06347",
-  "changeType": "Create",
-  "status": "Pending",
-  "created": "2017-02-23T14:58:54Z",
-  "id": "fef81f0b-f439-462d-88df-c773d3686c9b",
-  "singleBatchChangeIds": []
-}
-
-
\ No newline at end of file diff --git a/api/create-zone.html b/api/create-zone.html deleted file mode 100644 index b36323857..000000000 --- a/api/create-zone.html +++ /dev/null @@ -1,149 +0,0 @@ -VinylDNS: Create Zone

Create Zone

- -

Connects user to an existing zone. User must be a member of the group that has access to the zone. Connection info is optional, -if no info is provided the default VinylDNS connections will be used

- -

HTTP REQUEST

- -
-

POST /zones

-
- -

HTTP REQUEST PARAMS

- - - - - - - -
zone fields - adminGroupId, name, and email are required - refer to zone model
- -

EXAMPLE HTTP REQUEST

-
{
-  "adminGroupId": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae",
-  "name": "dummy.",
-  "email": "test@example.com"
-}
-
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Codedescription
202Accepted - The zone change is queued and is returned in the response body
400Bad Request - Connection failed, or group did not have access to the zone
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
403Forbidden - the user does not have the access required to perform the action
409Conflict - Zone already connected to
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
statusstringStatus of zone change
zonemapRefer to zone model
createdstringThe timestamp (UTC) the change was initiated
changeTypestringType of change requested (Create, Update, Sync, Delete); in this case Create
userIdstringThe user id that initiated the change
idstringThe ID of the change. This is not the ID of the zone
- -

EXAMPLE RESPONSE

- -
{
-  "status": "Pending",
-  "zone": {
-    "status": "Pending",
-    "account": "test_group",
-    "name": "488e6063-7832-40f6-87d3-87dae50c690a.",
-    "created": "2016-12-28T18:00:32Z",
-    "adminGroupId": "test-group-id",
-    "email": "test@test.com",
-    "shared": false,
-    "acl": {
-      "rules": [
-
-      ]
-    },
-    "id": "8ba20b72-cfdb-49d3-9216-9100aeaee7fc"
-  },
-  "created": "2016-12-28T18:00:32Z",
-  "changeType": "Create",
-  "userId": "vinyl",
-  "id": "dd449c27-bed5-4cd5-95e6-4c54fb20d930"
-}
-
-
\ No newline at end of file diff --git a/api/delete-group.html b/api/delete-group.html deleted file mode 100644 index 275676fde..000000000 --- a/api/delete-group.html +++ /dev/null @@ -1,138 +0,0 @@ -VinylDNS: Delete Group

Delete Group

- -

Deletes a Group in VinylDNS

- -

HTTP REQUEST

- -
-

DELETE /groups/{groupId}

-
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Codedescription
200OK - The group has been delete and the group info is returned in the response body
400Bad Request - The group could not be deleted
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
403Forbidden - The user does not have the access required to perform the action
404Not Found - The group was not found
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
idstringUnique UUID of the group
namemapThe name of the group
emailstringThe email distribution list of the group
descriptionstringThe group description, the group will not have this attribute if it was not set
createdstringThe timestamp (UTC) the group was created
statusstringActive or Deleted, in this case Deleted
membersArray of User ID objectsIDs of members of the group including admins
adminsArray of User ID objectsIDs of admins of the group
- -

EXAMPLE RESPONSE

- -
{
-  "id": "6f8afcda-7529-4cad-9f2d-76903f4b1aca",
-  "name": "some-group",
-  "email": "test@example.com",
-  "created": "2017-03-02T15:29:21Z",
-  "status": "Deleted",
-  "members": [
-    {
-      "id": "2764183c-5e75-4ae6-8833-503cd5f4dcb0"
-    },
-    {
-      "id": "c8630ebc-0af2-4c9a-a0a0-d18c590ed03e"
-    }
-  ],
-  "admins": [
-    {
-      "id": "2764183c-5e75-4ae6-8833-503cd5f4dcb0"
-    }
-  ]
-}
-
-
\ No newline at end of file diff --git a/api/delete-recordset.html b/api/delete-recordset.html deleted file mode 100644 index bd075686a..000000000 --- a/api/delete-recordset.html +++ /dev/null @@ -1,165 +0,0 @@ -VinylDNS: Delete RecordSet

Delete RecordSet

- -

Delete a RecordSet in a specified zone

- -

HTTP REQUEST

- -
-

DELETE /zones/{zoneId}/recordsets/{recordSetId}

-
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Codedescription
202Accepted - the delete is valid and has been accepted for processing; the record set change resource is returned in the response body
400Bad Request - the zone being updated is not active; typically because the connection information does not exist for the zone
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
403Forbidden - The user does not have the access required to perform the action
404Not Found - Zone or RecordSet not found
409Conflict - There is an existing pending change against this zone
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
zonemapContains information about the zone when the change was created
recordSetmapContains the recordset model
userIdstringThe user ID that initiated the change
changeTypestringType of change requested (Create, Update, Delete); in this case Delete
createdstringThe timestamp (UTC) the change was initiated
idstringThe ID of the change. This is not the ID of the recordset
- -

EXAMPLE RESPONSE

- -
{
-  "zone": {
-    "name": "vinyl.",
-    "email": "test@test.com",
-    "status": "Active",
-    "created": "2017-02-23T14:52:44Z",
-    "updated": "2017-02-23T15:12:33Z",
-    "id": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-    "account": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae",
-    "shared": false,
-    "acl": {
-      "rules": []
-    },
-    "adminGroupId": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae",
-    "latestSync": "2017-02-23T15:12:33Z"
-  },
-  "recordSet": {
-    "type": "A",
-    "zoneId": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-    "name": "foo",
-    "ttl": 38400,
-    "status": "PendingDelete",
-    "created": "2017-02-23T15:12:33Z",
-    "updated": "2017-02-23T15:18:27Z",
-    "records": [
-      {
-        "address": "2.2.2.2"
-      }
-    ],
-    "id": "da57c384-d6e8-4166-986d-2ca9d483f760",
-    "account": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae"
-  },
-  "userId": "0215d410-9b7e-4636-89fd-b6b948a06347",
-  "changeType": "Delete",
-  "status": "Pending",
-  "created": "2017-02-23T15:18:27Z",
-  "updates": {
-    "type": "A",
-    "zoneId": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-    "name": "foo",
-    "ttl": 38400,
-    "status": "Active",
-    "created": "2017-02-23T15:12:33Z",
-    "records": [
-      {
-        "address": "2.2.2.2"
-      }
-    ],
-    "id": "da57c384-d6e8-4166-986d-2ca9d483f760",
-    "account": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae"
-  },
-  "id": "c46cf622-285f-4f1b-b5b2-993a5a51ea5b"
-}
-
-
\ No newline at end of file diff --git a/api/delete-zone.html b/api/delete-zone.html deleted file mode 100644 index cf2be8b26..000000000 --- a/api/delete-zone.html +++ /dev/null @@ -1,137 +0,0 @@ -VinylDNS: Delete Zone

Delete Zone

- -

Abandons an existing zone that has already been connected to. -The zone will be disconnected from VinylDNS, but the RecordSets still exist in the backend DNS zone. -To delete the RecordSets see Delete RecordSet

- -

Note: We do not recommend that you abandon zones, as your zone history will be lost after the Delete. This endpoint is provided in certain situations where a zone was incorrectly started.

- -

HTTP REQUEST

- -
-

DELETE /zones/{zoneId}

-
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Codedescription
202Accepted - The change has been queued and is returned in the response body
400Bad Request - Zone was not empty and contains records
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
403Forbidden - The user does not have the access required to perform the action
404Not Found - Zone not found
409Conflict - Zone is unavailable
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
zonemapZone being deleted
userIdstringThe user id that initiated the change
changeTypestringType of change requested (Create, Update, Sync, Delete); in this case Delete
createdstringThe timestamp (UTC) the change was initiated
idstringThe ID of the change. This is not the ID of the zone
statusstringThe status of the zone change
- -

EXAMPLE RESPONSE

- -
{
-  "status": "Pending",
-  "zone": {
-    "status": "Deleted",
-    "updated": "2016-12-28T18:45:53Z",
-    "name": "443ad9ff-8f38-4540-b53f-e23a35fdfc28.",
-    "adminGroupId": "test-group-id",
-    "created": "2016-12-28T18:45:53Z",
-    "account": "test_group",
-    "email": "test@test.com",
-    "shared": false,
-    "acl": {
-      "rules": []
-    },
-    "id": "4995e883-f314-4c5f-8ee8-75003ca08ab0"
-  },
-  "created": "2016-12-28T18:45:53Z",
-  "changeType": "Delete",
-  "userId": "vinyl",
-  "id": "89c463e3-1615-42f7-8299-a0ca7ccea439"
-}
-
-
\ No newline at end of file diff --git a/api/get-batchchange.html b/api/get-batchchange.html deleted file mode 100644 index 3f7b086ad..000000000 --- a/api/get-batchchange.html +++ /dev/null @@ -1,194 +0,0 @@ -VinylDNS: Get Batch Change

Get Batch Change

- -

Retrieves a batch change given the batch change ID. Only the user who created a batch change and VinylDNS administrators will have access to get it.

- -

HTTP REQUEST

- -
-

GET /zones/batchrecordchanges/{id}

-
- -

HTTP REQUEST PARAMS

- - - - - - - - - - - - - - - - - - -
nametyperequired?description
idstringyesUnique identifier assigned to each created batch change.
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - -
Codedescription
200OK - The batch change is returned in response body.
403Forbidden - The user does not have the access required to perform the action.
404Not Found - Batch change not found.
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
userIdstringThe unique identifier of the user that created the batch change.
userNamestringThe username of the user that created the batch change.
commentsstringOptional comments about the batch change.
createdTimestampdate-timeThe timestamp (UTC) when the batch change was created.
changesArray of SingleChangeArray of single changes within a batch change. A SingleChange can either be a SingleAddChange or a SingleDeleteRRSetChange.
statusBatchChangeStatusStatus of the batch change.
idstringThe unique identifier for this batch change.
scheduledTimedate-timeOptional requested date and time to process the batch change.
approvalStatusBatchChangeApprovalStatusApproval status of the batch change.
reviewerIdstringOptional identifier of reviewer if batch change required manual review
reviewCommentstringOptional comment by reviewer if batch change required manual review
reviewTimestampdate-timeOptional timestamp (UTC) when the batch change was reviewed if manual review was required.
cancelledTimestampdate-timeOptional timestamp (UTC) if the batch change was cancelled by the creator
- -

EXAMPLE RESPONSE

- -
{
-    "userId": "vinyl", 
-    "userName": "vinyl201", 
-    "comments": "this is optional", 
-    "createdTimestamp": "2018-05-09T14:19:34Z", 
-    "changes": [
-        {
-            "changeType": "Add", 
-            "inputName": "parent.com.", 
-            "type": "A", 
-            "ttl": 200, 
-            "record": {
-                "address": "4.5.6.7"
-            }, 
-            "status": "Pending", 
-            "recordName": "parent.com.", 
-            "zoneName": "parent.com.", 
-            "zoneId": "74e93bfc-7296-4b86-83d3-1ffcb0eb3d13",
-            "recordChangeId": "a07299ce-5f81-11e8-9c2d-fa7ae01bbebc",
-            "recordSetId": "a0729f00-5f81-11e8-9c2d-fa7ae01bbebc",
-            "id": "7573ca11-3e30-45a8-9ba5-791f7d6ae7a7"
-        },
-        {
-            "changeType": "DeleteRecordSet", 
-            "inputName": "deleting.parent.com.", 
-            "type": "CNAME", 
-            "status": "Pending", 
-            "recordName": "deleting", 
-            "zoneName": "parent.com.", 
-            "zoneId": "74e93bfc-7296-4b86-83d3-1ffcb0eb3d13",
-            "recordChangeId": "bed15986-5f82-11e8-9c2d-fa7ae01bbebc",
-            "recordSetId": "c089e52c-5f82-11e8-9c2d-fa7ae01bbebc",
-            "id": "7573ca11-3e30-45a8-9ba5-791f7d6ae7a7"
-        }
-    ], 
-    "status": "PendingProcessing",
-    "id": "02bd95f4-a32c-443b-82eb-54dbaa55b31a"
-}
-
-
\ No newline at end of file diff --git a/api/get-group.html b/api/get-group.html deleted file mode 100644 index 8c01cd4b1..000000000 --- a/api/get-group.html +++ /dev/null @@ -1,130 +0,0 @@ -VinylDNS: Get Group

Get Group

- -

Gets a group that you are a part of

- -

HTTP REQUEST

- -
-

GET /groups/{groupId}

-
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - -
Codedescription
200OK - The group is returned in the response body
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
404Not Found - The group was not found
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
idstringUnique UUID of the group
namemapThe name of the group
emailstringThe email distribution list of the group
descriptionstringThe group description, the group may not have this field if it was not set
createdstringThe timestamp (UTC) the group was created
statusstringActive or Deleted
membersArray of User Id objectsIds of members of the group including admins
adminsArray of User Id objectsIds of admins of the group
- -

EXAMPLE RESPONSE

- -
{
-  "id": "6f8afcda-7529-4cad-9f2d-76903f4b1aca",
-  "name": "some-group",
-  "email": "test@example.com",
-  "created": "2017-03-02T15:29:21Z",
-  "status": "Active",
-  "members": [
-    {
-      "id": "2764183c-5e75-4ae6-8833-503cd5f4dcb0"
-    },
-    {
-      "id": "c8630ebc-0af2-4c9a-a0a0-d18c590ed03e"
-    }
-  ],
-  "admins": [
-    {
-      "id": "2764183c-5e75-4ae6-8833-503cd5f4dcb0"
-    }
-  ]
-}
-
-
\ No newline at end of file diff --git a/api/get-recordset-change.html b/api/get-recordset-change.html deleted file mode 100644 index b820aca88..000000000 --- a/api/get-recordset-change.html +++ /dev/null @@ -1,153 +0,0 @@ -VinylDNS: Get RecordSet Change

Get RecordSet Change

- -

RecordSet changes (Create, Update, Delete) are not immediately applied to the DNS backend; they are queued up for processing. Most changes are applied within a few seconds. -When you submit a change for processing, the response is a Change model. You can use the information in that change model in order to poll for the status of the change until it completes (status = Complete) or fails (status = Failed)

- -

HTTP REQUEST

- -
-

GET /zones/{zoneId}/recordsets/{recordSetId}/changes/{recordChangeId}

-
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - - - - - -
Codedescription
200OK - The record set change is returned in the response body
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
403Forbidden - The user does not have the access required to perform the action
404Not Found - The zone, record set, or change was not found
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
zonemapContains information about the zone when the change was created
recordSetmapContains the recordset model
userIdstringThe user ID that initiated the change
changeTypestringType of change requested (Create, Update, or Delete)
createdstringThe timestamp (UTC) the change was initiated
idstringThe ID of the change. This is not the ID of the recordset
statusRecordSetChangeStatusThe status of the change (Pending, Complete, or Failed)
singleBatchChangeIdsarray of SingleBatchChange ID objectsIf the recordset change was part of a batch change, the IDs of the single changes that comprise the recordset change
- -

EXAMPLE RESPONSE

- -
{
-  "zone": {
-    "name": "vinyl.",
-    "email": "test@test.com",
-    "status": "Active",
-    "created": "2017-02-23T14:52:44Z",
-    "id": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-    "account": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae",
-    "shared": false,
-    "acl": {
-      "rules": [
-
-      ]
-    },
-    "adminGroupId": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae"
-  },
-  "recordSet": {
-    "type": "A",
-    "zoneId": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-    "name": "foo",
-    "ttl": 300,
-    "status": "Pending",
-    "created": "2017-02-23T14:58:54Z",
-    "records": [
-      {
-        "address": "10.10.10.10"
-      }
-    ],
-    "id": "9a41b99c-8e67-445f-bcf3-f9c7cd1f2357",
-    "account": "0215d410-9b7e-4636-89fd-b6b948a06347"
-  },
-  "userId": "0215d410-9b7e-4636-89fd-b6b948a06347",
-  "changeType": "Create",
-  "status": "Pending",
-  "created": "2017-02-23T14:58:54Z",
-  "id": "fef81f0b-f439-462d-88df-c773d3686c9b",
-  "singleBatchChangeIds": []
-}
-
-
\ No newline at end of file diff --git a/api/get-recordset.html b/api/get-recordset.html deleted file mode 100644 index e0688386e..000000000 --- a/api/get-recordset.html +++ /dev/null @@ -1,159 +0,0 @@ -VinylDNS: Get RecordSet

Get RecordSet

- -

Gets a RecordSet in a specified zone

- -

HTTP REQUEST

- -
-

GET /zones/{zoneId}/recordsets/{recordSetId}

-
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - - - - - -
Codedescription
200OK - The record set is returned
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
403Forbidden - The user does not have the access required to perform the action
404Not Found - The zone with the id specified was not found, or the record set with id was not found
- -

HTTP RESPONSE ATTRIBUTES

-

The returned json object has all the fields from the RecordSet as well as an added accessLevel field

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
typestringType of record set
zoneIdstringThe zone the record is stored in
namestringThe name of the record set
ttlintegerThe TTL of the record set in seconds
statusstringThe status of the record set
createdstringThe timestamp (UTC) the change was initiated
updatedstringThe timestamp (UTC) the change was last updated
recordsarray of record dataArray of record data objects
idstringThe unique ID of the record set
accountstringDEPRECATED the ID of the account that created the record set
accessLevelstringaccessLevel that user has to record set based off acl rules and whether or not user is in Zone Admin Group
ownerGroupIdstringRecord ownership assignment, if found, applicable if the recordset is in a shared zone
ownerGroupNamestringName of assigned owner group, if found
- -

EXAMPLE RESPONSE

- -
{
-  "type": "A",
-  "zoneId": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-  "name": "already-exists",
-  "ttl": 38400,
-  "status": "Active",
-  "created": "2017-02-23T15:12:41Z",
-  "updated": "2017-02-23T15:12:41Z",
-  "records": [
-    {
-      "address": "6.6.6.1"
-    }
-  ],
-  "id": "dd9c1120-0594-4e61-982e-8ddcbc8b2d21",
-  "account": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae",
-  "accessLevel": "Delete",
-  "ownerGroupId": "f42385e4-5675-38c0-b42f-64105e743bfe",
-  "ownerGroupName": "Shared Group"
-}
-
-
\ No newline at end of file diff --git a/api/get-zone-by-id.html b/api/get-zone-by-id.html deleted file mode 100644 index 10b96cad9..000000000 --- a/api/get-zone-by-id.html +++ /dev/null @@ -1,107 +0,0 @@ -VinylDNS: Get Zone by ID

Get Zone by ID

- -

Retrieves a zone with the matching zone ID

- -

HTTP REQUEST

- -
-

GET /zones/{zoneId}

-
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - - - - - -
Codedescription
200OK - Successful lookup, the zone is returned in the response body
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
403Forbidden - The user does not have the access required to perform the action
404Not Found - Zone not found
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - -
nametypedescription
zonemaprefer to zone model
- -

EXAMPLE RESPONSE

- -
{
-  "zone": {
-    "status": "Active",
-    "account": "6baa85ad-267f-44ff-b535-818b7d7a2467",
-    "name": "system-test.",
-    "created": "2016-12-28T18:12:09Z",
-    "adminGroupId": "6baa85ad-267f-44ff-b535-818b7d7a2467",
-    "email": "test@example.com",
-    "connection": {
-      "primaryServer": "127.0.0.1:5301",
-      "keyName": "vinyl.",
-      "name": "system-test.",
-      "key": "OBF:1:B2cetOaRf1YAABAAek/w22XyKAleCRjA/hZO9fkNtNufPIRWTYHXviAk9GjrfcFOG9nNuB=="
-    },
-    "transferConnection": {
-      "primaryServer": "127.0.0.1:5301",
-      "keyName": "vinyl.",
-      "name": "system-test.",
-      "key": "OBF:1:PNt2k1nYkC0AABAAePpNMrDp+4C4GDbicWWlAqB5c4mKoKhvfpiWY1PfuRCVzSAeXydztB=="
-    },
-    "shared": true,
-    "acl": {
-      "rules": []
-    },
-    "id": "0f2fcece-b4ee-4982-b671-e5946f7db81d",
-    "latestSync": "2016-12-16T15:27:26Z"
-  }
-}
-
-
\ No newline at end of file diff --git a/api/get-zone-by-name.html b/api/get-zone-by-name.html deleted file mode 100644 index 1ccec5fb3..000000000 --- a/api/get-zone-by-name.html +++ /dev/null @@ -1,107 +0,0 @@ -VinylDNS: Get Zone by Name

Get Zone by Name

- -

Retrieves a zone with the matching zone name

- -

HTTP REQUEST

- -
-

GET /zones/name/{zoneName}

-
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - - - - - -
Codedescription
200OK - Successful lookup, the zone is returned in the response body
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
403Forbidden - The user does not have the access required to perform the action
404Not Found - Zone not found
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - -
nametypedescription
zonemaprefer to zone model
- -

EXAMPLE RESPONSE

- -
{
-  "zone": {
-    "status": "Active",
-    "account": "6baa85ad-267f-44ff-b535-818b7d7a2467",
-    "name": "system-test.",
-    "created": "2016-12-28T18:12:09Z",
-    "adminGroupId": "6baa85ad-267f-44ff-b535-818b7d7a2467",
-    "email": "test@example.com",
-    "connection": {
-      "primaryServer": "127.0.0.1:5301",
-      "keyName": "vinyl.",
-      "name": "system-test.",
-      "key": "OBF:1:B2cetOaRf1YAABAAek/w22XyKAleCRjA/hZO9fkNtNufPIRWTYHXviAk9GjrfcFOG9nNuB=="
-    },
-    "transferConnection": {
-      "primaryServer": "127.0.0.1:5301",
-      "keyName": "vinyl.",
-      "name": "system-test.",
-      "key": "OBF:1:PNt2k1nYkC0AABAAePpNMrDp+4C4GDbicWWlAqB5c4mKoKhvfpiWY1PfuRCVzSAeXydztB=="
-    },
-    "shared": true,
-    "acl": {
-      "rules": []
-    },
-    "id": "0f2fcece-b4ee-4982-b671-e5946f7db81d",
-    "latestSync": "2016-12-16T15:27:26Z"
-  }
-}
-
-
\ No newline at end of file diff --git a/api/index.html b/api/index.html deleted file mode 100644 index 0c294f84d..000000000 --- a/api/index.html +++ /dev/null @@ -1,27 +0,0 @@ -VinylDNS: API documentation
\ No newline at end of file diff --git a/api/list-batchchanges.html b/api/list-batchchanges.html deleted file mode 100644 index a596cb395..000000000 --- a/api/list-batchchanges.html +++ /dev/null @@ -1,241 +0,0 @@ -VinylDNS: List Batch Changes

List Batch Changes

- -

Retrieves the most recent 100 batch changes created by the user. This call will return a subset of the full information in each change, as detailed in the attributes section.

- -

The max number of batch changes that are returned from a single request has been set to 100.

- -

HTTP REQUEST

- -
-

GET zones/batchrecordchanges?startFrom={response.nextId}&maxItems={1-100}&ignoreAccess={true | false}&approval_status={BatchChangeApprovalStatus}

-
- -

HTTP REQUEST PARAMS

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametyperequired?description
startFromintnoIn order to advance through pages of results, the startFrom is set to the nextId that is returned on the previous response. It is up to the client to maintain previous pages if the client wishes to advance forward and backward. If not specified, will return the first page of results.
maxItemsintnoThe number of items to return in the page. Valid values are 1 - 100. Defaults to 100 if not provided.
ignoreAccessbooleannoFlag determining whether to retrieve only batch changes made by calling user or to retrieve all changes. Only affects system administrators (ie. support and super users). Defaults to false if not provided.
approvalStatusBatchChangeApprovalStatusnoFilter batch changes based on approval status. Can be one of AutoApproved, PendingReview, ManuallyApproved, Rejected, or Cancelled.
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - -
Codedescription
200OK - the batch change is returned in response body.
403Forbidden - the user does not have the access required to perform the action.
- -

If there are no batch changes created by the user, a successful empty response body is returned.

- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
batchChangesArray of BatchChangeSummarySummary information for the most recent 100 batch changes created by the user.
startFromintstartFrom sent in request, will not be returned if not provided.
nextIdintstartFrom parameter of next page request, will not be returned if record sets are exhausted.
maxItemsintegermaxItems sent in request, default is 100.
ignoreAccessbooleanignoreAccess sent in request, default is false.
approvalStatusBatchChangeApprovalStatusapprovalStatus sent in request, will not be returned if not provided.
- -
BatchChangeSummary
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
userIdstringThe unique identifier of the user that created the batch change.
userNamestringThe username of the user that created the batch change.
commentsstringConditional: comments about the batch change, if provided.
createdTimestampdate-timeThe timestamp (UTC) when the batch change was created.
totalChangesintThe total number of single changes within the batch change.
statusBatchChangeStatusStatus of the batch change.
idstringThe unique identifier for this batch change.
ownerGroupNamestringConditional: Record ownership assignment, if provided.
approvalStatusBatchChangeApprovalStatusWhether the batch change is currently awaiting manual review. Can be one of AutoApproved, PendingReview, ManuallyApproved, Rejected, or Cancelled.
- -

EXAMPLE RESPONSE

- -
{
-    "batchChanges": [
-        {
-            "userId": "vinyl", 
-            "userName": "vinyl201", 
-            "comments": "this is optional", 
-            "createdTimestamp": "2018-05-11T18:12:13Z", 
-            "totalChanges": 5, 
-            "status": "Complete", 
-            "id": "bd03175c-6fd7-419e-991c-3d5d1441d995",
-            "ownerGroupId": "f42385e4-5675-38c0-b42f-64105e743bfe",
-            "ownerGroupName": "some owner group name",
-            "approvalStatus": "AutoApproved"
-        }, 
-        {
-            "userId": "vinyl", 
-            "userName": "vinyl201", 
-            "comments": "this is optional", 
-            "createdTimestamp": "2018-05-11T18:12:12Z", 
-            "totalChanges": 10, 
-            "status": "Complete",
-            "id": "743cbd16-5440-4cf7-bca9-20319df9b651",
-            "ownerGroupId": "f42385e4-5675-38c0-b42f-64105e743bfe",
-            "ownerGroupName": "some owner group name",
-            "approvalStatus": "ManuallyApproved"
-        },
-        {
-            "userId": "vinyl", 
-            "userName": "vinyl201", 
-            "comments": "this is optional", 
-            "createdTimestamp": "2018-05-11T18:12:12Z", 
-            "totalChanges": 7, 
-            "status": "Complete", 
-            "id": "2b827a33-7c4f-4623-8dd9-277c6fba0e54",
-            "approvalStatus": "Rejected",
-            "reviewerId": "270ba4b3-f5eb-4043-a283-1a6cec0993f3",
-            "reviewerName": "some reviewer",
-            "reviewTimestamp": "2018-05-13T13:12:10Z"
-        }
-    ],
-    "maxItems": 100,
-    "ignoreAccess": false
-}
-
-
\ No newline at end of file diff --git a/api/list-group-activity.html b/api/list-group-activity.html deleted file mode 100644 index 7956cf2a0..000000000 --- a/api/list-group-activity.html +++ /dev/null @@ -1,207 +0,0 @@ -VinylDNS: List Group Activity

List Group Activity

- -

Retrieves a list of group activity

- -

HTTP REQUEST

- -
-

GET /groups/{groupId}/activity?startFrom={response.nextId}&maxItems={1 - 100}

-
- -

HTTP REQUEST PARAMS

- - - - - - - - - - - - - - - - - - - - - - - - -
nametyperequired?description
startFromanynoIn order to advance through pages of results, the startFrom is set to the nextId that is returned on the previous response. It is up to the client to maintain previous pages if the client wishes to advance forward and backward. If not specified, will return the first page of results
maxItemsintegernoThe number of items to return in the page. Valid values are 1 to 100. Defaults to 100 if not provided.
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - -
Codedescription
200OK - The changes have been returned in the response body
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
404Not Found - The group was not found
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
changesArray of Group Changesrefer to Group Change
startFromanystartFrom sent in request, will not be returned if not provided
nextIdanynextId, used as startFrom parameter of next page request, will not be returned if activity is exhausted
maxItemsintegermaxItems sent in request, default is 100
- -

GROUP CHANGE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
newGroupmapThe new group as a result of the change, refer to Membership Model
oldGroupmapThe old group before the change, refer to Membership Model
createdstringMillisecond timestamp that change was created
userIdstringUser Id of user who made the change
changeTypestringThe type change, either Create, Update, or Delete
- -

EXAMPLE RESPONSE

- -
{
-  "maxItems": 100,
-  "changes": [
-    {
-      "newGroup": {
-        "status": "Active",
-        "name": "test-list-group-activity-max-item-success",
-        "created": "2017-03-02T18:49:58Z",
-        "id": "1555bac7-0343-4d11-800f-955afb481818",
-        "admins": [
-          {
-            "id": "ok"
-          }
-        ],
-        "members": [
-          {
-            "id": "dummy199"
-          },
-          {
-            "id": "ok"
-          }
-        ],
-        "email": "test@test.com"
-      },
-      "created": "1488480605378",
-      "userId": "some-user",
-      "changeType": "Update",
-      "oldGroup": {
-        "status": "Active",
-        "name": "test-list-group-activity-max-item-success",
-        "created": "2017-03-02T18:49:58Z",
-        "id": "1555bac7-0343-4d11-800f-955afb481818",
-        "admins": [
-          {
-            "id": "ok"
-          }
-        ],
-        "members": [
-          {
-            "id": "dummy198"
-          },
-          {
-            "id": "ok"
-          }
-        ],
-        "email": "test@test.com"
-      },
-      "id": "11abb88b-c47d-469b-bc2d-6656e00711cf"
-    }
-  ]
-}
-
-
\ No newline at end of file diff --git a/api/list-group-admins.html b/api/list-group-admins.html deleted file mode 100644 index 4f8fed8f4..000000000 --- a/api/list-group-admins.html +++ /dev/null @@ -1,95 +0,0 @@ -VinylDNS: List Group Admins

List Group Admins

- -

Retrieves a group’s admins

- -

HTTP REQUEST

- -
-

GET /groups/{groupId}/admins

-
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - -
Codedescription
200OK - The admins have been returned in the response body
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
404Not Found - The group was not found
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - -
nametypedescription
adminsArray of Usersrefer to membership model
- -

EXAMPLE RESPONSE

- -
{
-  "admins": [
-    {
-      "userName": "jdoe201",
-      "firstName": "john",
-      "created": "2017-03-02T16:39:02Z",
-      "lastName": "doe",
-      "email": "john_doe@example.com",
-      "id": "2764183c-5e75-4ae6-8833-503cd5f4dcb0"
-    },
-    {
-      "userName": "jdoe202",
-      "firstName": "jane",
-      "created": "2017-03-02T16:50:02Z",
-      "lastName": "doe",
-      "email": "jane_doe@example.com",
-      "id": "1764183c-5e75-4ae6-8833-503cd5f4dcb4"
-    }
-  ]
-}
-
-
\ No newline at end of file diff --git a/api/list-group-members.html b/api/list-group-members.html deleted file mode 100644 index 477b07d40..000000000 --- a/api/list-group-members.html +++ /dev/null @@ -1,140 +0,0 @@ -VinylDNS: List Group Members

List Group Members

- -

Retrieves a list of group members

- -

HTTP REQUEST

- -
-

GET /groups/{groupId}/members?startFrom={response.nextId}&maxItems={1 - 100}

-
- -

HTTP REQUEST PARAMS

- - - - - - - - - - - - - - - - - - - - - - - - -
nametyperequired?description
startFromanynoIn order to advance through pages of results, the startFrom is set to the nextId that is returned on the previous response. It is up to the client to maintain previous pages if the client wishes to advance forward and backward. If not specified, will return the first page of results
maxItemsintegernoThe number of items to return in the page. Valid values are 1 to 100. Defaults to 100 if not provided.
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - -
Codedescription
200OK - The members have been returned in the response body
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
404Not Found - The group was not found
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
membersArray of Usersrefer to membership model, these Users will also include an isAdmin attribute
startFromanystartFrom sent in request, will not be returned if not provided
nextIdanynextId, used as startFrom parameter of next page request, will not be returned if members are exhausted
maxItemsintegermaxItems sent in request, default is 100
- -

EXAMPLE RESPONSE

- -
{
-  "members": [
-    {
-      "id": "0b1acc37-7d97-4da7-8a28-f1770bb99643",
-      "userName": "jdoe201",
-      "firstName": "John",
-      "lastName": "Doe",
-      "email": "John_Doe@example.com",
-      "created": "2017-03-02T18:42:31Z",
-      "isAdmin": true
-    },
-    {
-      "id": "0cb85121-671a-4920-ab02-0c17a7b40874",
-      "userName": "bwayne300",
-      "firstName": "Bruce",
-      "lastName": "Wayne",
-      "email": "Bruce_Wayne@cable.example.com",
-      "created": "2017-03-02T18:42:54Z",
-      "isAdmin": false
-    }
-  ],
-  "maxItems": 100
-}
-
-
\ No newline at end of file diff --git a/api/list-groups.html b/api/list-groups.html deleted file mode 100644 index 1957e6fe2..000000000 --- a/api/list-groups.html +++ /dev/null @@ -1,175 +0,0 @@ -VinylDNS: List Groups

List Groups

- -

Retrieves a list of groups that you are a part of

- -

HTTP REQUEST

- -
-

GET /groups?startFrom={response.nextId}&maxItems={1 - 100}&groupNameFilter={filter}&ignoreAccess={true | false}

-
- -

HTTP REQUEST PARAMS

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametyperequired?description
groupNameFilterstringnoOne or more characters contained in the name of the group set to search for. For example TP. This is a contains search only, no wildcards or regular expressions are supported
startFromanynoIn order to advance through pages of results, the startFrom is set to the nextId that is returned on the previous response. It is up to the client to maintain previous pages if the client wishes to advance forward and backward. If not specified, will return the first page of results
maxItemsintegernoThe number of items to return in the page. Valid values are 1 to 100. Defaults to 100 if not provided.
ignoreAccessbooleannoIf false, returns only groups the requesting user is a member of. If true, returns groups in the system, regardless of membership. Defaults to false if not provided. Super and support admin see all groups regardless of this value.
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - -
Codedescription
200OK - The groups have been returned in the response body
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
groupsArray of Groupsrefer to membership model
groupNameFilterstringname filter sent in request
startFromanystartFrom sent in request, will not be returned if not provided
nextIdanynextId, used as startFrom parameter of next page request, will not be returned if groups are exhausted
maxItemsintegermaxItems sent in request, default is 100
ignoreAccessbooleanThe ignoreAccess parameter that was sent in the HTTP request. This will be false if not sent.
- -

EXAMPLE RESPONSE

- -
{
-  "maxItems": 100,
-  "groups": [
-    {
-      "id": "93887728-2b26-4749-ba69-98871dda9cc0",
-      "name": "some-other-group",
-      "email": "test@example.com",
-      "created": "2017-03-02T16:23:07Z",
-      "status": "Active",
-      "members": [
-        {
-          "id": "2764183c-5e75-4ae6-8833-503cd5f4dcb0"
-        }
-      ],
-      "admins": [
-        {
-          "id": "2764183c-5e75-4ae6-8833-503cd5f4dcb0"
-        }
-      ]
-    },
-    {
-      "id": "aa1ea217-70a7-4350-b22b-c7e2f2158fb9",
-      "name": "some-group",
-      "email": "test@example.com",
-      "created": "2017-03-02T16:22:57Z",
-      "status": "Active",
-      "members": [
-        {
-          "id": "2764183c-5e75-4ae6-8833-503cd5f4dcb0"
-        }
-      ],
-      "admins": [
-        {
-          "id": "2764183c-5e75-4ae6-8833-503cd5f4dcb0"
-        }
-      ]
-    }
-  ],
-  "ignoreAccess": false
-}
-
-
\ No newline at end of file diff --git a/api/list-recordset-changes.html b/api/list-recordset-changes.html deleted file mode 100644 index 6db062628..000000000 --- a/api/list-recordset-changes.html +++ /dev/null @@ -1,610 +0,0 @@ -VinylDNS: List RecordSet Changes

List RecordSet Changes

- -

RecordSet changes (Create, Update, Delete) are not immediately applied to the DNS backend; they are queued up for processing. Most changes are applied within a few seconds. -When you submit a change for processing, the response is a Change model. You can use the information in that change model in order to poll for the status of the change until it completes (status = Complete) or fails (status = Failed) -

-Retrieves a list of RecordSet changes in a zone. All RecordSet changes are stored, including those coming from zone syncs. RecordSet changes come in max page sizes of 100 changes, paging must be done independently using startFrom and nextId parameters

- -

HTTP REQUEST

- -
-

GET /zones/{zoneId}/recordsetchanges?startFrom={response.nextId}&maxItems={1 - 100}

-
- -

HTTP REQUEST PARAMS

- - - - - - - - - - - - - - - - - - - - - - - - -
nametyperequired?description
startFromanynoIn order to advance through pages of results, the startFrom is set to the nextId that is returned on the previous response. It is up to the client to maintain previous pages if the client wishes to advance forward and backward. If not specified, will return the first page of results
maxItemsintnoThe number of items to return in the page. Valid values are 1 - 100. Defaults to 100 if not provided.
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - - - - - -
Codedescription
200OK - the recordset changes are returned in response body
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
403Forbidden - The user does not have the access required to perform the action
404Not Found - Zone not found
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
zoneIdstringId of zone used for request
recordSetChangesarray of recordset changesarray of recordset changes sorted by created time in descending order
startFromany(optional) The startFrom parameter that was sent in on the HTTP request. Will not be present if the startFrom parameter was not sent
nextIdany(optional) The identifier to be passed in as the startFrom parameter to retrieve the next page of results. If there are no results left, this field will not be present
maxItemsintThe maxItems parameter that was sent in on the HTTP request. This will be 100 if not sent
statusstringThe status of the change (Pending, Complete, Failed)
- -

EXAMPLE RESPONSE

- -
{
-  "recordSetChanges": [
-      {
-        "status": "Complete",
-        "zone": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:57Z",
-          "name": "system-test-history.",
-          "adminGroupId": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "created": "2016-12-30T15:37:56Z",
-          "account": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "email": "i.changed.this.10.times@history-test.com",
-          "shared": true,
-          "acl": {
-            "rules": []
-          },
-          "id": "9f353bc7-cb8d-491c-b074-34afafc97c5f"
-        },
-        "created": "2016-12-30T15:37:58Z",
-        "recordSet": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:58Z",
-          "name": "test-create-cname-ok",
-          "created": "2016-12-30T15:37:57Z",
-          "account": "history-id",
-          "zoneId": "9f353bc7-cb8d-491c-b074-34afafc97c5f",
-          "records": [
-            {
-              "cname": "changed-cname."
-            }
-          ],
-          "ttl": 200,
-          "type": "CNAME",
-          "id": "f62235df-5372-443c-9ba4-bdd3fca452f4"
-        },
-        "changeType": "Delete",
-        "userId": "history-id",
-        "updates": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:58Z",
-          "name": "test-create-cname-ok",
-          "created": "2016-12-30T15:37:57Z",
-          "account": "history-id",
-          "zoneId": "9f353bc7-cb8d-491c-b074-34afafc97c5f",
-          "records": [
-            {
-              "cname": "changed-cname."
-            }
-          ],
-          "ttl": 200,
-          "type": "CNAME",
-          "id": "f62235df-5372-443c-9ba4-bdd3fca452f4"
-        },
-        "id": "68fd6dbe-0da8-4280-bcf3-37f54528dc41"
-      },
-      {
-        "status": "Complete",
-        "zone": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:57Z",
-          "name": "system-test-history.",
-          "adminGroupId": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "created": "2016-12-30T15:37:56Z",
-          "account": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "email": "i.changed.this.10.times@history-test.com",
-          "shared": true,
-          "acl": {
-            "rules": []
-          },
-          "id": "9f353bc7-cb8d-491c-b074-34afafc97c5f"
-        },
-        "created": "2016-12-30T15:37:58Z",
-        "recordSet": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:58Z",
-          "name": "test-create-aaaa-ok",
-          "created": "2016-12-30T15:37:57Z",
-          "account": "history-id",
-          "zoneId": "9f353bc7-cb8d-491c-b074-34afafc97c5f",
-          "records": [
-            {
-              "address": "2003:db8:0:0:0:0:0:4"
-            },
-            {
-              "address": "2002:db8:0:0:0:0:0:3"
-            }
-          ],
-          "ttl": 200,
-          "type": "AAAA",
-          "id": "9559103d-4cb4-4d34-9d3f-eab3fe2e8aed"
-        },
-        "changeType": "Delete",
-        "userId": "history-id",
-        "updates": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:57Z",
-          "name": "test-create-aaaa-ok",
-          "created": "2016-12-30T15:37:57Z",
-          "account": "history-id",
-          "zoneId": "9f353bc7-cb8d-491c-b074-34afafc97c5f",
-          "records": [
-            {
-              "address": "2003:db8:0:0:0:0:0:4"
-            },
-            {
-              "address": "2002:db8:0:0:0:0:0:3"
-            }
-          ],
-          "ttl": 200,
-          "type": "AAAA",
-          "id": "9559103d-4cb4-4d34-9d3f-eab3fe2e8aed"
-        },
-        "id": "dabf1e57-49e7-4d2d-8a00-814d88546b0c"
-      },
-      {
-        "status": "Complete",
-        "zone": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:57Z",
-          "name": "system-test-history.",
-          "adminGroupId": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "created": "2016-12-30T15:37:56Z",
-          "account": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "email": "i.changed.this.10.times@history-test.com",
-          "shared": true,
-          "acl": {
-            "rules": []
-          },
-          "id": "9f353bc7-cb8d-491c-b074-34afafc97c5f"
-        },
-        "created": "2016-12-30T15:37:58Z",
-        "recordSet": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:58Z",
-          "name": "test-create-a-ok",
-          "created": "2016-12-30T15:37:57Z",
-          "account": "history-id",
-          "zoneId": "9f353bc7-cb8d-491c-b074-34afafc97c5f",
-          "records": [
-            {
-              "address": "9.9.9.9"
-            },
-            {
-              "address": "10.2.2.2"
-            }
-          ],
-          "ttl": 200,
-          "type": "A",
-          "id": "f1fd620e-5ff3-4ee9-839f-bc747a9867d9"
-        },
-        "changeType": "Delete",
-        "userId": "history-id",
-        "updates": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:57Z",
-          "name": "test-create-a-ok",
-          "created": "2016-12-30T15:37:57Z",
-          "account": "history-id",
-          "zoneId": "9f353bc7-cb8d-491c-b074-34afafc97c5f",
-          "records": [
-            {
-              "address": "9.9.9.9"
-            },
-            {
-              "address": "10.2.2.2"
-            }
-          ],
-          "ttl": 200,
-          "type": "A",
-          "id": "f1fd620e-5ff3-4ee9-839f-bc747a9867d9"
-        },
-        "id": "23ae1487-bc7f-481b-a544-10ceb7a87540"
-      },
-      {
-        "status": "Complete",
-        "zone": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:57Z",
-          "name": "system-test-history.",
-          "adminGroupId": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "created": "2016-12-30T15:37:56Z",
-          "account": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "email": "i.changed.this.10.times@history-test.com",
-          "shared": true,
-          "acl": {
-            "rules": []
-          },
-          "id": "9f353bc7-cb8d-491c-b074-34afafc97c5f"
-        },
-        "created": "2016-12-30T15:37:57Z",
-        "recordSet": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:58Z",
-          "name": "test-create-cname-ok",
-          "created": "2016-12-30T15:37:57Z",
-          "account": "history-id",
-          "zoneId": "9f353bc7-cb8d-491c-b074-34afafc97c5f",
-          "records": [
-            {
-              "cname": "changed-cname."
-            }
-          ],
-          "ttl": 200,
-          "type": "CNAME",
-          "id": "f62235df-5372-443c-9ba4-bdd3fca452f4"
-        },
-        "changeType": "Update",
-        "userId": "history-id",
-        "updates": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:57Z",
-          "name": "test-create-cname-ok",
-          "created": "2016-12-30T15:37:57Z",
-          "account": "history-id",
-          "zoneId": "9f353bc7-cb8d-491c-b074-34afafc97c5f",
-          "records": [
-            {
-              "cname": "cname."
-            }
-          ],
-          "ttl": 100,
-          "type": "CNAME",
-          "id": "f62235df-5372-443c-9ba4-bdd3fca452f4"
-        },
-        "id": "5c722555-c7be-4620-a1fd-8ca53a5b8683"
-      },
-      {
-        "status": "Complete",
-        "zone": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:57Z",
-          "name": "system-test-history.",
-          "adminGroupId": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "created": "2016-12-30T15:37:56Z",
-          "account": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "email": "i.changed.this.10.times@history-test.com",
-          "shared": true,
-          "acl": {
-            "rules": []
-          },
-          "id": "9f353bc7-cb8d-491c-b074-34afafc97c5f"
-        },
-        "created": "2016-12-30T15:37:57Z",
-        "recordSet": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:57Z",
-          "name": "test-create-aaaa-ok",
-          "created": "2016-12-30T15:37:57Z",
-          "account": "history-id",
-          "zoneId": "9f353bc7-cb8d-491c-b074-34afafc97c5f",
-          "records": [
-            {
-              "address": "2003:db8:0:0:0:0:0:4"
-            },
-            {
-              "address": "2002:db8:0:0:0:0:0:3"
-            }
-          ],
-          "ttl": 200,
-          "type": "AAAA",
-          "id": "9559103d-4cb4-4d34-9d3f-eab3fe2e8aed"
-        },
-        "changeType": "Update",
-        "userId": "history-id",
-        "updates": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:57Z",
-          "name": "test-create-aaaa-ok",
-          "created": "2016-12-30T15:37:57Z",
-          "account": "history-id",
-          "zoneId": "9f353bc7-cb8d-491c-b074-34afafc97c5f",
-          "records": [
-            {
-              "address": "2001:db8:0:0:0:0:0:3"
-            },
-            {
-              "address": "2002:db8:0:0:0:0:0:3"
-            }
-          ],
-          "ttl": 100,
-          "type": "AAAA",
-          "id": "9559103d-4cb4-4d34-9d3f-eab3fe2e8aed"
-        },
-        "id": "480fff34-61d3-4a1d-9696-f5007842b38a"
-      },
-      {
-        "status": "Complete",
-        "zone": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:57Z",
-          "name": "system-test-history.",
-          "adminGroupId": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "created": "2016-12-30T15:37:56Z",
-          "account": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "email": "i.changed.this.10.times@history-test.com",
-          "shared": true,
-          "acl": {
-            "rules": []
-          },
-          "id": "9f353bc7-cb8d-491c-b074-34afafc97c5f"
-        },
-        "created": "2016-12-30T15:37:57Z",
-        "recordSet": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:57Z",
-          "name": "test-create-a-ok",
-          "created": "2016-12-30T15:37:57Z",
-          "account": "history-id",
-          "zoneId": "9f353bc7-cb8d-491c-b074-34afafc97c5f",
-          "records": [
-            {
-              "address": "9.9.9.9"
-            },
-            {
-              "address": "10.2.2.2"
-            }
-          ],
-          "ttl": 200,
-          "type": "A",
-          "id": "f1fd620e-5ff3-4ee9-839f-bc747a9867d9"
-        },
-        "changeType": "Update",
-        "userId": "history-id",
-        "updates": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:57Z",
-          "name": "test-create-a-ok",
-          "created": "2016-12-30T15:37:57Z",
-          "account": "history-id",
-          "zoneId": "9f353bc7-cb8d-491c-b074-34afafc97c5f",
-          "records": [
-            {
-              "address": "10.1.1.1"
-            },
-            {
-              "address": "10.2.2.2"
-            }
-          ],
-          "ttl": 100,
-          "type": "A",
-          "id": "f1fd620e-5ff3-4ee9-839f-bc747a9867d9"
-        },
-        "id": "999d8674-e59b-478e-95c0-9d4eb964f2be"
-      },
-      {
-        "status": "Complete",
-        "zone": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:57Z",
-          "name": "system-test-history.",
-          "adminGroupId": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "created": "2016-12-30T15:37:56Z",
-          "account": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "email": "i.changed.this.10.times@history-test.com",
-          "connection": {
-            "primaryServer": "127.0.0.1:5301",
-            "keyName": "vinyl.",
-            "name": "system-test-history.",
-            "key": "OBF:1:YVgGogd/Y+oAABAAIp4s3z7FAn92uvfOci9v0jMjihQ+uV3bOCyNwpMPh78tL4q/A8dR7A=="
-          },
-          "transferConnection": {
-            "primaryServer": "127.0.0.1:5301",
-            "keyName": "vinyl.",
-            "name": "system-test-history.",
-            "key": "OBF:1:Pq3UqxiceV4AABAAdu90et1pkNn2ZO3MuYstki5BkQVm3T50RQLarpVhIgaoOKLi2CdL6Q=="
-          },
-          "shared": true,
-          "acl": {
-            "rules": []
-          },
-          "id": "9f353bc7-cb8d-491c-b074-34afafc97c5f"
-        },
-        "created": "2016-12-30T15:37:57Z",
-        "recordSet": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:57Z",
-          "name": "test-create-cname-ok",
-          "created": "2016-12-30T15:37:57Z",
-          "account": "history-id",
-          "zoneId": "9f353bc7-cb8d-491c-b074-34afafc97c5f",
-          "records": [
-            {
-              "cname": "cname."
-            }
-          ],
-          "ttl": 100,
-          "type": "CNAME",
-          "id": "f62235df-5372-443c-9ba4-bdd3fca452f4"
-        },
-        "changeType": "Create",
-        "userId": "history-id",
-        "id": "b05f0837-84bd-47aa-8a95-7bde91046268"
-      },
-      {
-        "status": "Complete",
-        "zone": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:57Z",
-          "name": "system-test-history.",
-          "adminGroupId": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "created": "2016-12-30T15:37:56Z",
-          "account": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "email": "i.changed.this.10.times@history-test.com",
-          "shared": true,
-          "acl": {
-            "rules": []
-          },
-          "id": "9f353bc7-cb8d-491c-b074-34afafc97c5f"
-        },
-        "created": "2016-12-30T15:37:57Z",
-        "recordSet": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:57Z",
-          "name": "test-create-aaaa-ok",
-          "created": "2016-12-30T15:37:57Z",
-          "account": "history-id",
-          "zoneId": "9f353bc7-cb8d-491c-b074-34afafc97c5f",
-          "records": [
-            {
-              "address": "2001:db8:0:0:0:0:0:3"
-            },
-            {
-              "address": "2002:db8:0:0:0:0:0:3"
-            }
-          ],
-          "ttl": 100,
-          "type": "AAAA",
-          "id": "9559103d-4cb4-4d34-9d3f-eab3fe2e8aed"
-        },
-        "changeType": "Create",
-        "userId": "history-id",
-        "id": "e7e6b7f9-5253-4947-9580-3f0b81a48717"
-      },
-      {
-        "status": "Complete",
-        "zone": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:57Z",
-          "name": "system-test-history.",
-          "adminGroupId": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "created": "2016-12-30T15:37:56Z",
-          "account": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "email": "i.changed.this.10.times@history-test.com",
-          "shared": true,
-          "acl": {
-            "rules": []
-          },
-          "id": "9f353bc7-cb8d-491c-b074-34afafc97c5f"
-        },
-        "created": "2016-12-30T15:37:57Z",
-        "recordSet": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:57Z",
-          "name": "test-create-a-ok",
-          "created": "2016-12-30T15:37:57Z",
-          "account": "history-id",
-          "zoneId": "9f353bc7-cb8d-491c-b074-34afafc97c5f",
-          "records": [
-            {
-              "address": "10.1.1.1"
-            },
-            {
-              "address": "10.2.2.2"
-            }
-          ],
-          "ttl": 100,
-          "type": "A",
-          "id": "f1fd620e-5ff3-4ee9-839f-bc747a9867d9"
-        },
-        "changeType": "Create",
-        "userId": "history-id",
-        "id": "6743d428-7748-4348-a6c9-ae59e9eeaf97"
-      }
-    ],
-  "maxItems": 100
-}
-
-
\ No newline at end of file diff --git a/api/list-recordsets-by-zone.html b/api/list-recordsets-by-zone.html deleted file mode 100644 index 280f8744e..000000000 --- a/api/list-recordsets-by-zone.html +++ /dev/null @@ -1,266 +0,0 @@ -VinylDNS: List / Search RecordSets

List / Search RecordSets by Zone

- -

Retrieves a list of RecordSets from the zone

- -

HTTP REQUEST

- -
-

GET /zones/{zoneId}/recordsets?startFrom={response.nextId}&maxItems={1 - 100}&recordNameFilter={filter}

-
- -

HTTP REQUEST PARAMS

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametyperequired?description
recordNameFilterstringnoCharacters that are part of the record name to search for. The wildcard character * is supported, for example www*. Omit the wildcard when searching for an exact record name.
recordTypeFilterArray of RecordTypenoAn array of record types to filter for listing record sets. Refer to recordset mode for supported types. Invalid record types will be ignored. If left empty or no valid record types are provided, then all record types will be returned.
nameSortstringnoName sort order for record sets returned by list record set response. Valid values are ASC (ascending; default) and DESC (descending).
startFromanynoIn order to advance through pages of results, the startFrom is set to the nextId that is returned on the previous response. It is up to the client to maintain previous pages if the client wishes to advance forward and backward. If not specified, will return the first page of results
maxItemsintegernoThe number of items to return in the page. Valid values are 1 to 100. Defaults to 100 if not provided.
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - - - - - -
Codedescription
200OK - The record sets are returned in the response body
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
403Forbidden - The user does not have the access required to perform the action
404Not Found - Zone or RecordSet not found
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
recordSetsArray of RecordSetsrefer to recordset model, the RecordSet data will also include the accessLevel the requesting user has based off acl rules and membership in Zone Admin Group
startFromanystartFrom sent in request, will not be returned if not provided
nextIdanynextId, used as startFrom parameter of next page request, will not be returned if record sets are exhausted
maxItemsintegermaxItems sent in request, default is 100
recordNameFilterstringname filter sent in request
recordTypeFilterArray of RecordTyperecord type filter sent in request
nameSortstringname sort order sent in request
- -

EXAMPLE RESPONSE

- -
{
-  "recordSets": [
-    {
-      "type": "A",
-      "zoneId": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-      "name": "already-exists",
-      "ttl": 38400,
-      "status": "Active",
-      "created": "2017-02-23T15:12:41Z",
-      "updated": "2017-02-23T15:12:41Z",
-      "records": [
-        {
-          "address": "6.6.6.1"
-        }
-      ],
-      "id": "dd9c1120-0594-4e61-982e-8ddcbc8b2d21",
-      "account": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae",
-      "accessLevel": "Delete"
-    },
-    {
-      "type": "NS",
-      "zoneId": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-      "name": "vinyl",
-      "ttl": 38400,
-      "status": "Active",
-      "created": "2017-02-23T15:12:33Z",
-      "records": [
-        {
-          "nsdname": "172.17.42.2."
-        }
-      ],
-      "id": "daf5ea7b-c28c-422a-ba47-2c37ca567a77",
-      "account": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae",
-      "accessLevel": "Delete"
-    },
-    {
-      "type": "SOA",
-      "zoneId": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-      "name": "vinyl",
-      "ttl": 38400,
-      "status": "Active",
-      "created": "2017-02-23T15:12:33Z",
-      "records": [
-        {
-          "mname": "172.17.42.2.",
-          "rname": "admin.test.com.",
-          "serial": 1439234395,
-          "refresh": 10800,
-          "retry": 3600,
-          "expire": 604800,
-          "minimum": 38400
-        }
-      ],
-      "id": "9da83158-05ab-4f14-8bd0-0a4d85cdeb30",
-      "account": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae",
-      "accessLevel": "Delete"
-    },
-    {
-      "type": "A",
-      "zoneId": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-      "name": "vinyl",
-      "ttl": 38400,
-      "status": "Active",
-      "created": "2017-02-23T15:12:33Z",
-      "records": [
-        {
-          "address": "5.5.5.5"
-        }
-      ],
-      "id": "d73275ff-e71e-4024-aef1-1236741443b5",
-      "account": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae",
-      "accessLevel": "Delete"
-    },
-    {
-      "type": "A",
-      "zoneId": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-      "name": "jenkins",
-      "ttl": 38400,
-      "status": "Active",
-      "created": "2017-02-23T15:12:33Z",
-      "records": [
-        {
-          "address": "10.1.1.1"
-        }
-      ],
-      "id": "0432f63b-3947-4262-9ade-a3311d07a099",
-      "account": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae",
-      "accessLevel": "Delete"
-    },
-    {
-      "type": "A",
-      "zoneId": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-      "name": "test",
-      "ttl": 38400,
-      "status": "Active",
-      "created": "2017-02-23T15:12:33Z",
-      "records": [
-        {
-          "address": "4.4.4.4"
-        },
-        {
-          "address": "3.3.3.3"
-        }
-      ],
-      "id": "dc0e3ce9-ec01-47f1-9418-461dc1754f48",
-      "account": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae",
-      "accessLevel": "Delete"
-    }
-  ],
-  "maxItems": 100,
-  "nameSort": "ASC"
-}
-
-
\ No newline at end of file diff --git a/api/list-recordsets-global.html b/api/list-recordsets-global.html deleted file mode 100644 index 4068fa735..000000000 --- a/api/list-recordsets-global.html +++ /dev/null @@ -1,185 +0,0 @@ -VinylDNS: Global List / Search RecordSets

Global List / Search RecordSets

- -

Retrieves a list of RecordSets globally in the VinylDNS database based on search criteria. A minimum of two alpha-numeric characters is required.

- -

HTTP REQUEST

- -
-

GET /recordsets?startFrom={response.nextId}&maxItems={1 - 100}&recordNameFilter={recordNameFilter}&recordTypeFilter={recordTypeFilter}&recordOwnerGroupFilter={recordOwnerGroupFilter}&nameSort={nameSort}

-
- -

HTTP REQUEST PARAMS

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametyperequired?description
recordNameFilterstringyesCharacters that are part of the record name to search for. The wildcard character * is supported, for example www*. Omit the wildcard when searching for an exact record name. At least two alphanumeric characters are required for searching.
recordTypeFilterArray of RecordTypenoAn array of record types to filter for listing record sets. Refer to recordset mode for supported types. Invalid record types will be ignored. If left empty or no valid record types are provided, then all record types will be returned.
recordOwnerGroupFilterstringnoOwner group ID for record set.
nameSortstringnoName sort order for record sets returned by list record set response. Valid values are ASC (ascending; default) and DESC (descending).
startFromanynoIn order to advance through pages of results, the startFrom is set to the nextId that is returned on the previous response. It is up to the client to maintain previous pages if the client wishes to advance forward and backward. If not specified, will return the first page of results
maxItemsintegernoThe number of items to return in the page. Valid values are 1 to 100. Defaults to 100 if not provided.
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - -
Codedescription
200OK - The record sets are returned in the response body
422Unprocessable Entity - recordNameFilter was either omitted or provided but does not contain at least two alphanumeric characters
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
recordSetsArray of RecordSetsrefer to recordset model
startFromanystartFrom sent in request, will not be returned if not provided
nextIdanynextId, used as startFrom parameter of next page request, will not be returned if record sets are exhausted
maxItemsintegermaxItems sent in request, default is 100
recordNameFilterstringname filter sent in request
recordTypeFilterArray of RecordTyperecord type filter sent in request
recordOwnerGroupFilterstringrecord owner group sent in request
nameSortstringname sort order sent in request
- -

EXAMPLE RESPONSE

- -
{
-  "recordSets": [
-    {
-      "type": "A",
-      "zoneId": "5f5304ba-c81f-456c-9d33-bb6179c8b1f1",
-      "name": "foo",
-      "ttl": 7200,
-      "status": "Active",
-      "created": "2019-04-26T17:15:35Z",
-      "records": [
-        {
-          "address": "1.1.1.1"
-        }
-      ],
-      "id": "f802596f-4f0e-4e65-bb43-c7ca439d2608",
-      "account": "system",
-      "fqdn": "foo.example.com.",
-      "zoneName": "example.com.",
-      "zoneShared": true
-    }
-  ],
-  "maxItems": 100,
-  "recordNameFilter": "foo*",
-  "recordTypeFilter": [
-    "A"
-  ],
-  "nameSort": "ASC"
-}
-
-
\ No newline at end of file diff --git a/api/list-zone-changes.html b/api/list-zone-changes.html deleted file mode 100644 index 66e48f5f3..000000000 --- a/api/list-zone-changes.html +++ /dev/null @@ -1,176 +0,0 @@ -VinylDNS: List Zone Changes

List Zone Changes

- -

Retrieves a list of zone changes to a zone. All zone changes are stored, including those coming from zone syncs. Zone changes come in max page sizes of 100 changes, paging must be done independently using startFrom and nextId parameters

- -

HTTP REQUEST

- -
-

GET /zones/{zoneId}/changes?startFrom={response.nextId}&maxItems={1 - 100}

-
- -

HTTP REQUEST PARAMS

- - - - - - - - - - - - - - - - - - - - - - - - -
nametyperequired?description
startFromanynoIn order to advance through pages of results, the startFrom is set to the nextId that is returned on the previous response. It is up to the client to maintain previous pages if the client wishes to advance forward and backward. If not specified, will return the first page of results
maxItemsintnoThe number of items to return in the page. Valid values are 1 - 100. Defaults to 100 if not provided.
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - - - - - -
Codedescription
200Accepted - The zone changes will be returned in the response body
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
403Forbidden - The user does not have the access required to perform the action
404Not Found - Zone not found
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
zoneIdstringId of zone used for request
zoneChangesarray of zone changesarray of zone changes sorted by created time in descending order
startFromany(optional) The startFrom parameter that was sent in on the HTTP request. Will not be present if the startFrom parameter was not sent
nextIdany(optional) The identifier to be passed in as the startFrom parameter to retrieve the next page of results. If there are no results left, this field will not be present
maxItemsintThe maxItems parameter that was sent in on the HTTP request. This will be 100 if not sent
- -

EXAMPLE RESPONSE

- -
{
-  "zoneId": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-  "zoneChanges": [
-      {
-        "status": "Synced",
-        "zone": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:57Z",
-          "name": "system-test-history.",
-          "adminGroupId": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "created": "2016-12-30T15:37:56Z",
-          "account": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "email": "i.changed.this.10.times@history-test.com",
-          "shared": true,
-          "acl": {
-            "rules": []
-          },
-          "id": "9f353bc7-cb8d-491c-b074-34afafc97c5f"
-        },
-        "created": "2016-12-30T15:37:57Z",
-        "changeType": "Update",
-        "userId": "history-id",
-        "id": "6d4deccb-4632-475e-9ebc-3f6bace5fe68"
-      },
-      {
-        "status": "Synced",
-        "zone": {
-          "status": "Active",
-          "updated": "2016-12-30T15:37:57Z",
-          "name": "system-test-history.",
-          "adminGroupId": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "created": "2016-12-30T15:37:56Z",
-          "account": "67b4da23-6832-4600-8450-9fa0664caeeb",
-          "email": "i.changed.this.9.times@history-test.com",
-          "shared": true,
-          "acl": {
-            "rules": []
-          },
-          "id": "9f353bc7-cb8d-491c-b074-34afafc97c5f"
-        },
-        "created": "2016-12-30T15:37:57Z",
-        "changeType": "Update",
-        "userId": "history-id",
-        "id": "59c2db90-41aa-49ae-8c56-e13a2ada918d"
-      }
-  ],
-  "startFrom": "2910234",
-  "nextId": "1034932",
-  "maxItems": 2
-}
-
-
\ No newline at end of file diff --git a/api/list-zones.html b/api/list-zones.html deleted file mode 100644 index 4ec9c3681..000000000 --- a/api/list-zones.html +++ /dev/null @@ -1,222 +0,0 @@ -VinylDNS: List / Search Zones

List / Search Zone

- -

Retrieves the list of zones a user has access to. The zone name is only sorted alphabetically.

- -

HTTP REQUEST

- -
- - - - - - - -
GET /zones?nameFilter={yoursearchhere}&startFrom={response.nextId}&maxItems={1 - 100}&ignoreAccess={truefalse}
-
- -

HTTP REQUEST PARAMS

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametyperequired?description
nameFilterstringnoCharacters that are part of the zone name to search for. The wildcard character * is supported, for example www*. Omit the wildcard character when searching for an exact zone name.
startFromanynoIn order to advance through pages of results, the startFrom is set to the nextId that is returned on the previous response. It is up to the client to maintain previous pages if the client wishes to advance forward and backward. If not specified, will return the first page of results
maxItemsintnoThe number of items to return in the page. Valid values are 1 - 100. Defaults to 100 if not provided.
ignoreAccessbooleannoIf false, returns only zones the requesting user owns or has ACL access to. If true, returns zones in the system, regardless of ownership. Defaults to false if not provided.
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - -
Codedescription
200OK - The zones and search info are returned in response body
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
403Forbidden - The user does not have the access required to perform the action
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
zonesArray of ZonesAn array of the zones found. The zones are sorted alphabetically by zone name.
startFromany(optional) The startFrom parameter that was sent in on the HTTP request. Will not be present if the startFrom parameter was not sent
nextIdany(optional) The identifier to be passed in as the startFrom parameter to retrieve the next page of results. If there are no results left, this field will not be present.
maxItemsintThe maxItems parameter that was sent in the HTTP request. This will be 100 if not sent.
ignoreAccessbooleanThe ignoreAccess parameter that was sent in the HTTP request. This will be false if not sent.
- -

EXAMPLE RESPONSE

- -
{
-  "zones": [
-    {
-      "status": "Active",
-      "account": "a0b5ea74-cc05-4932-a294-9bf935d52744",
-      "name": "list-zones-test-searched-1.",
-      "created": "2016-12-16T15:21:47Z",
-      "adminGroupId": "a0b5ea74-cc05-4932-a294-9bf935d52744",
-      "email": "test@test.com",
-      "shared": false,
-      "acl": {
-        "rules": []
-      },
-      "id": "31a3d8a9-bea0-458f-9c24-3d39d4b929d6",
-      "latestSync": "2016-12-16T15:27:26Z",
-      "accessLevel": "NoAccess"
-    },
-    {
-      "status": "Active",
-      "account": "a0b5ea74-cc05-4932-a294-9bf935d52744",
-      "name": "list-zones-test-searched-2.",
-      "created": "2016-12-16T15:21:47Z",
-      "adminGroupId": "a0b5ea74-cc05-4932-a294-9bf935d52744",
-      "email": "test@test.com",
-      "shared": false,
-      "acl": {
-        "rules": []
-      },
-      "id": "f1a376b2-2d8f-41f3-b8c8-9c9fba308f5d",
-      "latestSync": "2016-12-16T15:27:26Z",
-      "accessLevel": "Delete"
-    },
-    {
-      "status": "Active",
-      "account": "a0b5ea74-cc05-4932-a294-9bf935d52744",
-      "name": "list-zones-test-searched-3.",
-      "created": "2016-12-16T15:21:47Z",
-      "adminGroupId": "a0b5ea74-cc05-4932-a294-9bf935d52744",
-      "email": "test@test.com",
-      "shared": false,
-      "acl": {
-        "rules": []
-      },
-      "id": "568de57d-cb34-4f05-a9b5-35f9187490af",
-      "latestSync": "2016-12-16T15:27:26Z",
-      "accessLevel": "Read"
-    },
-    {
-      "status": "Active",
-      "account": "a0b5ea74-cc05-4932-a294-9bf935d52744",
-      "name": "list-zones-test-unfiltered-1.",
-      "created": "2016-12-16T15:21:47Z",
-      "adminGroupId": "a0b5ea74-cc05-4932-a294-9bf935d52744",
-      "email": "test@test.com",
-      "shared": false,
-      "acl": {
-        "rules": []
-      },
-      "id": "98dac90c-236e-4171-8729-c977ad38717e",
-      "latestSync": "2016-12-16T15:27:26Z",
-      "accessLevel": "NoAccess"
-    },
-    {
-      "status": "Active",
-      "account": "a0b5ea74-cc05-4932-a294-9bf935d52744",
-      "name": "list-zones-test-unfiltered-2.",
-      "created": "2016-12-16T15:21:47Z",
-      "adminGroupId": "a0b5ea74-cc05-4932-a294-9bf935d52744",
-      "email": "test@test.com",
-      "shared": false,
-      "acl": {
-        "rules": []
-      },
-      "id": "e4942020-b85a-421f-a8e2-124d8ba79422",
-      "latestSync": "2016-12-16T15:27:26Z",
-      "accessLevel": "Read"
-    }
-  ],
-  "maxItems": 100,
-  "ignoreAccess": true
-}
-
-
\ No newline at end of file diff --git a/api/membership-model.html b/api/membership-model.html deleted file mode 100644 index e58eb8ab6..000000000 --- a/api/membership-model.html +++ /dev/null @@ -1,182 +0,0 @@ -VinylDNS: Membership Model

Membership Model

- -

Table of Contents

- - - -

MEMBERSHIP BREAKDOWN

- -

Every zone can be connected to by only one group in VinylDNS. That initial group will be the admin group for that zone, -which can be changed later on in a Zone Update. Every member of the admin group -will be an admin of that zone, and can preform zone syncs, zone updates, zone deletes, and record set changes regardless -of any Access Control Rules set on them. -

-While users in the admin group will have complete zone access, further users can be given limited membership through Zone -ACL Rules

- -

GROUP ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
fieldtypedescription
namestringThis should be a single word name used for the groups. Use hyphens if needed, no spaces
emailstringThe email distribution list for the group
descriptionstringA short description of the group, if more info is needed other than the name. The group will not have this attribute if it was not included in the create request
idstringUnique UUID of the group
createddate-timeThe timestamp (UTC) when the group was created
statusstringActive or Deleted
membersArray of User id objectsSet of User ids in the group
adminsArray of User id objectsSet of User ids that are admins of the group. All admin user ids should also be in the members array
- -

Being in the admin set of a group has no impact on zone privileges when the group is the zone’s admin group. Being a group admin allows adding users to -the group, deleting users from the group, toggling other users’ admin statuses (including your own), and deleting the group

- -

GROUP EXAMPLE

- -
{
-  "id": "dc4c7c79-5bbc-41bf-992e-8d6c4ec574c6",
-  "name": "some-group",
-  "email": "test@example.com",
-  "created": "2017-01-30T20:05:24Z",
-  "status": "Active",
-  "members": [
-    {
-      "id": "2764183c-5e75-4ae6-8833-503cd5f4dcb0"
-    },
-    {
-      "id": "a6d35b1a-57d7-4a65-bec2-d7ed30a7c430"
-    }
-  ],
-  "admins": [
-    {
-      "id": "a6d35b1a-57d7-4a65-bec2-d7ed30a7c430"
-    }
-  ]
-}
-
- -

USER ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
fieldtypedescription
userNamestringThis should be the AD username of the user
firstNamestringFirst name of the user
lastNamestringLast name of the user
emailstringEmail address of the user
createddate-timeThe timestamp (UTC) when the user was created
idstringUnique UUID of the user
isTestbooleanDefaults to false. Used for restricted access during VinylDNS testing, can be ignored by clients
- -

To get your access and secret keys, log into the VinylDNS portal and then with the top right drop-down select Download Credentials

- -

USER EXAMPLE

- -
{
-  "userName": "jdoe201",
-  "firstName": "John",
-  "lastName": "Doe",
-  "email": "john_doe@example.com",
-  "id": "1764183c-5e75-4ae6-8833-503cd5f4dcb3",
-  "isTest": false
-}
-
-
\ No newline at end of file diff --git a/api/recordset-model.html b/api/recordset-model.html deleted file mode 100644 index 959a791de..000000000 --- a/api/recordset-model.html +++ /dev/null @@ -1,421 +0,0 @@ -VinylDNS: RecordSet Model

RecordSet Model

- -

Table of Contents

- - - -

RecordSet ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
fieldtypedescription
zoneIdstringthe id of the zone to which this recordset belongs
namestringThe name of the RecordSet
typestringType of DNS record, supported records are currently: A, AAAA, CNAME, DS, MX, NAPTR, NS, PTR, SOA, SRV, TXT, SSHFP, and SPF. Unsupported types will be given the type UNKNOWN
ttllongthe TTL in seconds for the recordset
statusstringActive - RecordSet is added is created and ready for use, Inactive - RecordSet effects are not applied, Pending - RecordSet is queued for creation, PendingUpdate - RecordSet is queued for update, PendingDelete - RecordSet is queued for delete
createddate-timeThe timestamp (UTC) when the recordset was created
updateddate-timeThe timestamp (UTC) when the recordset was last updated
recordsArray of RecordDataArray of record data, a single RecordSet can have multiple DNS records as long as they are all the same type
idstringthe id of the recordset. This is important as you will use it for other recordset operations
accountstringDEPRECATED The account that created the RecordSet
- -

RecordSet EXAMPLE

- -
{
-    "type": "A",
-    "zoneId": "8f8f649f-998e-4428-a029-b4ba5f5bd4ca",
-    "name": "foo",
-    "ttl": 38400,
-    "status": "Active",
-    "created": "2017-02-22T21:34:35Z",
-    "records": [
-        {
-            "address": "1.1.1.1"
-        },
-        {
-            "address": "2.2.2.2"
-        },
-        {
-            "address": "3.3.3.3"
-        }
-    ],
-    "id": "8306cce4-e16a-4579-9b19-4af46dc75853",
-    "account": "b34f8d18-646f-4843-a80a-7c0d58a22bf5"
-}
-
- -

RECORD DATA INFORMATION

-

Current supported record types are: A, AAAA, CNAME, DS, MX, NAPTR, NS, PTR, SOA, SRV, TXT, SSHFP, and SPF. -Each individual record encodes its data in a record data object, in which each record type has different required attributes -

-SOA records and NS origin records (record with the same name as the zone) are currently read-only and cannot be created, updated or deleted. -Non-origin NS records can be created or updated for approved name servers only. Any non-origin NS record can be deleted.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
record typeattributetype
Aaddressstring

  
AAAAaddressstring

  
CNAMEcnamestring

  
DSkeytaginteger
DSalgorithminteger
DSdigesttypeinteger
DSdigeststring

  
MXpreferenceinteger
MXexchangestring

  
NAPTRorderinteger
NAPTRpreferenceinteger
NAPTRflagsstring
NAPTRservicestring
NAPTRregexpstring
NAPTRreplacementstring

  
NSnsdnamestring

  
PTRptrdnamestring

  
SOAmnamestring
SOArnamestring
SOAseriallong
SOArefreshlong
SOAretrylong
SOAexpirelong
SOAminimumlong

  
SPFtextstring

  
SRVpriorityinteger
SRVweightinteger
SRVportinteger
SRVtargetstring

  
SSHFPalgorithminteger
SSHFPtypeinteger
SSHFPfingerprintstring

  
TXTtextstring
- -

RECORD DATA EXAMPLE

- -

Each record is a map that must include all attributes for the data type, the records are stored in the records field of the RecordSet. -The records must be an array of at least one record map. All records in the records array must be of the type stored in the typ field of the RecordSet

- -

Use the @ symbol to point to the zone origin

- -

CNAME records cannot point to the zone origin, thus the RecordSet name cannot be @ nor the zone origin

- -

Individual SSHFP record:

- -
{
-    "type": "SSHFP",
-    "zoneId": "8f8f649f-998e-4428-a029-b4ba5f5bd4ca",
-    "name": "foo",
-    "ttl": 38400,
-    "status": "Active",
-    "created": "2017-02-22T21:34:35Z",
-    "records": [
-        {
-            "algorithm": 1,
-            "type": 3,
-            "fingerprint": "560c7d19d5da9a3a5c7c19992d1fbde15d8dad31"
-        }
-    ],
-    "id": "8306cce4-e16a-4579-9b19-4af46dc75853",
-    "account": "b34f8d18-646f-4843-a80a-7c0d58a22bf5"
-}
-
- -

Multiple SSHFP records:

- -
{
-    "type": "SSHFP",
-    "zoneId": "8f8f649f-998e-4428-a029-b4ba5f5bd4ca",
-    "name": "foo",
-    "ttl": 38400,
-    "status": "Active",
-    "created": "2017-02-22T21:34:35Z",
-    "records": [
-        {
-          "algorithm": 1,
-          "type": 2,
-          "fingerprint": "560c7d19d5da9a3a5c7c19992d1fbde15d8dad31"
-        },
-        {
-          "algorithm": 3,
-          "type": 1,
-          "fingerprint": "160c7d19d5da9a3a5c7c19992d1fbde15d8dad31"
-        },
-        {
-          "algorithm": 4,
-          "type": 1,
-          "fingerprint": "260c7d19d5da9a3a5c7c19992d1fbde15d8dad31"
-        }
-    ],
-    "id": "8306cce4-e16a-4579-9b19-4af46dc75853",
-    "account": "b34f8d18-646f-4843-a80a-7c0d58a22bf5"
-}
-
-
\ No newline at end of file diff --git a/api/reject-batchchange.html b/api/reject-batchchange.html deleted file mode 100644 index c586008ef..000000000 --- a/api/reject-batchchange.html +++ /dev/null @@ -1,211 +0,0 @@ -VinylDNS: Reject Batch Change

Reject Batch Change

- -

Manually rejects a batch change in pending review status given the batch change ID, resulting in immediate failure. Only -system administrators (i.e., support or super user) can manually review a batch change.

- -

Note: If manual review is disabled in the VinylDNS instance, -users trying to access this endpoint will encounter a 404 Not Found response since it will not exist.

- -

HTTP REQUEST

- -
-

POST /zones/batchrecordchanges/{id}/reject

-
- -

HTTP REQUEST PARAMS

- - - - - - - - - - - - - - - - - - - - - - - - -
nametyperequired?description
idstringyesUnique identifier assigned to each created batch change.
reviewCommentstringnoOptional rejection explanation.
- -

EXAMPLE HTTP REQUEST

-
{
-    "reviewComment": "Comments are optional."
-}
-
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - - - - - -
Codedescription
200OK Batch change is rejected and is returned in response body.
400BadRequest Batch change is not in pending approval status.
403Forbidden User is not a system administrator (ie. support or super user).
404NotFound Batch change does not exist.
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
userIdstringThe unique identifier of the user that created the batch change.
userNamestringThe username of the user that created the batch change.
commentsstringConditional: comments about the batch change, if provided.
createdTimestampdate-timeThe timestamp (UTC) when the batch change was created.
changesArray of SingleChangeArray of single changes within a batch change. A SingleChange can either be a SingleAddChange or a SingleDeleteRRSetChange.
statusBatchChangeStatusStatus of the batch change.
idstringThe unique identifier for this batch change.
ownerGroupIdstringConditional: Record ownership assignment, if provided.
approvalStatusBatchChangeApprovalStatusWhether the batch change is currently awaiting manual review. Will be Rejected status when rejecting.
reviewerIdstringUnique identifier for the reviewer of the batch change.
reviewerUserNamestringUser name for the reviewer of the batch change.
reviewCommentstringConditional: Comment from the reviewer of the batch change, if provided.
reviewTimestampdate-timeThe timestamp (UTC) of when the batch change was manually reviewed.
- -

EXAMPLE RESPONSE

- -
{
-    "userId": "vinyl", 
-    "userName": "vinyl201", 
-    "comments": "this is optional", 
-    "createdTimestamp": "2019-07-25T20:22:53Z",
-    "changes": [
-        {
-            "changeType": "Add",
-            "inputName": "reject.parent.com.",
-            "type": "A",
-            "ttl": 7200,
-            "record": {
-                "address": "1.2.3.4"
-            },
-            "status": "Rejected",
-            "recordName": "",
-            "zoneName": "",
-            "zoneId": "",
-            "validationErrors": [
-                {
-                    "errorType": "ZoneDiscoveryError",
-                    "message": "Zone Discovery Failed: zone for \"reject.parent.com.\" does not exist in VinylDNS. If zone exists, then it must be connected to in VinylDNS."
-                }
-            ],
-            "id": "db811a02-5b0f-44ad-8ad9-8ecac7ba6bb4"
-        }
-    ],
-    "status": "Failed",
-    "id": "50e1b48b-80fa-41e0-96ef-72438abc31ec",
-    "ownerGroupId": "159a41c5-e67e-4951-b539-05f5ac788139",
-    "reviewerId": "90c11ffc-5a71-4794-97c6-74d19c81af7d ",
-    "reviewComment": "We can't make *this* change - are you out of your mind?!",
-    "reviewTimestamp": "2019-07-25T20:33:41Z",
-    "approvalStatus": "Rejected"
-}
-
-
\ No newline at end of file diff --git a/api/sync-zone.html b/api/sync-zone.html deleted file mode 100644 index cc22222f0..000000000 --- a/api/sync-zone.html +++ /dev/null @@ -1,148 +0,0 @@ -VinylDNS: Sync Zone

Sync Zone

- -

Used to sync VinylDNS zone info with existing zone info. When a sync is performed, a zone transfer is initiated with the backend DNS server. -The backend data is compared to the existing data in VinylDNS. If there are any differences, the backend DNS Server is considered -the source of truth and will overwrite the data in VinylDNS. All changes will be recorded in VinylDNS so they can be seen in the -zone history.

- -

While the zone is syncing, the zone will be unavailable for updates (read-only).

- -

We have done some testing on how long syncs take. These will vary with usage:

- -
    -
  • 1000 records ~ 1 second
  • -
  • 10,000 records ~ 10 seconds
  • -
  • 100,000 records ~ 6 minutes
  • -
- -

Please keep these numbers in mind when you perform syncs.

- -

HTTP REQUEST

- -
-

POST /zones/{zoneId}/sync

-
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Codedescription
200OK - Successful lookup, the zone is returned in the response body
400Bad Request - invalid sync state, a sync has been performed recently, or zone is inactive
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
403Forbidden - the user does not have the access required to perform the action
404Not Found - Zone not found
409Conflict - Zone has a pending update
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
statusstringSync status
zonemapRefer to zone model
createdstringThe timestamp (UTC) the sync was initiated
changeTypestringType of change requested (Create, Update, Sync, Delete); in this case Sync
userIdstringThe user ID that initiated the change
idstringThe ID of the change. This is not the id of the zone
- -

EXAMPLE RESPONSE

- -
{
-  "status": "Pending",
-  "zone": {
-    "status": "Syncing",
-    "updated": "2016-12-28T19:22:02Z",
-    "name": "sync-test.",
-    "adminGroupId": "cf00d1e4-46f1-493a-a3be-0ae79dd306a5",
-    "created": "2016-12-28T19:22:01Z",
-    "account": "cf00d1e4-46f1-493a-a3be-0ae79dd306a5",
-    "email": "test@test.com",
-    "shared": false,
-    "acl": {
-      "rules": []
-    },
-    "id": "621a13df-a2e3-4394-84c0-3eb3a664dff4"
-  },
-  "created": "2016-12-28T19:22:02Z",
-  "changeType": "Sync",
-  "userId": "ok",
-  "id": "03f1ee91-9053-4346-8b53-e0f6042600f2"
-}
-
-
\ No newline at end of file diff --git a/api/update-group.html b/api/update-group.html deleted file mode 100644 index 8487cc054..000000000 --- a/api/update-group.html +++ /dev/null @@ -1,229 +0,0 @@ -VinylDNS: Update Group

Update Group

- -

Updates a Group in VinylDNS

- -

HTTP REQUEST

- -
-

PUT /groups/{groupId}

-
- -

HTTP REQUEST PARAMS

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametyperequired?description
idstringyesThe ID of the group
namestringyesThe name of the group. Should be one word, use hyphens if needed but no spaces
emailstringyesThe email distribution list for the group
descriptionstringnoA short description of the group, if more info is needed other than the name
createddate-timeyesThe timestamp (UTC) when the group was created
statusstringyesActive or Deleted, should not be changed in an update, a delete request will handle deleting a group
membersArray of User ID objectsyesSet of User IDs in the group
adminsArray of User ID objectsyesSet of User IDs that are admins of the group. All admin user ids should also be in the members array
- -

EXAMPLE HTTP REQUEST

- -
{
-  "id": "6f8afcda-7529-4cad-9f2d-76903f4b1aca",
-  "name": "some-group",
-  "email": "test@example.com",
-  "created": "Thu Mar 02 2017 10:29:21",
-  "status": "Active",
-  "members": [
-    {
-      "id": "4764183c-5e75-4ae6-8833-503cd5f4dcb0"
-    },
-    {
-      "id": "k8630ebc-0af2-4c9a-a0a0-d18c590ed03e"
-    }
-  ],
-  "admins": [
-    {
-      "id": "4764183c-5e75-4ae6-8833-503cd5f4dcb0"
-    }
-  ]
-}
-
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Codedescription
200OK - The group has been updated and the group info is returned in the response body
400Bad Request - The group was invalid or a user id was not found
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
403Forbidden - The user does not have the access required to perform the action
404Not Found - The group was not found
409Conflict - The group already exists
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
idstringUnique UUID of the group
namemapThe name of the group
emailstringThe email distribution list of the group
descriptionstringThe group description, the group will not have this attribute if it was not included in the update request and already did not exist
createdstringThe timestamp (UTC) the group was created
statusstringActive or Deleted, in this case Active
membersArray of User Id objectsIds of members of the group including admins
adminsArray of User Id objectsIds of admins of the group
- -

EXAMPLE RESPONSE

- -
{
-  "id": "6f8afcda-7529-4cad-9f2d-76903f4b1aca",
-  "name": "some-group",
-  "email": "test@example.com",
-  "created": "2017-03-02T15:29:21Z",
-  "status": "Active",
-  "members": [
-    {
-      "id": "2764183c-5e75-4ae6-8833-503cd5f4dcb0"
-    },
-    {
-      "id": "c8630ebc-0af2-4c9a-a0a0-d18c590ed03e"
-    }
-  ],
-  "admins": [
-    {
-      "id": "2764183c-5e75-4ae6-8833-503cd5f4dcb0"
-    }
-  ]
-}
-
-
\ No newline at end of file diff --git a/api/update-recordset.html b/api/update-recordset.html deleted file mode 100644 index ed93dee1a..000000000 --- a/api/update-recordset.html +++ /dev/null @@ -1,264 +0,0 @@ -VinylDNS: Update RecordSet

Update RecordSet

- -

Updates a RecordSet. This performs a delete of the old record, and inserts the new record. -

- -

HTTP REQUEST

- -
-

PUT /zones/{zoneId}/recordsets/{recordSetId}

-
- -

HTTP REQUEST PARAMS

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametyperequired?description
zoneIdstringyesid of the zone where the recordset belongs, this value must match the zoneId of the existing recordSet
idstringyesthe id of the recordset being updated
namestringyesthe name of the recordset being updated
typestringyesthe type of recordset
ttlintegeryesthe TTL in seconds
recordsarray of record datayesrecord data for recordset, see RecordSet Model
ownerGroupIdstringsometimes*Record ownership assignment, applicable if the recordset is in a shared zone
- -

*Note: If a recordset has an ownerGroupId you must include that value in the update request, otherwise the update will remove the ownerGroupId value

- -

EXAMPLE HTTP REQUEST

-
{
-  "id": "dd9c1120-0594-4e61-982e-8ddcbc8b2d21",
-  "name": "already-exists",
-  "type": "A",
-  "ttl": 38400,
-  "records": [
-    {
-      "address": "6.5.4.3"
-    }
-  ],
-  "zoneId": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-  "ownerGroupId": "f42385e4-5675-38c0-b42f-64105e743bfe"
-}
-
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Codedescription
202Accepted - the update is valid and has been accepted for processing; the record set change resource is returned in the response body
400Bad Request - the zone being updated is not active; typically because the connection information does not exist for the zone
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
403Forbidden - The user does not have the access required to perform the action
404Not Found - Zone or RecordSet not found
409Conflict - There is an existing pending change against this record set
422Unprocessable Entity
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
zonemapContains information about the zone when the change was created
recordSetmapContains the recordset model
updatesmapNew data to overwrite current record set
userIdstringThe user id that initiated the change
changeTypestringType of change requested (Create, Update, Delete); in this case Update
createdstringThe timestamp (UTC) the change was initiated
idstringThe ID of the change. This is not the ID of the recordset
statusRecordSetChangeStatusThe status of the change (Pending, Complete, or Failed)
singleBatchChangeIdsarray of SingleBatchChange ID objectsIf the recordset change was part of a batch change, the IDs of the single changes that comprise the recordset change
- -

EXAMPLE RESPONSE

- -
{
-  "zone": {
-    "name": "vinyl.",
-    "email": "test@test.com",
-    "status": "Active",
-    "created": "2017-02-23T14:52:44Z",
-    "updated": "2017-02-23T15:12:33Z",
-    "id": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-    "account": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae",
-    "shared": false,
-    "acl": {
-      "rules": [
-
-      ]
-    },
-    "adminGroupId": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae",
-    "latestSync": "2017-02-23T15:12:33Z"
-  },
-  "recordSet": {
-    "type": "A",
-    "zoneId": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-    "name": "already-exists",
-    "ttl": 38400,
-    "status": "PendingUpdate",
-    "created": "2017-02-23T15:12:41Z",
-    "updated": "2017-02-23T15:12:41Z",
-    "records": [
-      {
-        "address": "6.6.6.1"
-      }
-    ],
-    "id": "dd9c1120-0594-4e61-982e-8ddcbc8b2d21",
-    "account": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae"
-  },
-  "userId": "0215d410-9b7e-4636-89fd-b6b948a06347",
-  "changeType": "Update",
-  "status": "Pending",
-  "created": "2017-02-23T15:12:41Z",
-  "updates": {
-    "type": "A",
-    "zoneId": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-    "name": "already-exists",
-    "ttl": 38400,
-    "status": "Active",
-    "created": "2017-02-23T15:12:33Z",
-    "records": [
-      {
-        "address": "6.6.6.6"
-      }
-    ],
-    "id": "dd9c1120-0594-4e61-982e-8ddcbc8b2d21",
-    "account": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae",
-    "ownerGroupId": "f42385e4-5675-38c0-b42f-64105e743bfe"
-  },
-  "id": "df69bc45-2942-4fb7-813c-4dd21cfad7fa",
-  "singleBatchChangeIds": []
-}
-
-
\ No newline at end of file diff --git a/api/update-zone.html b/api/update-zone.html deleted file mode 100644 index 98ac5d8a2..000000000 --- a/api/update-zone.html +++ /dev/null @@ -1,166 +0,0 @@ -VinylDNS: Update Zone

Update Zone

- -

Updates an existing zone that has already been connected to. Used to update the ACL rules or zone level meta data like the zone connection or email.

- -

HTTP REQUEST

- -
-

PUT /zones/{zoneId}

-
- -

HTTP REQUEST PARAMS

- - - - - - - -
zone fields, refer to zone model
- -

EXAMPLE HTTP REQUEST

- -
{
-  "name": "vinyl.",
-  "email": "update@update.com",
-  "status": "Active",
-  "created": "2017-02-23T14:52:44Z",
-  "updated": "2017-02-23T19:05:33Z",
-  "id": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-  "account": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae",
-  "shared": false,
-  "acl": {
-    "rules": []
-  },
-  "adminGroupId": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae",
-  "latestSync": "2017-02-23T19:05:33Z",
-  "adminGroupName": "test",
-  "hiddenKey": "",
-  "hiddenTransferKey": ""
-}
-
- -

HTTP RESPONSE TYPES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Codedescription
200Accepted - The zone change is returned in the response body
400Bad Request - connection failed
401Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect
403Forbidden - the user does not have the access required to perform the action
404Not Found - Zone not found
409Conflict - Zone has a pending update
- -

HTTP RESPONSE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nametypedescription
zonemapZone sent with update request, refer to zone model
userIdstringThe user id that initiated the change
changeTypestringType of change requested (Create, Update, Sync, Delete); in this case Update
createdstringThe timestamp (UTC) the change was initiated
idstringThe ID of the change. This is not the ID of the zone
statusstringThe status of the zone change
- -

EXAMPLE RESPONSE

- -
{
-  "zone": {
-    "name": "vinyl.",
-    "email": "update@update.com",
-    "status": "Active",
-    "created": "2017-02-23T14:52:44Z",
-    "updated": "2017-02-23T19:23:26Z",
-    "id": "2467dc05-68eb-4498-a9d5-78d24bb0893c",
-    "account": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae",
-    "shared": false,
-    "acl": {
-      "rules": []
-    },
-    "adminGroupId": "9b22b686-54bc-47fb-a8f8-cdc48e6d04ae",
-    "latestSync": "2017-02-23T19:05:33Z"
-  },
-  "userId": "0215d410-9b7e-4636-89fd-b6b948a06347",
-  "changeType": "Update",
-  "status": "Pending",
-  "created": "2017-02-23T19:23:26Z",
-  "id": "d1fcd28d-61fe-4c24-ac0b-4377d66d50db"
-}
-
-
\ No newline at end of file diff --git a/api/zone-model.html b/api/zone-model.html deleted file mode 100644 index 9eb60d16d..000000000 --- a/api/zone-model.html +++ /dev/null @@ -1,414 +0,0 @@ -VinylDNS: Zone Model

Zone Model

- -

Table of Contents

- - - -

ZONE ATTRIBUTES

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
fieldtypedescription
statusstringActive - the zone is connected and ready for use; Syncing - the zone is currently syncing with the DNS backend and is not available until syncing is complete.
updateddate-timeThe last time the zone was changed. Note: this does not include changes to record sets, only the zone entity itself
namestringThe name of the zone
adminGroupIdstringThe id of the administrators group for the zone
createddate-timeThe time when the zone was first created
accountstringDEPRECATED The account that created the zone
emailstringThe distribution email for the zone
backendIdstringOptional. Recommended over connection and transferConnection. The configuration ID of the DNS backend server for the zone. If not provided, default keys will be used unless connection and transfer connection are provided.
connectionZoneConnectionOptional. The connection used to issue DDNS updates to the backend zone. If not provided, default keys will be used unless backendId is provided. See the Zone Connection Attributes for more information
transferConnectionZoneConnectionOptional. The connection that is used to sync the zone with the DNS backend. This can be different than the update connection. If not provided, default keys will be used unless backendId is provided.
sharedbooleanAn indicator that the zone is shared with anyone. At this time only VinylDNS administrators can set this to true.
aclZoneACLThe access control rules governing the zone. See the Zone ACL Rule Attributes for more information
idstringThe unique identifier for this zone
latestSyncdate-timeThe last date and time the zone was synced
isTestbooleanDefaults to false. Used for restricted access during VinylDNS testing, can be ignored by clients
accessLevelstringAccess level of the user requesting the zone. Current levels are Delete (full access), Read and NoAccess.
- -

ZONE EXAMPLE

- -
{
-  "status": "Active",
-  "updated": "2016-12-16T15:27:28Z",
-  "name": "ok.",
-  "adminGroupId": "92b298e8-97db-4f1b-881b-fd08ca0dd311",
-  "created": "2016-12-16T15:27:26Z",
-  "account": "92b298e8-97db-4f1b-881b-fd08ca0dd311",
-  "email": "test@test.com",
-  "connection": {
-    "primaryServer": "127.0.0.1:5301",
-    "keyName": "vinyl.",
-    "name": "ok.",
-    "key": "OBF:1:W1FXgpOjjrQAABAARrZmyLjFSOuFYTAw81mhvNEmNAc4RnYzPjJQMEjVQWWLRohu7gRAVw=="
-  },
-  "transferConnection": {
-    "primaryServer": "127.0.0.1:5301",
-    "keyName": "vinyl.",
-    "name": "ok.",
-    "key": "OBF:1:W1FXgpOjjrQAABAARrZmyLjFSOuFYTAw81mhvNEmNAc4RnYzPjJQMEjVQWWLRohu7gRAVw=="
-  },
-  "shared": false,
-  "acl": {
-    "rules": [
-      {
-        "accessLevel": "Write",
-        "userId": "<uuid>",
-        "description": "some_test_rule",
-        "recordTypes": []
-      },
-      {
-        "recordMask": ".*",
-        "accessLevel": "Write",
-        "userId": "<uuid>",
-        "description": "some_test_rule",
-        "recordTypes": []
-      },
-      {
-        "recordMask": "test.*",
-        "accessLevel": "Read",
-        "groupId": "<uuid>",
-        "description": "some_test_rule",
-        "recordTypes": []
-      }
-    ]
-  },
-  "id": "9cbdd3ac-9752-4d56-9ca0-6a1a14fc5562",
-  "latestSync": "2016-12-16T15:27:26Z",
-  "backendId":"func-test-backend",
-  "accessLevel": "Delete"
-}
-
- -

ZONE ACL RULE ATTRIBUTES

-

ACL Rules are used to govern user and group access to record operations on a zone. ACL Rules can be associated with a specific user, or all users in a specified group. If neither a user or a group is attached to an ACL rule, then the rule applies to all users in the system. -

-Use the Zone Update endpoint to update the acl attribute of the zone

- -
-

Important! If a user is mentioned on an ACL Rule directly, or is a member of a group that is mentioned on an ACL Rule, that user will be able to see the zone.

-
- -
-

Rules made without selecting a group or user will apply to all users in VinylDNS.

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
fieldtypedescription
recordMaskstring(optional) A regular expression that is used to match against record names. If left empty, then all records will be matched for the rule. All records matching the match will be governed by this rule.
recordTypesArray[String]An array of all record types that this rule applies to. If left empty, then all record types will be governed by this rule.
accessLevelstringNoAccess - cannot see the data for the record; Read - can read only the record; Write - the user can create and edit records, but cannot delete them; Delete - the user can read, create, update, and delete records
userIdstring(optional) The unique identifier for the user the rule applies to. Note: this is not the name of the user, but their uuid in VinylDNS
groupIdstring(optional) The unique identifier for the group the rule applies to. Note: you cannot set both the userId and groupId, only one
descriptionstring(optional) A user entered description for the rule
- -

The priority of ACL Rules in descending precedence:

-
    -
  1. Individual rules placed on a user
  2. -
  3. Rules placed on groups that a user is in
  4. -
  5. Rules placed on all users in VinylDNS
  6. -
- -
-

Note: Being in the admin group of a zone will grant users full access regardless of ACL Rules

-
- -

For conflicting rules, the rule that is more specific will take precedence. For example, if the account jdoe201 was given Read access to all records in a zone -through the rule:

- -
{
-  "userId": "<uuid>",
-  "accessLevel": "Read",
-}
-
- -

and then Write access to only A records through the rule:

- -
{
-  "userId": "<uuid>",
-  "accessLevel": "Write",
-  "recordTypes": ["A"]
-}
-
- -

and then Delete access to only A records that matched the expression *dev* through the rule:

- -
{
-  "userId": "<uuid>",
-  "accessLevel": "Delete",
-  "recordTypes": ["A"],
-  "recordMask": "*dev*"
-}
-
- -

then the rule with the recordMask will take precedence and give Delete access to matched A RecordSets, the rule with recordTypes will -take precedence and give Write access to all other A records, and the more broad rule will give Read access to all other record types in the zone

- -

ZONE ACL RULE EXAMPLES

-

Grant read/write/delete access to www.* records of type A, AAAA, CNAME to one user -Under this rule, the user specified will be able to view, create, edit, and delete records in the zone that match the expression www.* and are of type A, AAAA, or CNAME.

- -
{
-  "recordMask": "www.*",
-  "accessLevel": "Delete",
-  "userId": "<uuid>",
-  "recordTypes": ["A", "AAAA", "CNAME"]
-}
-
- -

Grant read only access to all VinylDNS users to A, AAAA, CNAME records

- -
{
-  "accessLevel": "Read",
-  "recordTypes": ["A", "AAAA", "CNAME"]
-}
-
- -

Grant read/write/delete access to records of type A, AAAA, CNAME to one group*

- -
{
-  "accessLevel": "Delete",
-  "groupId": "<uuid>",
-  "recordTypes": ["A", "AAAA", "CNAME"]
-}
-
- -

PTR ACL RULES WITH CIDR MASKS

-

ACL rules can be applied to specific record types and can include record masks to further narrow down which records they -apply to. These record masks apply to record names, but because PTR record names are part their reverse zone ip, the use of regular -expressions for record masks are not supported. -

-Instead PTR record masks must be CIDR rules, which will denote a range of IP addresses that the rule will apply to. -While more information and useful CIDR rule utility tools can be found online, CIDR rules describe how many bits of an ip address’ binary representation -must be the same for a match.

- -

PTR ACL RULES WITH CIDR MASKS EXAMPLE

-

The ACL Rule

- -
{
-    "recordTypes": ["PTR"],
-    "accessLevel": "Read"
-}
-
- -

Will give Read permissions to PTR Record Sets to all users in VinylDNS -

-The IPv4 ACL Rule

- -
{
-    "recordTypes": ["PTR"],
-    "accessLevel": "Read",
-    "recordMask": "100.100.100.100/16"
-}
-
- -

Will give Read permissions to PTR Record Sets 100.100.000.000 to 100.100.255.255, as 16 bits is half of an IPv4 address -

-The IPv6 ACL Rule

- -
{
-    "recordTypes": ["PTR"],
-    "accessLevel": "Read",
-    "recordMask": "1000:1000:1000:1000:1000:1000:1000:1000/64"
-}
-
- -

Will give Read permissions to PTR Record Sets 1000:1000:1000:1000:0000:0000:0000:0000 to 1000:1000:1000:1000:FFFF:FFFF:FFFF:FFFF, as 64 bits is half of an IPv6 address.

- -

ZONE CONNECTION ATTRIBUTES

-

In order for VinylDNS to make updates in DNS, it needs key information for every zone. There are 3 ways to specify that key information; ask your VinylDNS admin which is appropriate for your zone based on the configuration of the service:

- -
    -
  1. Leave connection, transfer connection, and backend ID blank: In this case, the default VinylDNS keys will be used
  2. -
  3. Specify a backend ID on the zone: if multiple backends are configured for your instance of VinylDNS, you can specify a backend ID on the zone and the keys associated with that backend will be used.
  4. -
  5. Specify zone connection and transfer connection on the zone itself: see below for details
  6. -
- -

Note that if both a backend ID and specific connection keys are included on a zone, the specific connection keys will be used.

- -

Zone Connection specifies the connection information to the backend DNS server.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
fieldtypedescription
primaryServerstringThe IP address or host that is connected to. This can take a port as well 127.0.0.1:5300. If no port is specified, 53 will be assumed.
keyNamestringThe name of the DNS key that has access to the DNS server and zone. Note: For the transfer connection, the key must be given allow-transfer access to the zone. For the primary connection, the key must be given allow-update access to the zone.
namestringA user identifier for the connection.
keystringThe TSIG secret key used to sign requests when communicating with the primary server. Note: After creating the zone, the key value itself is hashed and obfuscated, so it will be unusable from a client perspective.
- -

ZONE CONNECTION EXAMPLE

- -
{
-  "primaryServer": "127.0.0.1:5301",
-  "keyName": "vinyl.",
-  "name": "ok.",
-  "key": "OBF:1:W1FXgpOjjrQAABAARrZmyLjFSOuFYTAw81mhvNEmNAc4RnYzPjJQMEjVQWWLRohu7gRAVw=="
-}
-
- -

SHARED ZONES

- -

Shared zones allow for a more open management of records in VinylDNS. Zone administrators can assign ownership of -records to groups. Any user in VinylDNS can claim existing unowned records in shared zones, as well as create records in -those zones. Once a record is owned, only users in the record owner group, the zone administrators and those with -relevant ACL rules can modify or delete the record. The batch change API endpoint -and DNS change area of the portal are where users can create new records in shared zones, -modify records they own, or claim unowned records. If a zone’s shared state changes to false the record ownership access -is no longer applicable.

-
\ No newline at end of file diff --git a/css/custom.css b/css/custom.css deleted file mode 100644 index 1d4299629..000000000 --- a/css/custom.css +++ /dev/null @@ -1,23 +0,0 @@ -.screenshot { - max-width: 100%; - margin-top: 20px; - margin-bottom: 20px; -} - -.jumbotron { - padding-top: 155px; - padding-bottom: 20px; - background-attachment: scroll; - background: url("../img/jumbotron_pattern.png") repeat center; - background-color: #123051; -} - -#masthead { - background-attachment: scroll; - background: url("../img/jumbotron_pattern.png") repeat center; - background-color: #123051; -} - -.important { - color: red; -} diff --git a/css/light-style.css b/css/light-style.css deleted file mode 100644 index 58046c71d..000000000 --- a/css/light-style.css +++ /dev/null @@ -1 +0,0 @@ -@import url("https://fonts.googleapis.com/css?family=Fira+Mono:400,500,700&display=swap");@import url("https://fonts.googleapis.com/css?family=Open+Sans:400,600,700&display=swap");@import url("https://fonts.googleapis.com/css?family=Hind:400,500,600&display=swap");body{margin:0;font-size:15px;color:#333;background:#fff;font-family:"Open Sans",sans-serif}a{color:#009ADA;text-decoration:none}.container{max-width:980px;margin:0 auto;padding:0 24px}h1,h2,h3,h4,h5,h6{font-family:"Hind",sans-serif;position:relative}h1{font-size:2.2rem}h2{font-size:2rem}h3{font-size:1.6rem}h4{font-size:1.3rem}h5{font-size:1.2rem}h6{font-size:1.1rem}@keyframes bg-gradient{0%{background-position:50%}36%{background-position:60%}40%{background-position:80%}50%{background-position:40%}66%{background-position:15%}100%{background-position:50%}}#navigation{background:#fff;padding:16px 0;font-family:"Hind",sans-serif;height:64px;display:flex;flex:0 0 56px}#navigation a{color:#333}#navigation .navbar-wrapper{z-index:20;display:flex;align-items:center;justify-content:space-between;position:relative;width:100%}#navigation .navbar-wrapper .navigation-brand{font-size:18px}#navigation .navbar-wrapper .navigation-brand .brand{display:inline-flex;align-items:center}#navigation .navbar-wrapper .navigation-brand .brand:hover{background:none}#navigation .navbar-wrapper .navigation-brand .brand .icon-wrapper{width:36px;height:36px;margin-right:8px}@keyframes subtle-transition{80%{background-color:#013567}95%{background-color:#333}}#navigation .navbar-wrapper .navigation-brand .brand .brand-title{position:absolute;font-weight:500;white-space:nowrap;left:70px}#navigation .navbar-wrapper .navigation-brand .custom-feature-icon .icon-wrapper{background:url("../img/light-navbar-brand.svg") no-repeat}#navigation .navbar-wrapper .navigation-brand .background-mask .icon-wrapper{-webkit-mask:url("../img/light-navbar-brand.svg") no-repeat;mask:url("../img/light-navbar-brand.svg") no-repeat;background-color:#013567;animation:subtle-transition 6.66s infinite linear}#navigation .navbar-wrapper .navigation-menu>ul>li:not(:first-child){margin-left:24px}#navigation .navbar-wrapper .navigation-menu li{display:inline-block;list-style:none}#navigation .navbar-wrapper .navigation-menu li a span:focus,#navigation .navbar-wrapper .navigation-menu li a span:hover{border-bottom:2px solid}#navigation .navbar-wrapper .navigation-menu li a i:focus,#navigation .navbar-wrapper .navigation-menu li a i:hover{opacity:0.7}#navigation .navbar-wrapper .navigation-menu .nav-item-text+.nav-item-text{margin-left:8px}@media (max-width: 868px){#navigation .navbar-wrapper .navigation-menu .nav-item-text{display:none}}#navigation .navbar-wrapper .navigation-menu .nav-item-icon{display:none}@media (max-width: 868px){#navigation .navbar-wrapper .navigation-menu .nav-item-icon{display:inline-block}}@media (max-width: 868px){#navigation .navbar-wrapper .navigation-menu .search-nav{display:none}}.button{display:block;background:none;border:none;outline:none;text-decoration:none;position:relative}.button:hover{cursor:pointer}.button>img{vertical-align:bottom}.button.link-like{font-size:15px;text-transform:none;color:#333;font-family:"Hind",sans-serif;padding:0}.button.link-like:hover,.button.link-like:focus{text-decoration:none;box-shadow:0 2px #333}.close{height:28px;position:absolute;left:0;top:0;width:32px}.close::after,.close::before{background-color:#fff;content:" ";height:100%;left:98%;position:absolute;top:34%;width:2px}.close::before{transform:rotate(45deg)}.close::after{transform:rotate(-45deg)}#masthead{background:linear-gradient(160deg, transparent 66%, #011e3a 97%),linear-gradient(130deg, #012549, #013567 16%);background-position:center;background-size:200% 100%;animation:bg-gradient 12s ease infinite;color:#fff;flex:1 0 auto;max-height:50%;padding:48px 0;font-family:"Hind",sans-serif;display:flex;flex-direction:row;align-items:center}#masthead .text-center{text-align:center;max-width:750px}#masthead .text-center .masthead-description{font-size:3rem;margin-bottom:56px;font-weight:600}#masthead .masthead-button{text-align:center;color:#fff;padding:11px 40px;border:2px solid #fff;font-weight:600;border-radius:2px;transition:all 350ms ease}#masthead .masthead-button:hover{background-color:#fff;color:#013567}.menu-container{border-bottom:solid 1px rgba(51,51,51,0.1)}#horizontal-menu{display:flex;justify-content:left;max-width:980px;margin:0 auto;padding:0 24px;min-height:44px}#horizontal-menu .horizontal-nav{display:inline-flex;flex-wrap:wrap;list-style:none;margin:0;padding:0}#horizontal-menu .horizontal-nav li{margin-right:32px;padding:10px 0}#horizontal-menu .horizontal-nav li a{padding:10px 0;font-weight:600;color:rgba(51,51,51,0.7);transition:color 0.4ms ease}#horizontal-menu .horizontal-nav li a.active{color:#013567}#horizontal-menu .horizontal-nav li a:hover{color:#333;border-bottom:solid 3px #333}.home{height:100%;display:flex;flex-direction:column}#site-main{background-color:rgba(1,53,103,0.05);font-family:"Open Sans",sans-serif;flex:1 0 auto;display:flex;flex-direction:column;justify-content:center}#site-main.page-site-main{flex:1 0 auto}#site-main .main-content{flex:1 0 auto;padding:48px 0}#site-main a{text-decoration:underline}#site-main a:hover{text-decoration:none}#content p{line-height:22px}#content ul{padding-left:16px}#content ul li{line-height:32px;padding-left:8px}#search-dropdown{position:relative}#search-dropdown .dropdown{display:block;outline:0;width:100%}#search-dropdown label{padding-right:0.3em;font-weight:normal}#search-dropdown label i{padding-right:0.2em}#search-dropdown .dropdown-content{position:absolute;min-width:100px;overflow:hidden auto;box-shadow:0 8px 16px 0 rgba(0,0,0,0.2);z-index:1;background:#fff;margin:0;padding:0;opacity:0.5;transform:rotate3d(1, 0, 0, 90deg);transition:transform ease 250ms, opacity ease 100ms;transform-origin:top}#search-dropdown .dropdown-content .dropdown-item{width:100%;text-align:left}#search-dropdown .dropdown-content .dropdown-item .dropdown-item-link{padding:12px 9px;text-decoration:none;display:block;border-radius:0;color:#333}#search-dropdown .dropdown-content .dropdown-item .dropdown-item-link:hover span{border-bottom:2px solid}#search-dropdown .dropdown-content .dropdown-item .dropdown-item-link:focus span{border-bottom:2px solid}#search-dropdown .show{transform:rotate3d(1, 0, 0, 0);opacity:1}div[id$='version-dropdown']{position:relative}div[id$='version-dropdown'] .dropdown{display:block;outline:0;width:100%}div[id$='version-dropdown'] .dropdown-content{position:absolute;min-width:100px;overflow:hidden auto;box-shadow:0 8px 16px 0 rgba(0,0,0,0.2);z-index:1;background:#fff;margin:0;padding:0;opacity:0.5;transform:rotate3d(1, 0, 0, 90deg);transition:transform ease 250ms, opacity ease 100ms;transform-origin:top}div[id$='version-dropdown'] .dropdown-content .dropdown-item{width:100%}div[id$='version-dropdown'] .dropdown-content .dropdown-item .dropdown-item-link{padding:12px 9px;text-decoration:none;display:block;border-radius:0}div[id$='version-dropdown'] .dropdown-content .dropdown-item .dropdown-item-link:hover span{border-bottom:2px solid}div[id$='version-dropdown'] .show{transform:rotate3d(1, 0, 0, 0);opacity:1}#site-footer{font-family:"Hind",sans-serif;padding:40px 0;font-size:14px}#site-footer .row{margin:0 auto}#site-footer .row p{margin:8px 0}#site-footer .row a{text-decoration:underline}#site-footer .row a:hover{text-decoration:none}@media (max-width: 868px){#site-footer{text-align:center}}.docs{background:rgba(1,53,103,0.05);height:100%;display:flex;flex-direction:column}.docs #wrapper{padding-left:290px;transition:padding-left 0.5s ease}.docs #wrapper.toggled{padding-left:0}.docs #wrapper.toggled #sidebar-wrapper{left:-290px}.docs #page-content-wrapper #content .content-wrapper a{text-decoration:underline}.docs #page-content-wrapper #content .content-wrapper a:hover{text-decoration:none}.docs #sidebar-wrapper{background-image:linear-gradient(to bottom, #013567 60%, #012549 100%);z-index:1000;position:fixed;left:0;height:100%;width:290px;overflow:hidden hidden;transition:left 0.5s ease}.docs #sidebar-wrapper:hover{overflow:hidden auto}.docs #sidebar-wrapper .sidebar-toggle{display:none}.docs #sidebar-wrapper #sidebar-brand{padding:12px 24px;font-family:"Hind",sans-serif;font-size:18px;height:64px;display:flex;justify-content:space-between;align-items:center;background-color:#013a71}.docs #sidebar-wrapper #sidebar-brand a{display:inline-flex;align-items:center;color:#fff}.docs #sidebar-wrapper #sidebar-brand a .brand-wrapper{position:relative;width:36px;height:36px;background:url("../img/light-sidebar-brand.svg") no-repeat}.docs #sidebar-wrapper #sidebar-brand a span{z-index:30;white-space:nowrap;position:absolute;left:70px;font-weight:500}.docs #sidebar-wrapper .sidebar-nav{margin-top:16px;padding:0}.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item{display:flex;flex-direction:column;position:relative}.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item .sub-section{background:#013a71;max-height:0;transition:max-height 0.3s ease-in-out;overflow:hidden}.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item .sub-section a{display:flex;justify-content:flex-start;align-items:center;padding:16px 32px;font-size:0.875rem;height:auto}.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item .sub-section a.active{color:#fff;box-shadow:3px 0 #009ADA inset}.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item a,.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item button{box-sizing:border-box;font-family:"Open Sans", sans-serif;font-size:0.95rem;display:flex;justify-content:space-between;align-items:center;padding:16px 24px;line-height:16px;width:100%;transition:background 0.33s ease-in-out}.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item a,.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item button{color:#fff}.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item a:visited,.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item button:visited{color:#fff}.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item a:hover,.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item button:hover{color:rgba(255,255,255,0.8)}.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item a:active,.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item a:focus,.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item button:active,.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item button:focus{color:#fff}.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item a:hover,.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item button:hover{text-decoration:none}.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item .fa{pointer-events:none;position:absolute;color:#fff;font-size:1.2rem;right:16px;top:16px;transition:transform 0.25s;line-height:16px}.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item.active>a,.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item.active button{box-shadow:3px 0 #009ADA inset}.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item.open>a,.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item.open button{background:#013f7b}.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item.open .fa{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg)}.docs #sidebar-wrapper .sidebar-nav .sidebar-nav-item.open .sub-section{max-height:1600px}.docs #page-content-wrapper{width:100%}.docs #page-content-wrapper .nav{background:#fff}.docs #page-content-wrapper .nav .action-menu a{font-size:24px;padding:0 4px}.docs #page-content-wrapper .nav .action-menu a:hover{transform:scaleX(1.5)}.docs #page-content-wrapper .nav .col-lg-12{padding:12px 24px;display:flex;justify-content:space-between;align-items:center;height:64px}.docs #page-content-wrapper .nav a:not(.dropdown-item-link){color:#013567;padding:0 16px;display:block;font-size:16px;transition:color 0.25s ease, transform 0.25s ease}.docs #page-content-wrapper .nav a:not(.dropdown-item-link):hover{color:#013f7b}.docs #page-content-wrapper .nav ul{padding:0;margin:0}@media (max-width: 530px){.docs #page-content-wrapper .nav ul .search-nav{display:none !important}}.docs #page-content-wrapper .nav ul li{list-style:none;display:inline-block}.docs #page-content-wrapper .nav ul li span:not(.dropdown-item-link-text){display:inline-flex;flex-direction:row-reverse;font-size:14px}.docs #page-content-wrapper .nav ul li .label{margin:0 8px;font-weight:bold;color:#013567}.docs #page-content-wrapper section{background:#fff;margin:24px;border-radius:2px;padding:32px}.docs #page-content-wrapper section a:focus,.docs #page-content-wrapper section a:hover{text-decoration:none}.docs #page-content-wrapper section a:focus{outline:0}.docs #page-content-wrapper section code{padding:2px 4px;border-radius:2px}.docs #page-content-wrapper section pre{padding:0;font-size:13px;margin-top:20px}.docs #page-content-wrapper section pre code{font-family:"Fira Mono",monospace;font-size:inherit;white-space:pre-wrap;border-radius:2px;border:solid 1px rgba(1,1,1,0.2)}.docs #page-content-wrapper section pre .hljs{padding:24px}.docs #page-content-wrapper section .hljs-addition,.docs #page-content-wrapper section .hljs-meta,.docs #page-content-wrapper section .hljs-string,.docs #page-content-wrapper section .hljs-symbol,.docs #page-content-wrapper section .hljs-template-tag,.docs #page-content-wrapper section .hljs-template-variable{line-height:24px}.docs #page-content-wrapper .header-link{position:absolute;font-size:0.6em;left:-2em;top:-0.05em;opacity:0;padding:0.8em;transform:scale3d(0.5, 0.5, 0.5);transition:opacity 0.2s ease, transform 0.2s ease}.docs #page-content-wrapper .header-link .fa{transform:rotate3d(0, 0, 1, 135deg)}.docs #page-content-wrapper h1:hover .header-link,.docs #page-content-wrapper h2:hover .header-link,.docs #page-content-wrapper h3:hover .header-link,.docs #page-content-wrapper h4:hover .header-link,.docs #page-content-wrapper h5:hover .header-link,.docs #page-content-wrapper h6:hover .header-link{opacity:1;transform:scale3d(1, 1, 1)}.docs .sidebar-toggle{background:none;border:none;color:rgba(1,53,103,0.05);display:inline-block;padding:24px 32px;position:relative;text-align:center;text-decoration:none;transition:color 0.3s ease, transform 0.3s ease}.docs .sidebar-toggle .menu-icon{position:absolute;top:37%;left:38%}.docs .sidebar-toggle:hover{color:#fff;cursor:pointer}@media (max-width: 868px){.docs #wrapper{padding-left:0;transition:padding-left 0.4s ease}.docs #sidebar-wrapper{left:-100%}.docs #wrapper.toggled #sidebar-wrapper{left:0;width:100%;overflow-y:auto}.docs #wrapper.toggled #sidebar-wrapper .sidebar-toggle{display:block;opacity:0.7;transition:opacity 0.3s ease, transform 0.3s ease}.docs #wrapper.toggled #sidebar-wrapper .sidebar-toggle:hover{opacity:1;transform:rotate(-180deg)}.docs #wrapper.toggled #page-content-wrapper{height:100vh;overflow:hidden}}code[class="highlighter-rouge"]{background-color:rgba(1,53,103,0.1)}.page{height:100%;display:flex;flex-direction:column}.page #navigation{background:linear-gradient(160deg, transparent 66%, #011e3a 97%),linear-gradient(130deg, #012549, #013567 16%);background-position:center;background-size:200% 100%;animation:bg-gradient 12s ease infinite}.page #navigation a{color:#fff}.page #navigation button.link-like{color:#fff}.page #navigation button.link-like:hover,.page #navigation button.link-like:focus{box-shadow:0 2px #fff}.page #navigation .dropdown-content{background:#013567}.page #navigation .page-icon-wrapper{width:36px;height:36px;background:url("../img/light-sidebar-brand.svg") no-repeat;margin-right:8px}.page-site-main{padding:40px 0}.page-site-main .use{flex:1 1 auto}.features-masthead{padding:130px 0}.features-image{width:49%;height:100%;background:url("../img/features-header.svg") no-repeat;background-size:contain;background-position:center;position:absolute;top:0;right:0}.feature-header{display:flex;align-items:center;justify-content:space-between;height:100%;width:100%;position:relative}.feature-header .features-header-description{display:flex;flex-direction:column}.feature-header .features-header-description .masthead-title{font-size:3.5rem;font-weight:600;margin:0}.feature-header .features-header-description .masthead-description{font-size:1.65rem;margin:0 0 10px 0}.feature-header .features-header-description .masthead-button{text-align:center;width:106px;margin-top:16px}.features-header-description{max-width:49%}.features{display:flex;padding:100px 0}.features .feature-item{flex:1;align-items:center;text-align:center;min-height:240px;margin-right:40px;display:flex;flex-direction:column;justify-content:space-between;color:#333}.features .feature-item h4,.features .feature-item p{margin:8px 0 0 0}.features .feature-item:last-child{margin-right:0}.features .feature-item .first-feature-icon-wrapper,.features .feature-item .fourth-feature-icon-wrapper,.features .feature-item .second-feature-icon-wrapper,.features .feature-item .third-feature-icon-wrapper{margin-top:0;width:56px;min-height:56px;padding-bottom:8px}@keyframes subtle-transition{80%{background-color:#013567}95%{background-color:#333}}.features .feature-item .background-mask .first-feature-icon-wrapper{-webkit-mask:url("../img/first-feature-icon.svg") no-repeat;mask:url("../img/first-feature-icon.svg") no-repeat;background-color:#013567;animation:subtle-transition 6.66s infinite linear}.features .feature-item .background-mask .second-feature-icon-wrapper{-webkit-mask:url("../img/second-feature-icon.svg") no-repeat;mask:url("../img/second-feature-icon.svg") no-repeat;background-color:#013567;animation:subtle-transition 6.66s infinite linear}.features .feature-item .background-mask .third-feature-icon-wrapper{-webkit-mask:url("../img/third-feature-icon.svg") no-repeat;mask:url("../img/third-feature-icon.svg") no-repeat;background-color:#013567;animation:subtle-transition 6.66s infinite linear}.features .feature-item .custom-feature-icon .first-feature-icon-wrapper{background:url("../img/first-feature-icon.svg") no-repeat}.features .feature-item .custom-feature-icon .second-feature-icon-wrapper{background:url("../img/second-feature-icon.svg") no-repeat}.features .feature-item .custom-feature-icon .third-feature-icon-wrapper{background:url("../img/third-feature-icon.svg") no-repeat}.features .feature-item .feature-item-header{display:flex;flex-direction:column;align-items:center;flex:1 0 auto}#site-main .learn-more-button{padding:6px 24px;font-size:14px;color:#013567;border:2px solid #013567;font-weight:600;border-radius:2px;transition:all 350ms ease;width:80px;text-decoration:none;margin-top:16px}#site-main .learn-more-button:hover{background-color:#013567;color:#fff}@media (max-width: 868px){.feature-header{justify-content:center;text-align:center;padding:0}.feature-header .features-image{display:none}.feature-header .features-header-description{max-width:100%;align-items:center;padding:48px 0}.feature-header .features-header-description .masthead-title{font-size:2rem}.feature-header .features-header-description .masthead-description{font-size:1.25rem}.features{flex-direction:column;padding:0}.features .feature-item{min-height:220px;width:80%;margin:48px auto}.features .feature-item:last-child{margin-right:auto}}table{background-color:rgba(0,0,0,0);border:1px solid #DDD;border-collapse:collapse}table>tbody>tr>td,table>tbody>tr>th,table>thead>tr>td,table>thead>tr>th,table>tfoot>tr>td,table>tfoot>tr>th{border:1px solid #DDD;padding:8px;text-align:left}caption{padding-top:8px;padding-bottom:8px;color:#E3E2E3;text-align:left}th{text-align:left}.table{width:100%;max-width:100%;margin-bottom:20px}.table>tbody>tr>td,.table>tbody>tr>th,.table>thead>tr>td,.table>thead>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #DDD}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #DDD}.table>colgroup+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>td,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>caption+thead>tr:first-child>th{border-top:0}.table>tbody+tbody{border-top:2px solid #DDD}.table .table{background-color:#fff}.table-condensed>tbody>tr>td,.table-condensed>tbody>tr>th,.table-condensed>thead>tr>td,.table-condensed>thead>tr>th,.table-condensed>tfoot>tr>td,.table-condensed>tfoot>tr>th{padding:5px}.table-bordered{border:1px solid #DDD}.table-bordered>tbody>tr>td,.table-bordered>tbody>tr>th,.table-bordered>thead>tr>td,.table-bordered>thead>tr>th,.table-bordered>tfoot>tr>td,.table-bordered>tfoot>tr>th{border:1px solid #DDD}.table-bordered>thead>tr>td,.table-bordered>thead>tr>th{border-bottom-width:2px}.table-striped>tbody>tr:nth-of-type(odd){background-color:#F9F9F9}.table-hover>tbody>tr:hover{background-color:#f5f5f5}table col[class*="col-"]{position:static;float:none;display:table-column}table td[class*="col-"],table th[class*="col-"]{position:static;float:none;display:table-cell}.table>thead>tr>td.active,.table>thead>tr>th.active,.table>thead>tr.active>td,.table>thead>tr.active>th,.table>tbody>tr>td.active,.table>tbody>tr>th.active,.table>tbody>tr.active>td,.table>tbody>tr.active>th,.table>tfoot>tr>td.active,.table>tfoot>tr>th.active,.table>tfoot>tr.active>td,.table>tfoot>tr.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>td.active:hover,.table-hover>tbody>tr>th.active:hover,.table-hover>tbody>tr.active:hover>td,.table-hover>tbody>tr:hover>.active,.table-hover>tbody>tr.active:hover>th{background-color:#e8e8e8}.table>thead>tr>td.success,.table>thead>tr>th.success,.table>thead>tr.success>td,.table>thead>tr.success>th,.table>tbody>tr>td.success,.table>tbody>tr>th.success,.table>tbody>tr.success>td,.table>tbody>tr.success>th,.table>tfoot>tr>td.success,.table>tfoot>tr>th.success,.table>tfoot>tr.success>td,.table>tfoot>tr.success>th{background-color:#dff0d8}.table-hover>tbody>tr>td.success:hover,.table-hover>tbody>tr>th.success:hover,.table-hover>tbody>tr.success:hover>td,.table-hover>tbody>tr:hover>.success,.table-hover>tbody>tr.success:hover>th{background-color:#d0e9c6}.table>thead>tr>td.info,.table>thead>tr>th.info,.table>thead>tr.info>td,.table>thead>tr.info>th,.table>tbody>tr>td.info,.table>tbody>tr>th.info,.table>tbody>tr.info>td,.table>tbody>tr.info>th,.table>tfoot>tr>td.info,.table>tfoot>tr>th.info,.table>tfoot>tr.info>td,.table>tfoot>tr.info>th{background-color:#d9edf7}.table-hover>tbody>tr>td.info:hover,.table-hover>tbody>tr>th.info:hover,.table-hover>tbody>tr.info:hover>td,.table-hover>tbody>tr:hover>.info,.table-hover>tbody>tr.info:hover>th{background-color:#c4e3f3}.table>thead>tr>td.warning,.table>thead>tr>th.warning,.table>thead>tr.warning>td,.table>thead>tr.warning>th,.table>tbody>tr>td.warning,.table>tbody>tr>th.warning,.table>tbody>tr.warning>td,.table>tbody>tr.warning>th,.table>tfoot>tr>td.warning,.table>tfoot>tr>th.warning,.table>tfoot>tr.warning>td,.table>tfoot>tr.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>td.warning:hover,.table-hover>tbody>tr>th.warning:hover,.table-hover>tbody>tr.warning:hover>td,.table-hover>tbody>tr:hover>.warning,.table-hover>tbody>tr.warning:hover>th{background-color:#faf2cc}.table>thead>tr>td.danger,.table>thead>tr>th.danger,.table>thead>tr.danger>td,.table>thead>tr.danger>th,.table>tbody>tr>td.danger,.table>tbody>tr>th.danger,.table>tbody>tr.danger>td,.table>tbody>tr.danger>th,.table>tfoot>tr>td.danger,.table>tfoot>tr>th.danger,.table>tfoot>tr.danger>td,.table>tfoot>tr.danger>th{background-color:#f2dede}.table-hover>tbody>tr>td.danger:hover,.table-hover>tbody>tr>th.danger:hover,.table-hover>tbody>tr.danger:hover>td,.table-hover>tbody>tr:hover>.danger,.table-hover>tbody>tr.danger:hover>th{background-color:#ebcccc}.table-responsive{overflow-x:auto;min-height:0.01%}@media screen and (max-width: 768px){.table-responsive{width:100%;margin-bottom:15px;overflow-y:hidden;-ms-overflow-style:-ms-autohiding-scrollbar;border:1px solid #DDD}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>thead>tr>th,.table-responsive>.table>tfoot>tr>td,.table-responsive>.table>tfoot>tr>th{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child{border-left:0}.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child{border-right:0}.table-responsive>.table-bordered>tfoot>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tbody>tr:last-child>th{border-bottom:0}} diff --git a/extra_md/contributing.html b/extra_md/contributing.html deleted file mode 100644 index ba526a0e4..000000000 --- a/extra_md/contributing.html +++ /dev/null @@ -1,256 +0,0 @@ -VinylDNS: Contributing

Contributing to VinylDNS

- -

The following are a set of guidelines for contributing to VinylDNS and its associated repositories.

- -

Table of Contents

- - - -

Code of Conduct

- -

This project and everyone participating in it are governed by the VinylDNS Code Of Conduct. By -participating, you agree to this Code.

- -

Issues

- -

Work on VinylDNS is tracked by GitHub Issues. To contribute to VinylDNS, -you can join the discussion on an issue, submit a Pull Request to resolve the issue, or make an issue of your own. -VinylDNS issues are generally labeled as bug reports, feature requests, or maintenance requests.

- -

Working on an Issue

- -

If you would like to contribute to VinylDNS, you can look through good first issue and help wanted issues. We keep a -list of these issues around to encourage participation in building the platform. In the issue list, you can chose “ -Labels” and choose a specific label to narrow down the issues to review.

- -
    -
  • Beginner issues: only require a few lines of code to complete, rather isolated to one or two files. A good way to -get through changing and testing your code, and meet everyone!
  • -
  • Help wanted issues: these are more involved than beginner issues, are items that tend to come near the top of our -backlog but not necessarily in the current development stream.
  • -
- -

Besides those issues, you can sort the issue list by number of comments to find one that may be of interest. You do -not have to limit yourself to only good first issue or help wanted issues.

- -

When resolving an issue, you generally will do so by making a Pull Request, and adding a link to the -issue.

- -

Before choosing an issue, see if anyone is assigned or has indicated they are working on it (either in comment or via -Pull Request). If that is the case, then instead of making a Pull Request of your own, you can help out by reviewing -their Pull Request.

- -

Submitting an Issue

- -

When submitting an issue you will notice there are three issue templates to choose from. Before making any issue, please -go search the issue list (open and closed issues) and check to see if a similar issue has been made. If so, we ask that -you do not duplicate an issue, but feel free to comment on the existing issue with additional details.

- -
    -
  • Bug report: If you find a bug in the project you can report it with this template and the VinylDNS team will take -a look at it. Please be as detailed as possible as it will help us recreate the bug and figure out what exactly is -going on. If you are unsure whether what you found is a bug, we encourage you to first pop in -our discussion board, and we can help determine if what you’re -seeing is unexpected behavior, and if it is we will direct to make the bug report.
  • -
  • Feature request: Use this template if you have something you wish to be added to the project. Please be detailed -when describing why you are requesting the feature, what you want it to do, and alternative solutions you have -considered.
  • -
- -

Discussion Process

- -

Some issues may require discussion with the community before proceeding to implementation. This can happen if the issue -is a larger change, for example a big refactoring or new feature. The VinylDNS maintainers may label an issue for ** -Discussion** in order to solicit more detail before proceeding. If the issue is straightforward and/or well documented, -it can be implemented immediately by the submitter. If the submitter is unable to make the changes required to address -the issue, the VinylDNS maintainers will prioritize the work in our backlog.

- -

Pull Requests

- -

Contributions to VinylDNS are generally made -via Github Pull Requests. Most Pull Requests are related to -an issue, and will have a link to the issue in the Pull Request.

- -

General Flow

- -

We follow the standard GitHub Flow for taking code contributions. The following is the process typically followed:

- -
    -
  1. Create a fork of the repository that you want to contribute code to
  2. -
  3. Clone your forked repository to your local machine
  4. -
  5. In your local machine, add a remote to the “main” repository, we call this “upstream” by running -git remote add upstream https://github.com/vinyldns/vinyldns.git. Note: you can also use ssh instead of https
  6. -
  7. Create a local branch for your work git checkout -b your-user-name/user-branch-name. Add whatever your GitHub user -name is before whatever you want your branch to be.
  8. -
  9. Begin working on your local branch
  10. -
  11. Be sure to add necessary unit, integration, and functional tests, see -the Testing -section of the Developer Guide.
  12. -
  13. Make sure you run all builds before posting a Pull Request! It’s faster to run everything locally rather than waiting -for the build server to complete its job. -See DEVELOPER_GUIDE.md for information on -local development.
  14. -
  15. When you are ready to contribute your code, run git push origin your-user-name/user-branch-name to push your -changes to your own fork
  16. -
  17. Go to the VinylDNS main repository (or whatever repo you are contributing -to) -and you will see your change waiting and a link to “Create a Pull Request”. Click the link to create a Pull Request.
  18. -
  19. Be as detailed as possible in the description of your Pull Request. Describe what you changed, why you changed it, -and give a detailed list of changes and impacted files. If your Pull Request is related to an existing issue, be sure -to link the issue in the Pull Request itself, in addition to the Pull Request description.
  20. -
  21. You will receive comments on your Pull Request. Use the Pull Request as a dialog on your changes.
  22. -
- -

Pull Request Requirements

- -

Commit Messages

- -
    -
  • Limit the first line to 72 characters or fewer.
  • -
  • Use the present tense (“Add validation” not “Added validation”).
  • -
  • Use the imperative mood (“Move database call” not “Moves database call”).
  • -
  • Reference issues and other pull requests liberally after the first line. -Use GitHub Auto Linking -to link your Pull Request to other issues.
  • -
  • Use markdown syntax as much as you want
  • -
- -

Testing

- -

When making changes to the VinylDNS codebase, be sure to add necessary unit, integration, and functional tests. For -specifics on our tests, see the Testing -section of the Developer Guide.

- -

Documentation Edits

- -

Documentation for the VinylDNS project lives in files such as this one in the root of the project directory, as well as -in modules/docs/src/main/mdoc for the docs you see on vinyldns.io. Many changes, such as those -that impact an API endpoint, config, portal usage, etc, will also need corresponding documentation edited to prevent it -from going stale. The -VinylDNS gh-pages branch README has -information on how to run and edit the documentation page.

- -

Style Guides

- -
    -
  • For Scala code we use Scalastyle. The configs are scalastyle-config.xml and -scalastyle-test-config.xml for source code and test code respectively -
      -
    • We have it set to fail builds if the styling rules are not followed. For example, one of our rules is that all -lines must be <= 120 characters, and a build will fail if that is violated.
    • -
    -
  • -
  • For our python code that we use for functional testing, we generally try to -follow PEP 8
  • -
- -

License Header Checks

- -

VinylDNS is configured with sbt-header. All existing scala files have the -appropriate header. To add or check for headers, follow these steps:

- -
API
- -

You can check for headers in the API in sbt with:

- -
> ;project api;headerCheck;test:headerCheck;it:headerCheck
-
- -

If you add a new file, you can add the appropriate header in sbt with:

- -
> ;project api;headerCreate;test:headerCreate;it:headerCreate
-
- -
Portal
- -

You can check for headers in the Portal in sbt with:

- -
> ;project portal;headerCheck;test:headerCheck;checkJsHeaders
-
- -

If you add a new file, you can add the appropriate header in sbt with:

- -
> ;project portal;headerCreate;test:headerCreate;createJsHeaders
-
- -

Contributor License Agreement

- -

Before Comcast merges your code into the project you must sign the -Comcast Contributor License Agreement (CLA).

- -

If you haven’t previously signed a Comcast CLA, you’ll automatically be asked to when you open a pull request. -Alternatively, we can send you a PDF that you can sign and scan back to us. Please create a new GitHub issue to request -a PDF version of the CLA.

- -

Modifying your Pull Requests

- -

Often times, you will need to make revisions to your Pull Requests that you submit. This is part of the standard process -of code review. There are different ways that you can make revisions, but the following process is pretty standard.

- -
    -
  1. Sync with upstream -first. git checkout master && git fetch upstream && git rebase upstream master && git push origin master
  2. -
  3. Checkout your branch on your local git checkout your-user-name/user-branch-name
  4. -
  5. Sync your branch with latest git rebase master. Note: If you have merge conflicts, you will have to resolve them
  6. -
  7. Revise your Pull Request, making changes recommended in the comments / code review
  8. -
  9. Stage and commit these changes on top of your existing commits
  10. -
  11. When all tests pass, git push origin your-user-name/user-branch-name to revise your commit. Note: If you rebased -or altered the commit history, you will have to force push with a -f flag. GitHub automatically recognizes the -update and will re-run verification on your Pull Request!
  12. -
- -

Pull Request Approval

- -

A pull request must satisfy our pull request requirements

- -

Afterwards, if a Pull Request is approved, a maintainer of the project will merge it. If you are a maintainer, you can -merge your Pull Request once you have the approval of at least 2 other maintainers.

- -
-

Note: The first time you make a Pull Request, add yourself to the authors list here as part of the Pull Request

-
- -
\ No newline at end of file diff --git a/highlight/LICENSE b/highlight/LICENSE deleted file mode 100644 index 2250cc7ec..000000000 --- a/highlight/LICENSE +++ /dev/null @@ -1,29 +0,0 @@ -BSD 3-Clause License - -Copyright (c) 2006, Ivan Sagalaev. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/highlight/highlight.pack.js b/highlight/highlight.pack.js deleted file mode 100644 index d826a4355..000000000 --- a/highlight/highlight.pack.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! highlight.js v9.16.2 | BSD3 License | git.io/hljslicense */ -!function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"==typeof exports||exports.nodeType?n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs})):e(exports)}(function(a){var f=[],i=Object.keys,b={},u={},n=/^(no-?highlight|plain|text)$/i,l=/\blang(?:uage)?-([\w-]+)\b/i,t=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,r={case_insensitive:"cI",lexemes:"l",contains:"c",keywords:"k",subLanguage:"sL",className:"cN",begin:"b",beginKeywords:"bK",end:"e",endsWithParent:"eW",illegal:"i",excludeBegin:"eB",excludeEnd:"eE",returnBegin:"rB",returnEnd:"rE",variants:"v",IDENT_RE:"IR",UNDERSCORE_IDENT_RE:"UIR",NUMBER_RE:"NR",C_NUMBER_RE:"CNR",BINARY_NUMBER_RE:"BNR",RE_STARTERS_RE:"RSR",BACKSLASH_ESCAPE:"BE",APOS_STRING_MODE:"ASM",QUOTE_STRING_MODE:"QSM",PHRASAL_WORDS_MODE:"PWM",C_LINE_COMMENT_MODE:"CLCM",C_BLOCK_COMMENT_MODE:"CBCM",HASH_COMMENT_MODE:"HCM",NUMBER_MODE:"NM",C_NUMBER_MODE:"CNM",BINARY_NUMBER_MODE:"BNM",CSS_NUMBER_MODE:"CSSNM",REGEXP_MODE:"RM",TITLE_MODE:"TM",UNDERSCORE_TITLE_MODE:"UTM",COMMENT:"C",beginRe:"bR",endRe:"eR",illegalRe:"iR",lexemesRe:"lR",terminators:"t",terminator_end:"tE"},_="",m={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0},c="of and for in not or if then".split(" ");function C(e){return e.replace(/&/g,"&").replace(//g,">")}function E(e){return e.nodeName.toLowerCase()}function o(e){return n.test(e)}function s(e){var n,t={},r=Array.prototype.slice.call(arguments,1);for(n in e)t[n]=e[n];return r.forEach(function(e){for(n in e)t[n]=e[n]}),t}function g(e){var a=[];return function e(n,t){for(var r=n.firstChild;r;r=r.nextSibling)3===r.nodeType?t+=r.nodeValue.length:1===r.nodeType&&(a.push({event:"start",offset:t,node:r}),t=e(r,t),E(r).match(/br|hr|img|input/)||a.push({event:"stop",offset:t,node:r}));return t}(e,0),a}function d(e,n,t){var r=0,a="",i=[];function c(){return e.length&&n.length?e[0].offset!==n[0].offset?e[0].offset"}function l(e){a+=""}function o(e){("start"===e.event?u:l)(e.node)}for(;e.length||n.length;){var s=c();if(a+=C(t.substring(r,s[0].offset)),r=s[0].offset,s===e){for(i.reverse().forEach(l);o(s.splice(0,1)[0]),(s=c())===e&&s.length&&s[0].offset===r;);i.reverse().forEach(u)}else"start"===s[0].event?i.push(s[0].node):i.pop(),o(s.splice(0,1)[0])}return a+C(t.substr(r))}function R(n){return n.v&&!n.cached_variants&&(n.cached_variants=n.v.map(function(e){return s(n,{v:null},e)})),n.cached_variants?n.cached_variants:function e(n){return!!n&&(n.eW||e(n.starts))}(n)?[s(n,{starts:n.starts?s(n.starts):null})]:[n]}function v(e){if(r&&!e.langApiRestored){for(var n in e.langApiRestored=!0,r)e[n]&&(e[r[n]]=e[n]);(e.c||[]).concat(e.v||[]).forEach(v)}}function p(n,r){var a={};return"string"==typeof n?t("keyword",n):i(n).forEach(function(e){t(e,n[e])}),a;function t(t,e){r&&(e=e.toLowerCase()),e.split(" ").forEach(function(e){var n=e.split("|");a[n[0]]=[t,function(e,n){return n?Number(n):function(e){return-1!=c.indexOf(e.toLowerCase())}(e)?0:1}(n[0],n[1])]})}}function O(r){function s(e){return e&&e.source||e}function f(e,n){return new RegExp(s(e),"m"+(r.cI?"i":"")+(n?"g":""))}function a(a){var i,e,c={},u=[],l={},t=1;function n(e,n){c[t]=e,u.push([e,n]),t+=function(e){return new RegExp(e.toString()+"|").exec("").length-1}(n)+1}for(var r=0;r')+n+(t?"":_)}function l(){R+=null!=g.sL?function(){var e="string"==typeof g.sL;if(e&&!b[g.sL])return C(v);var n=e?x(g.sL,v,!0,d[g.sL]):B(v,g.sL.length?g.sL:void 0);return 0")+'"');if("end"===n.type){var r=function(e){var n=e[0],t=c(g,n);if(t){var r=g;for(r.skip?v+=n:(r.rE||r.eE||(v+=n),l(),r.eE&&(v=n));g.cN&&(R+=_),g.skip||g.sL||(p+=g.relevance),(g=g.parent)!==t.parent;);return t.starts&&(t.endSameAsBegin&&(t.starts.eR=t.eR),o(t.starts)),r.rE?0:n.length}}(n);if(null!=r)return r}return v+=t,t.length}var E=S(e);if(!E)throw new Error('Unknown language: "'+e+'"');O(E);var r,g=n||E,d={},R="";for(r=g;r!==E;r=r.parent)r.cN&&(R=u(r.cN,"",!0)+R);var v="",p=0;try{for(var M,N,h=0;g.t.lastIndex=h,M=g.t.exec(a);)N=t(a.substring(h,M.index),M),h=M.index+N;for(t(a.substr(h)),r=g;r.parent;r=r.parent)r.cN&&(R+=_);return{relevance:p,value:R,i:!1,language:e,top:g}}catch(e){if(e.message&&-1!==e.message.indexOf("Illegal"))return{i:!0,relevance:0,value:C(a)};throw e}}function B(t,e){e=e||m.languages||i(b);var r={relevance:0,value:C(t)},a=r;return e.filter(S).filter(T).forEach(function(e){var n=x(e,t,!1);n.language=e,n.relevance>a.relevance&&(a=n),n.relevance>r.relevance&&(a=r,r=n)}),a.language&&(r.second_best=a),r}function M(e){return m.tabReplace||m.useBR?e.replace(t,function(e,n){return m.useBR&&"\n"===e?"
":m.tabReplace?n.replace(/\t/g,m.tabReplace):""}):e}function N(e){var n,t,r,a,i,c=function(e){var n,t,r,a,i=e.className+" ";if(i+=e.parentNode?e.parentNode.className:"",t=l.exec(i))return S(t[1])?t[1]:"no-highlight";for(n=0,r=(i=i.split(/\s+/)).length;n/g,"\n"):n=e,i=n.textContent,r=c?x(c,i,!0):B(i),(t=g(n)).length&&((a=document.createElementNS("http://www.w3.org/1999/xhtml","div")).innerHTML=r.value,r.value=d(t,g(a),i)),r.value=M(r.value),e.innerHTML=r.value,e.className=function(e,n,t){var r=n?u[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}(e.className,c,r.language),e.result={language:r.language,re:r.relevance},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.relevance}))}function h(){if(!h.called){h.called=!0;var e=document.querySelectorAll("pre code");f.forEach.call(e,N)}}function S(e){return e=(e||"").toLowerCase(),b[e]||b[u[e]]}function T(e){var n=S(e);return n&&!n.disableAutodetect}return a.highlight=x,a.highlightAuto=B,a.fixMarkup=M,a.highlightBlock=N,a.configure=function(e){m=s(m,e)},a.initHighlighting=h,a.initHighlightingOnLoad=function(){addEventListener("DOMContentLoaded",h,!1),addEventListener("load",h,!1)},a.registerLanguage=function(n,e){var t=b[n]=e(a);v(t),t.rawDefinition=e.bind(null,a),t.aliases&&t.aliases.forEach(function(e){u[e]=n})},a.listLanguages=function(){return i(b)},a.getLanguage=S,a.autoDetection=T,a.inherit=s,a.IR=a.IDENT_RE="[a-zA-Z]\\w*",a.UIR=a.UNDERSCORE_IDENT_RE="[a-zA-Z_]\\w*",a.NR=a.NUMBER_RE="\\b\\d+(\\.\\d+)?",a.CNR=a.C_NUMBER_RE="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",a.BNR=a.BINARY_NUMBER_RE="\\b(0b[01]+)",a.RSR=a.RE_STARTERS_RE="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",a.BE=a.BACKSLASH_ESCAPE={b:"\\\\[\\s\\S]",relevance:0},a.ASM=a.APOS_STRING_MODE={cN:"string",b:"'",e:"'",i:"\\n",c:[a.BE]},a.QSM=a.QUOTE_STRING_MODE={cN:"string",b:'"',e:'"',i:"\\n",c:[a.BE]},a.PWM=a.PHRASAL_WORDS_MODE={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},a.C=a.COMMENT=function(e,n,t){var r=a.inherit({cN:"comment",b:e,e:n,c:[]},t||{});return r.c.push(a.PWM),r.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",relevance:0}),r},a.CLCM=a.C_LINE_COMMENT_MODE=a.C("//","$"),a.CBCM=a.C_BLOCK_COMMENT_MODE=a.C("/\\*","\\*/"),a.HCM=a.HASH_COMMENT_MODE=a.C("#","$"),a.NM=a.NUMBER_MODE={cN:"number",b:a.NR,relevance:0},a.CNM=a.C_NUMBER_MODE={cN:"number",b:a.CNR,relevance:0},a.BNM=a.BINARY_NUMBER_MODE={cN:"number",b:a.BNR,relevance:0},a.CSSNM=a.CSS_NUMBER_MODE={cN:"number",b:a.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},a.RM=a.REGEXP_MODE={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[a.BE,{b:/\[/,e:/\]/,relevance:0,c:[a.BE]}]},a.TM=a.TITLE_MODE={cN:"title",b:a.IR,relevance:0},a.UTM=a.UNDERSCORE_TITLE_MODE={cN:"title",b:a.UIR,relevance:0},a.METHOD_GUARD={b:"\\.\\s*"+a.UIR,relevance:0},a});hljs.registerLanguage("java",function(e){var a="false synchronized int abstract float private char boolean var static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private module requires exports do",t={cN:"number",b:"\\b(0[bB]([01]+[01_]+[01]+|[01]+)|0[xX]([a-fA-F0-9]+[a-fA-F0-9_]+[a-fA-F0-9]+|[a-fA-F0-9]+)|(([\\d]+[\\d_]+[\\d]+|[\\d]+)(\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))?|\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))([eE][-+]?\\d+)?)[lLfF]?",relevance:0};return{aliases:["jsp"],k:a,i:/<\/|#/,c:[e.C("/\\*\\*","\\*/",{relevance:0,c:[{b:/\w+@/,relevance:0},{cN:"doctag",b:"@[A-Za-z]+"}]}),e.CLCM,e.CBCM,e.ASM,e.QSM,{cN:"class",bK:"class interface",e:/[{;=]/,eE:!0,k:"class interface",i:/[:"\[\]]/,c:[{bK:"extends implements"},e.UTM]},{bK:"new throw return else",relevance:0},{cN:"function",b:"([À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*(<[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*(\\s*,\\s*[À-ʸa-zA-Z_$][À-ʸa-zA-Z_$0-9]*)*>)?\\s+)+"+e.UIR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:a,c:[{b:e.UIR+"\\s*\\(",rB:!0,relevance:0,c:[e.UTM]},{cN:"params",b:/\(/,e:/\)/,k:a,relevance:0,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]},t,{cN:"meta",b:"@[A-Za-z]+"}]}});hljs.registerLanguage("scala",function(e){var t={cN:"subst",v:[{b:"\\$[A-Za-z0-9_]+"},{b:"\\${",e:"}"}]},a={cN:"string",v:[{b:'"',e:'"',i:"\\n",c:[e.BE]},{b:'"""',e:'"""',relevance:10},{b:'[a-z]+"',e:'"',i:"\\n",c:[e.BE,t]},{cN:"string",b:'[a-z]+"""',e:'"""',c:[t],relevance:10}]},c={cN:"type",b:"\\b[A-Z][A-Za-z0-9_]*",relevance:0},r={cN:"title",b:/[^0-9\n\t "'(),.`{}\[\]:;][^\n\t "'(),.`{}\[\]:;]+|[^0-9\n\t "'(),.`{}\[\]:;=]/,relevance:0},n={cN:"class",bK:"class object trait type",e:/[:={\[\n;]/,eE:!0,c:[{bK:"extends with",relevance:10},{b:/\[/,e:/\]/,eB:!0,eE:!0,relevance:0,c:[c]},{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,relevance:0,c:[c]},r]},l={cN:"function",bK:"def",e:/[:={\[(\n;]/,eE:!0,c:[r]};return{k:{literal:"true false null",keyword:"type yield lazy override def with val var sealed abstract private trait object if forSome for while throw finally protected extends import final return else break new catch super class case package default try this match continue throws implicit"},c:[e.CLCM,e.CBCM,a,{cN:"symbol",b:"'\\w[\\w\\d_]*(?!')"},c,l,n,e.CNM,{cN:"meta",b:"@[A-Za-z]+"}]}});hljs.registerLanguage("bash",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)}/}]},a={cN:"string",b:/"/,e:/"/,c:[e.BE,t,{cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]}]};return{aliases:["sh","zsh"],l:/\b-?[a-z\._]+\b/,k:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",_:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"meta",b:/^#![^\n]+sh\s*$/,relevance:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:!0,c:[e.inherit(e.TM,{b:/\w[\w\d_]*/})],relevance:0},e.HCM,a,{cN:"",b:/\\"/},{cN:"string",b:/'/,e:/'/},t]}}); \ No newline at end of file diff --git a/highlight/styles/hybrid.css b/highlight/styles/hybrid.css deleted file mode 100644 index 29735a189..000000000 --- a/highlight/styles/hybrid.css +++ /dev/null @@ -1,102 +0,0 @@ -/* - -vim-hybrid theme by w0ng (https://github.com/w0ng/vim-hybrid) - -*/ - -/*background color*/ -.hljs { - display: block; - overflow-x: auto; - padding: 0.5em; - background: #1d1f21; -} - -/*selection color*/ -.hljs::selection, -.hljs span::selection { - background: #373b41; -} - -.hljs::-moz-selection, -.hljs span::-moz-selection { - background: #373b41; -} - -/*foreground color*/ -.hljs { - color: #c5c8c6; -} - -/*color: fg_yellow*/ -.hljs-title, -.hljs-name { - color: #f0c674; -} - -/*color: fg_comment*/ -.hljs-comment, -.hljs-meta, -.hljs-meta .hljs-keyword { - color: #707880; -} - -/*color: fg_red*/ -.hljs-number, -.hljs-symbol, -.hljs-literal, -.hljs-deletion, -.hljs-link { - color: #cc6666 -} - -/*color: fg_green*/ -.hljs-string, -.hljs-doctag, -.hljs-addition, -.hljs-regexp, -.hljs-selector-attr, -.hljs-selector-pseudo { - color: #b5bd68; -} - -/*color: fg_purple*/ -.hljs-attribute, -.hljs-code, -.hljs-selector-id { - color: #b294bb; -} - -/*color: fg_blue*/ -.hljs-keyword, -.hljs-selector-tag, -.hljs-bullet, -.hljs-tag { - color: #81a2be; -} - -/*color: fg_aqua*/ -.hljs-subst, -.hljs-variable, -.hljs-template-tag, -.hljs-template-variable { - color: #8abeb7; -} - -/*color: fg_orange*/ -.hljs-type, -.hljs-built_in, -.hljs-builtin-name, -.hljs-quote, -.hljs-section, -.hljs-selector-class { - color: #de935f; -} - -.hljs-emphasis { - font-style: italic; -} - -.hljs-strong { - font-weight: bold; -} diff --git a/img/favicon.png b/img/favicon.png deleted file mode 100644 index 85efb0d48..000000000 Binary files a/img/favicon.png and /dev/null differ diff --git a/img/favicon114x114.png b/img/favicon114x114.png deleted file mode 100644 index ce186ee1c..000000000 Binary files a/img/favicon114x114.png and /dev/null differ diff --git a/img/favicon120x120.png b/img/favicon120x120.png deleted file mode 100644 index 069dd2a2c..000000000 Binary files a/img/favicon120x120.png and /dev/null differ diff --git a/img/favicon128x128.png b/img/favicon128x128.png deleted file mode 100644 index 6fb7c805f..000000000 Binary files a/img/favicon128x128.png and /dev/null differ diff --git a/img/favicon144x144.png b/img/favicon144x144.png deleted file mode 100644 index afe9b6d44..000000000 Binary files a/img/favicon144x144.png and /dev/null differ diff --git a/img/favicon150x150.png b/img/favicon150x150.png deleted file mode 100644 index 56971c2f7..000000000 Binary files a/img/favicon150x150.png and /dev/null differ diff --git a/img/favicon152x152.png b/img/favicon152x152.png deleted file mode 100644 index 88fe4335d..000000000 Binary files a/img/favicon152x152.png and /dev/null differ diff --git a/img/favicon16x16.png b/img/favicon16x16.png deleted file mode 100644 index 73f9f9984..000000000 Binary files a/img/favicon16x16.png and /dev/null differ diff --git a/img/favicon196x196.png b/img/favicon196x196.png deleted file mode 100644 index bd2968128..000000000 Binary files a/img/favicon196x196.png and /dev/null differ diff --git a/img/favicon24x24.png b/img/favicon24x24.png deleted file mode 100644 index 368d0828f..000000000 Binary files a/img/favicon24x24.png and /dev/null differ diff --git a/img/favicon310x150.png b/img/favicon310x150.png deleted file mode 100644 index 5bd98a024..000000000 Binary files a/img/favicon310x150.png and /dev/null differ diff --git a/img/favicon310x310.png b/img/favicon310x310.png deleted file mode 100644 index 7bd6b9e5e..000000000 Binary files a/img/favicon310x310.png and /dev/null differ diff --git a/img/favicon32x32.png b/img/favicon32x32.png deleted file mode 100644 index d9e2d257d..000000000 Binary files a/img/favicon32x32.png and /dev/null differ diff --git a/img/favicon48x48.png b/img/favicon48x48.png deleted file mode 100644 index 989549b83..000000000 Binary files a/img/favicon48x48.png and /dev/null differ diff --git a/img/favicon57x57.png b/img/favicon57x57.png deleted file mode 100644 index c95e26172..000000000 Binary files a/img/favicon57x57.png and /dev/null differ diff --git a/img/favicon60x60.png b/img/favicon60x60.png deleted file mode 100644 index 4aaf82471..000000000 Binary files a/img/favicon60x60.png and /dev/null differ diff --git a/img/favicon64x64.png b/img/favicon64x64.png deleted file mode 100644 index a8b9c2d66..000000000 Binary files a/img/favicon64x64.png and /dev/null differ diff --git a/img/favicon70x70.png b/img/favicon70x70.png deleted file mode 100644 index 91c00ceff..000000000 Binary files a/img/favicon70x70.png and /dev/null differ diff --git a/img/favicon72x72.png b/img/favicon72x72.png deleted file mode 100644 index b63ed2021..000000000 Binary files a/img/favicon72x72.png and /dev/null differ diff --git a/img/favicon76x76.png b/img/favicon76x76.png deleted file mode 100644 index d58f1bd8e..000000000 Binary files a/img/favicon76x76.png and /dev/null differ diff --git a/img/favicon96x96.png b/img/favicon96x96.png deleted file mode 100644 index f3f7ccbe5..000000000 Binary files a/img/favicon96x96.png and /dev/null differ diff --git a/img/features-header.svg b/img/features-header.svg deleted file mode 100644 index fe2f15393..000000000 --- a/img/features-header.svg +++ /dev/null @@ -1,83 +0,0 @@ - - - - header-image - Created with Sketch. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/img/first-feature-icon.svg b/img/first-feature-icon.svg deleted file mode 100644 index db2f82c75..000000000 --- a/img/first-feature-icon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - features01 - Created with Sketch. - - - - - - - - - - \ No newline at end of file diff --git a/img/first_icon.png b/img/first_icon.png deleted file mode 100644 index 0283901ea..000000000 Binary files a/img/first_icon.png and /dev/null differ diff --git a/img/first_icon2x.png b/img/first_icon2x.png deleted file mode 100644 index 4a0644df0..000000000 Binary files a/img/first_icon2x.png and /dev/null differ diff --git a/img/jumbotron_pattern.png b/img/jumbotron_pattern.png deleted file mode 100644 index a85115ffa..000000000 Binary files a/img/jumbotron_pattern.png and /dev/null differ diff --git a/img/jumbotron_pattern2x.png b/img/jumbotron_pattern2x.png deleted file mode 100644 index a85115ffa..000000000 Binary files a/img/jumbotron_pattern2x.png and /dev/null differ diff --git a/img/light-navbar-brand.svg b/img/light-navbar-brand.svg deleted file mode 100644 index 3ed4dedb7..000000000 --- a/img/light-navbar-brand.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/img/light-sidebar-brand.svg b/img/light-sidebar-brand.svg deleted file mode 100644 index 3ed4dedb7..000000000 --- a/img/light-sidebar-brand.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/img/light_navbar_brand.png b/img/light_navbar_brand.png deleted file mode 100644 index 85efb0d48..000000000 Binary files a/img/light_navbar_brand.png and /dev/null differ diff --git a/img/navbar_brand.png b/img/navbar_brand.png deleted file mode 100644 index d77078120..000000000 Binary files a/img/navbar_brand.png and /dev/null differ diff --git a/img/navbar_brand2x.png b/img/navbar_brand2x.png deleted file mode 100644 index 85efb0d48..000000000 Binary files a/img/navbar_brand2x.png and /dev/null differ diff --git a/img/navbar_brand36x36.png b/img/navbar_brand36x36.png deleted file mode 100644 index b4a944088..000000000 Binary files a/img/navbar_brand36x36.png and /dev/null differ diff --git a/img/portal/change-history-annotated.png b/img/portal/change-history-annotated.png deleted file mode 100644 index 2bb9e9a62..000000000 Binary files a/img/portal/change-history-annotated.png and /dev/null differ diff --git a/img/portal/connect-to-zone.png b/img/portal/connect-to-zone.png deleted file mode 100644 index d700995ae..000000000 Binary files a/img/portal/connect-to-zone.png and /dev/null differ diff --git a/img/portal/create-acl-rule.png b/img/portal/create-acl-rule.png deleted file mode 100644 index 52487428f..000000000 Binary files a/img/portal/create-acl-rule.png and /dev/null differ diff --git a/img/portal/create-group.png b/img/portal/create-group.png deleted file mode 100644 index 10e62b6e3..000000000 Binary files a/img/portal/create-group.png and /dev/null differ diff --git a/img/portal/credentials_annotated.png b/img/portal/credentials_annotated.png deleted file mode 100644 index 19f459499..000000000 Binary files a/img/portal/credentials_annotated.png and /dev/null differ diff --git a/img/portal/dns-change-approval-with-errors.png b/img/portal/dns-change-approval-with-errors.png deleted file mode 100644 index ee1f4d84f..000000000 Binary files a/img/portal/dns-change-approval-with-errors.png and /dev/null differ diff --git a/img/portal/dns-change-cancel-prompt-annotated.png b/img/portal/dns-change-cancel-prompt-annotated.png deleted file mode 100644 index d1347efb9..000000000 Binary files a/img/portal/dns-change-cancel-prompt-annotated.png and /dev/null differ diff --git a/img/portal/dns-change-cancel-prompt.png b/img/portal/dns-change-cancel-prompt.png deleted file mode 100644 index af1deb387..000000000 Binary files a/img/portal/dns-change-cancel-prompt.png and /dev/null differ diff --git a/img/portal/dns-change-cancelled.png b/img/portal/dns-change-cancelled.png deleted file mode 100644 index 7d3201ea1..000000000 Binary files a/img/portal/dns-change-cancelled.png and /dev/null differ diff --git a/img/portal/dns-change-list-annotated.png b/img/portal/dns-change-list-annotated.png deleted file mode 100644 index 15094929b..000000000 Binary files a/img/portal/dns-change-list-annotated.png and /dev/null differ diff --git a/img/portal/dns-change-list.png b/img/portal/dns-change-list.png deleted file mode 100644 index 8989d2b5a..000000000 Binary files a/img/portal/dns-change-list.png and /dev/null differ diff --git a/img/portal/dns-change-main-annotated.png b/img/portal/dns-change-main-annotated.png deleted file mode 100644 index 66c204825..000000000 Binary files a/img/portal/dns-change-main-annotated.png and /dev/null differ diff --git a/img/portal/dns-change-main.png b/img/portal/dns-change-main.png deleted file mode 100644 index 5fb2fc7fd..000000000 Binary files a/img/portal/dns-change-main.png and /dev/null differ diff --git a/img/portal/dns-change-new-annotated.png b/img/portal/dns-change-new-annotated.png deleted file mode 100644 index 0aefa0c91..000000000 Binary files a/img/portal/dns-change-new-annotated.png and /dev/null differ diff --git a/img/portal/dns-change-new.png b/img/portal/dns-change-new.png deleted file mode 100644 index ac0846f62..000000000 Binary files a/img/portal/dns-change-new.png and /dev/null differ diff --git a/img/portal/dns-change-non-fatal-errors.png b/img/portal/dns-change-non-fatal-errors.png deleted file mode 100644 index 05eab5b63..000000000 Binary files a/img/portal/dns-change-non-fatal-errors.png and /dev/null differ diff --git a/img/portal/dns-change-open-requests-filter-annotated.png b/img/portal/dns-change-open-requests-filter-annotated.png deleted file mode 100644 index 3783645a7..000000000 Binary files a/img/portal/dns-change-open-requests-filter-annotated.png and /dev/null differ diff --git a/img/portal/dns-change-open-requests-filter.png b/img/portal/dns-change-open-requests-filter.png deleted file mode 100644 index 2a25dd06f..000000000 Binary files a/img/portal/dns-change-open-requests-filter.png and /dev/null differ diff --git a/img/portal/dns-change-review.png b/img/portal/dns-change-review.png deleted file mode 100644 index c7a782b40..000000000 Binary files a/img/portal/dns-change-review.png and /dev/null differ diff --git a/img/portal/dns-change-reviewed.png b/img/portal/dns-change-reviewed.png deleted file mode 100644 index 3d4481308..000000000 Binary files a/img/portal/dns-change-reviewed.png and /dev/null differ diff --git a/img/portal/dns-change-schedule-annotated.png b/img/portal/dns-change-schedule-annotated.png deleted file mode 100644 index f718c8215..000000000 Binary files a/img/portal/dns-change-schedule-annotated.png and /dev/null differ diff --git a/img/portal/dns-change-summary.png b/img/portal/dns-change-summary.png deleted file mode 100644 index 5fbebe5b7..000000000 Binary files a/img/portal/dns-change-summary.png and /dev/null differ diff --git a/img/portal/dns-changes-admin-view.png b/img/portal/dns-changes-admin-view.png deleted file mode 100644 index 80a01a7f8..000000000 Binary files a/img/portal/dns-changes-admin-view.png and /dev/null differ diff --git a/img/portal/group-membership.png b/img/portal/group-membership.png deleted file mode 100644 index b8aefd7d7..000000000 Binary files a/img/portal/group-membership.png and /dev/null differ diff --git a/img/portal/groups-listed-all.png b/img/portal/groups-listed-all.png deleted file mode 100644 index a92e09929..000000000 Binary files a/img/portal/groups-listed-all.png and /dev/null differ diff --git a/img/portal/groups-listed.png b/img/portal/groups-listed.png deleted file mode 100644 index de1aa7ec1..000000000 Binary files a/img/portal/groups-listed.png and /dev/null differ diff --git a/img/portal/groups-main-all.png b/img/portal/groups-main-all.png deleted file mode 100644 index d19e1d609..000000000 Binary files a/img/portal/groups-main-all.png and /dev/null differ diff --git a/img/portal/groups-main.png b/img/portal/groups-main.png deleted file mode 100644 index d4bed070e..000000000 Binary files a/img/portal/groups-main.png and /dev/null differ diff --git a/img/portal/login.png b/img/portal/login.png deleted file mode 100644 index af8d6d6bf..000000000 Binary files a/img/portal/login.png and /dev/null differ diff --git a/img/portal/logout-annotated.png b/img/portal/logout-annotated.png deleted file mode 100644 index 850ac6d40..000000000 Binary files a/img/portal/logout-annotated.png and /dev/null differ diff --git a/img/portal/main-annotated.png b/img/portal/main-annotated.png deleted file mode 100644 index f00ab63ef..000000000 Binary files a/img/portal/main-annotated.png and /dev/null differ diff --git a/img/portal/main.png b/img/portal/main.png deleted file mode 100644 index ff986f3a5..000000000 Binary files a/img/portal/main.png and /dev/null differ diff --git a/img/portal/manage-records-annotated.png b/img/portal/manage-records-annotated.png deleted file mode 100644 index 03643f9ef..000000000 Binary files a/img/portal/manage-records-annotated.png and /dev/null differ diff --git a/img/portal/manage-records-sort.png b/img/portal/manage-records-sort.png deleted file mode 100644 index 0d8b657b3..000000000 Binary files a/img/portal/manage-records-sort.png and /dev/null differ diff --git a/img/portal/manage-zone.png b/img/portal/manage-zone.png deleted file mode 100644 index 6614623b2..000000000 Binary files a/img/portal/manage-zone.png and /dev/null differ diff --git a/img/portal/recordset-search-filters.png b/img/portal/recordset-search-filters.png deleted file mode 100644 index 0244e1e02..000000000 Binary files a/img/portal/recordset-search-filters.png and /dev/null differ diff --git a/img/portal/recordset-search-info.png b/img/portal/recordset-search-info.png deleted file mode 100644 index b6c679deb..000000000 Binary files a/img/portal/recordset-search-info.png and /dev/null differ diff --git a/img/portal/recordset-search-main.png b/img/portal/recordset-search-main.png deleted file mode 100644 index 56fc20bb3..000000000 Binary files a/img/portal/recordset-search-main.png and /dev/null differ diff --git a/img/portal/recordset-search-name-filter.png b/img/portal/recordset-search-name-filter.png deleted file mode 100644 index b068f0216..000000000 Binary files a/img/portal/recordset-search-name-filter.png and /dev/null differ diff --git a/img/portal/search-zones-all-zones.png b/img/portal/search-zones-all-zones.png deleted file mode 100644 index f42b7ac71..000000000 Binary files a/img/portal/search-zones-all-zones.png and /dev/null differ diff --git a/img/portal/search-zones-my-zones.png b/img/portal/search-zones-my-zones.png deleted file mode 100644 index f9c006f97..000000000 Binary files a/img/portal/search-zones-my-zones.png and /dev/null differ diff --git a/img/portal/sync-zones-annotated.png b/img/portal/sync-zones-annotated.png deleted file mode 100644 index efa10a4af..000000000 Binary files a/img/portal/sync-zones-annotated.png and /dev/null differ diff --git a/img/portal/zone-list.png b/img/portal/zone-list.png deleted file mode 100644 index 8c1d33ed6..000000000 Binary files a/img/portal/zone-list.png and /dev/null differ diff --git a/img/portal/zone-main.png b/img/portal/zone-main.png deleted file mode 100644 index ab55a9201..000000000 Binary files a/img/portal/zone-main.png and /dev/null differ diff --git a/img/portal/zone-records-annotated.png b/img/portal/zone-records-annotated.png deleted file mode 100644 index 339d04776..000000000 Binary files a/img/portal/zone-records-annotated.png and /dev/null differ diff --git a/img/portal/zones-all-zones.png b/img/portal/zones-all-zones.png deleted file mode 100644 index 08ae43192..000000000 Binary files a/img/portal/zones-all-zones.png and /dev/null differ diff --git a/img/portal/zones-my-zones.png b/img/portal/zones-my-zones.png deleted file mode 100644 index 8c1d33ed6..000000000 Binary files a/img/portal/zones-my-zones.png and /dev/null differ diff --git a/img/poster.png b/img/poster.png deleted file mode 100644 index 804959a9e..000000000 Binary files a/img/poster.png and /dev/null differ diff --git a/img/sample-email-nofitication.png b/img/sample-email-nofitication.png deleted file mode 100644 index 4dc55e585..000000000 Binary files a/img/sample-email-nofitication.png and /dev/null differ diff --git a/img/second-feature-icon.svg b/img/second-feature-icon.svg deleted file mode 100644 index 51bc7b562..000000000 --- a/img/second-feature-icon.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - features02 - Created with Sketch. - - - - - - - - - - \ No newline at end of file diff --git a/img/second_icon.png b/img/second_icon.png deleted file mode 100644 index 0c7749cbf..000000000 Binary files a/img/second_icon.png and /dev/null differ diff --git a/img/second_icon2x.png b/img/second_icon2x.png deleted file mode 100644 index 439b643c0..000000000 Binary files a/img/second_icon2x.png and /dev/null differ diff --git a/img/sidebar_brand.png b/img/sidebar_brand.png deleted file mode 100644 index f08e6831b..000000000 Binary files a/img/sidebar_brand.png and /dev/null differ diff --git a/img/sidebar_brand2x.png b/img/sidebar_brand2x.png deleted file mode 100644 index 28e4d1164..000000000 Binary files a/img/sidebar_brand2x.png and /dev/null differ diff --git a/img/sidebar_brand36x36.png b/img/sidebar_brand36x36.png deleted file mode 100644 index 58dace8bd..000000000 Binary files a/img/sidebar_brand36x36.png and /dev/null differ diff --git a/img/third-feature-icon.svg b/img/third-feature-icon.svg deleted file mode 100644 index 2097fe24c..000000000 --- a/img/third-feature-icon.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - features03 - Created with Sketch. - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/img/third_icon.png b/img/third_icon.png deleted file mode 100644 index ba07d7c13..000000000 Binary files a/img/third_icon.png and /dev/null differ diff --git a/img/third_icon2x.png b/img/third_icon2x.png deleted file mode 100644 index 030e8f426..000000000 Binary files a/img/third_icon2x.png and /dev/null differ diff --git a/img/vinyldns-fulllogoDARK-300.png b/img/vinyldns-fulllogoDARK-300.png deleted file mode 100644 index 7d6cf3107..000000000 Binary files a/img/vinyldns-fulllogoDARK-300.png and /dev/null differ diff --git a/js/docs.js b/js/docs.js deleted file mode 100644 index 49eb7f42b..000000000 --- a/js/docs.js +++ /dev/null @@ -1,163 +0,0 @@ -/** - * Toggle an specific class to the received DOM element. - * @param {string} elemSelector The query selector specifying the target element. - * @param {string} [activeClass='active'] The class to be applied/removed. - */ -function toggleClass(elemSelector, activeClass = "active") { - const elem = document.querySelector(elemSelector); - if (elem) { - elem.classList.toggle(activeClass); - } -} - -/** - * Toggle specific classes to an array of corresponding DOM elements. - * @param {Array} elemSelectors The query selectors specifying the target elements. - * @param {Array} activeClasses The classes to be applied/removed. - */ -function toggleClasses(elemSelectors, activeClasses) { - elemSelectors.map((elemSelector, idx) => { - toggleClass(elemSelector, activeClasses[idx]); - }); -} - -/** - * Remove active class from siblings DOM elements and apply it to event target. - * @param {Element} element The element receiving the class, and whose siblings will lose it. - * @param {string} [activeClass='active'] The class to be applied. - */ -function activate(element, activeClass = "active") { - [...element.parentNode.children].map(elem => - elem.classList.remove(activeClass) - ); - element.classList.add(activeClass); -} - -/** - * Remove active class from siblings parent DOM elements and apply it to element target parent. - * @param {Element} element The element receiving the class, and whose siblings will lose it. - * @param {string} [activeClass='active'] The class to be applied. - */ -function activateParent(element, activeClass = "active") { - const elemParent = element.parentNode; - activate(elemParent, activeClass); -} - -/** - * Remove active class from siblings parent DOM elements and apply it to element target parent. - * @param {Element} element The element receiving the class, and whose siblings will lose it. - * @param {string} [activeClass='active'] The class to be applied. - */ -function toggleParent(element, activeClass = "active") { - const elemParent = element.parentNode; - if (elemParent) { - elemParent.classList.toggle(activeClass); - } -} - -/** - * This will make the specified elements click event to show/hide the menu sidebar. - */ -function activateToggle() { - const menuToggles = document.querySelectorAll("#menu-toggle, #main-toggle"); - if (menuToggles) { - [...menuToggles].map(elem => { - elem.onclick = e => { - e.preventDefault(); - toggleClass("#wrapper", "toggled"); - }; - }); - } -} - -/** - * This will make the specified elements click event to behave as a menu - * parent entry, or a link, or sometimes both, depending on the context. - */ -function activateMenuNesting() { - const menuParents = document.querySelectorAll(".drop-nested"); - if (menuParents) { - [...menuParents].map(elem => { - elem.onclick = e => { - e.preventDefault(); - toggleParent(elem, "open"); - const elementType = e.currentTarget.tagName.toLowerCase(); - if (elementType === "a") { - const linkElement = e.currentTarget; - const linkElementParent = linkElement.parentNode; - const destination = linkElement.href; - if ( - destination !== window.location.href && - !linkElementParent.classList.contains("active") - ) { - window.location.href = destination; - } - } - }; - }); - } -} - -/** - * Aux function to retrieve repository stars and watchers count info from - * GitHub API and set it on its proper nodes. - */ -async function loadGitHubStats() { - const content = document.querySelector("#content"); - const ghOwner = content.dataset.githubOwner; - const ghRepo = content.dataset.githubRepo; - - if (ghOwner && ghRepo) { - const ghAPI = `https://api.github.com/repos/${ghOwner}/${ghRepo}`; - const ghDataResponse = await fetch(ghAPI); - const ghData = await ghDataResponse.json(); - const watchersElement = document.querySelector("#eyes"); - const starsElement = document.querySelector("#stars"); - watchersElement.textContent = ghData.subscribers_count; - starsElement.textContent = ghData.stargazers_count; - } -} - -/** - * Function to create an anchor with an specific id - * @param {string} id The corresponding id from which the href will be created. - * @returns {Element} The new created anchor. - */ -function anchorForId(id) { - const anchor = document.createElement("a"); - anchor.className = "header-link"; - anchor.href = `#${id}`; - anchor.innerHTML = ''; - return anchor; -} - -/** - * Aux function to retrieve repository stars and watchers count info from - * @param {string} level The specific level to select header from. - * @param {Element} containingElement The element receiving the anchor. - */ -function linkifyAnchors(level, containingElement) { - const headers = containingElement.getElementsByTagName(`h${level}`); - [...headers].map(header => { - if (typeof header.id !== "undefined" && header.id !== "") { - header.append(anchorForId(header.id)); - } - }); -} - -/** - * Function - */ -function linkifyAllLevels() { - const content = document.querySelector("#content"); - [...Array(7).keys()].map(level => { - linkifyAnchors(level, content); - }); -} - -window.addEventListener("DOMContentLoaded", () => { - activateToggle(); - activateMenuNesting(); - loadGitHubStats(); - linkifyAllLevels(); -}); diff --git a/js/main.js b/js/main.js deleted file mode 100644 index 01865e185..000000000 --- a/js/main.js +++ /dev/null @@ -1,73 +0,0 @@ -jQuery(document).ready(function() { - hljs.initHighlightingOnLoad(); - activeToggle(); - loadGitHubStats(); - linkifyAllLevels(".docs .content-wrapper"); -}); - - -function activeToggle() { - $("#menu-toggle").click(function(e) { - e.preventDefault(); - $("#wrapper").toggleClass("toggled"); - }); -} - -var anchorForId = function (id) { - var anchor = document.createElement("a"); - anchor.className = "header-link"; - anchor.href = "#" + id; - anchor.innerHTML = ""; - return anchor; -}; - -var linkifyAnchors = function (level, containingElement) { - var headers = containingElement.getElementsByTagName("h" + level); - for (var h = 0; h < headers.length; h++) { - var header = headers[h]; - - if (typeof header.id !== "undefined" && header.id !== "") { - header.appendChild(anchorForId(header.id)); - } - } -}; - -var linkifyAllLevels = function (blockSelector) { - var contentBlock = document.querySelector(blockSelector); - if (!contentBlock) { - return; - } - for (var level = 1; level <= 6; level++) { - linkifyAnchors(level, contentBlock); - } -}; - -var baseURL = window.location.href; - -function shareSiteFacebook(text) { - launchPopup('http://www.facebook.com/sharer/sharer.php?u='+baseURL+'&t=' + text); -} - -function shareSiteTwitter(text) { - launchPopup('https://twitter.com/home?status=' + text); - return false; -} - -function launchPopup(url) { - window.open(url, 'Social Share', 'height=320, width=640, toolbar=no, menubar=no, scrollbars=no, resizable=no, location=no, directories=no, status=no'); -} - -function loadGitHubStats() { - var content = $("#content"); - var githubOwner = content.attr("data-github-owner") - var githubRepo = content.attr("data-github-repo") - - if(githubOwner && githubRepo) { - var gitHubAPI = "https://api.github.com/repos/" + githubOwner + "/" + githubRepo + "?callback=?"; - $.getJSON(gitHubAPI).done(function(data) { - $('#eyes').text(data.data.subscribers_count); - $('#stars').text(data.data.stargazers_count); - }); - } - -} diff --git a/js/search.js b/js/search.js deleted file mode 100644 index 21ab616d1..000000000 --- a/js/search.js +++ /dev/null @@ -1,520 +0,0 @@ -// When the user clicks on the search box, we want to toggle the search dropdown -function displayToggleSearch(e) { - e.preventDefault(); - e.stopPropagation(); - - closeDropdownSearch(e); - - if (idx === null) { - console.log("Building search index..."); - prepareIdxAndDocMap(); - console.log("Search index built."); - } - const dropdown = document.querySelector("#search-dropdown-content"); - if (dropdown) { - if (!dropdown.classList.contains("show")) { - dropdown.classList.add("show"); - } - document.addEventListener("click", closeDropdownSearch); - document.addEventListener("keydown", searchOnKeyDown); - document.addEventListener("keyup", searchOnKeyUp); - } -} - -//We want to prepare the index only after clicking the search bar -var idx = null -const docMap = new Map() - -function prepareIdxAndDocMap() { - const docs = [ - { - "title": "Access the Portal", - "url": "/portal/access.html", - "content": "Access the portal Login The login page is where you provide your account username and password to access VinylDNS. The URL to access VinylDNS varies by instance. Check with your VinylDNS administrators for login information. Logout To logout of VinylDNS select your username in the top right of the portal to reveal the dropdown menu containing the Logout link." - } , - { - "title": "Approve Batch Change", - "url": "/api/approve-batchchange.html", - "content": "Approve Batch Change Manually approves a batch change in pending review status given the batch change ID, resulting in revalidation and submission for backend processing. Only system administrators (ie. support or super user) can manually review a batch change. In the event that a batch change is approved and still encounters non-fatal errors, it will remain in manual review state until a successful approval (202 Accepted) or rejection (200 OK). Note: If manual review is disabled in the VinylDNS instance, users trying to access this endpoint will encounter a 404 Not Found response since it will not exist. HTTP REQUEST POST /zones/batchrecordchanges/{id}/approve HTTP REQUEST PARAMS name type required? description id string yes Unique identifier assigned to each created batch change. reviewComment string no Optional approval explanation. EXAMPLE HTTP REQUEST { \"reviewComment\": \"Comments are optional.\" } HTTP RESPONSE TYPES Code description 202 OK Batch change is approved and is returned in response body. Batch change is submitted for backend processing. 400 BadRequest Batch change is not in pending approval status. 403 Forbidden User is not a system administrator (ie. support or super user) or is attempting to approve a scheduled batch prior to its scheduled due date. 404 NotFound Batch change does not exist. Since we re-run validations upon successful approval, the create batch error codes still hold, so it is possible to see them as well. HTTP RESPONSE ATTRIBUTES name type description userId string The unique identifier of the user that created the batch change. userName string The username of the user that created the batch change. comments string Conditional: comments about the batch change, if provided. createdTimestamp date-time The timestamp (UTC) when the batch change was created. changes Array of SingleChange Array of single changes within a batch change. A SingleChange can either be a SingleAddChange or a SingleDeleteRRSetChange. status BatchChangeStatus Status of the batch change. id string The unique identifier for this batch change. ownerGroupId string Conditional: Record ownership assignment, if provided. approvalStatus BatchChangeApprovalStatus Whether the batch change is currently awaiting manual review. Will be ManuallyApproved status when approving. reviewerId string Unique identifier for the reviewer of the batch change. reviewerUserName string User name for the reviewer of the batch change. reviewComment string Conditional: Comment from the reviewer of the batch change, if provided. reviewTimestamp date-time The timestamp (UTC) of when the batch change was manually reviewed. EXAMPLE RESPONSE { \"userId\": \"vinyl\", \"userName\": \"vinyl201\", \"comments\": \"\", \"createdTimestamp\": \"2019-07-25T20:08:17Z\", \"changes\": [ { \"changeType\": \"Add\", \"inputName\": \"approve.parent.com.\", \"type\": \"A\", \"ttl\": 7200, \"record\": { \"address\": \"1.1.1.1\" }, \"status\": \"Pending\", \"recordName\": \"approve\", \"zoneName\": \"parent.com.\", \"zoneId\": \"876879e5-293d-4092-99ab-9cbdf50c1636\", \"validationErrors\": [], \"id\": \"a69cad97-994d-41e3-aed2-ec8c86a30ac5\" } ], \"status\": \"PendingProcessing\", \"id\": \"2343fa88-d4da-4377-986a-34ba4e8ca628\", \"ownerGroupId\": \"159a41c5-e67e-4951-b539-05f5ac788139\", \"reviewerId\": \"90c11ffc-5a71-4794-97c6-74d19c81af7d \", \"reviewComment\": \"Good to go!\", \"reviewTimestamp\": \"2019-07-25T20:10:28Z\", \"approvalStatus\": \"ManuallyApproved\" }" - } , - { - "title": "Authentication", - "url": "/api/auth-mechanism.html", - "content": "API Authentication The API Authentication for VinylDNS is modeled after the AWS Signature Version 4 Signing process. The AWS documentation for it can be found here. Similar to how the AWS Signature Version 4 signing process adds authentication information to AWS requests, VinylDNS’s API Authenticator also adds authentication information to every API request. VinylDNS API Authentication Process Retrieve the Authorization HTTP Header (Auth Header) from the HTTP Request Context. Parse the retrieved Auth Header into an AWS String to Sign structure which should be in the form: StringToSign = Algorithm + \\n + RequestDateTime + \\n + CredentialScope + \\n + HashedCanonicalRequest String to Sign Example: AWS4-HMAC-SHA256 20150830T123600Z 20150830/us-east-1/iam/aws4_request f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59 Extract the access key from the Auth Header and search for the account associated with the access key. Validate the signature of the request. Build the authentication information, which essentially contains all the authorized accounts for the signed in user. Authentication Failure Response If any these validations fail, a 401 (Unauthorized) or a 403 (Forbidden) error will be thrown; otherwise unanticipated exceptions will simply bubble out and result as 500s or 503s. If the Auth Header is not found, then a 401 (Unauthorized) error is returned. If the Auth Header cannot be parsed, then a 403 (Forbidden) error is returned. If the access key cannot be found, then a 401 (Unauthorized) error is returned. If the request signature cannot be validated, then a 403 (Forbidden) error is returned." - } , - { - "title": "Batch Change Errors", - "url": "/api/batchchange-errors.html", - "content": "Batch Change Errors Single Change Errors Non-Fatal Errors Fatal Errors Full-Request Errors SINGLE CHANGE ERRORS Single change errors are errors that get collected at different validation stages and correspond to individual change inputs. Each change can have its own list of one or more errors. Single change errors are grouped into the following stages: Independent input validations: Validate invalid data input formats and values. Record and zone discovery: Resolve record and zone from fully-qualified input name. Dependent context validations: Check for sufficient user access and conflicts with existing records or other submissions within the batch. Since single change errors are collected at different stages, errors at later stages may exist but will not appear unless errors at earlier stages are addressed. An example is that a user may initially get an error about required data missing from the DNS request, and then after correcting the data encounter an issue about a conflicting record already existing in the DNS backend. EXAMPLE ERROR RESPONSE BY CHANGE [ { \"changeType\": \"Add\", \"inputName\": \"good-A.another.example.com.\", \"type\": \"A\", \"ttl\": 200, \"record\": { \"address\": \"1.2.3.4\" } }, { \"changeType\": \"Add\", \"inputName\": \"duplicate.example.com\", \"type\": \"CNAME\", \"ttl\": 200, \"record\": { \"cname\": \"test.example.com.\" }, \"errors\": [ \"Record with name \\\"duplicate.example.com.\\\" is not unique in the batch change. CNAME record cannot use duplicate name.\" ] }, { \"changeType\": \"Add\", \"inputName\": \"duplicate.example.com\", \"type\": \"A\", \"ttl\": 300, \"record\": { \"address\": \"1.2.3.4\" } }, { \"changeType\": \"Add\", \"inputName\": \"bad-ttl-and-invalid-name$.sample.com.\", \"type\": \"A\", \"ttl\": 29, \"record\": { \"address\": \"1.2.3.4\" }, \"errors\": [ \"Failed validation 29, TTL must be between 30 and 2147483647.\", \"Failed validation bad-ttl-and-invalid-name$.sample.com., valid domain names are a series of one or more labels joined by dots and terminate on a dot.\" ] } ] Single Change Errors Single change errors can be further classified as non-fatal or fatal errors. The presence of one or more fatal errors will result in an immediate failure (ie. hard stop) and no changes in the batch will be accepted. The behavior of non-fatal errors depends on whether manual review is configured on: if manual review is disabled, non-fatal errors are treated as fatal errors; if manual review is enabled, batches with only non-fatal errors will enter a pending review state. When non-fatal errors are encountered with manual review enabled, the errors will be saved on the corresponding SingleChanges. The SingleChanges will also have a status of NeedsReview. The following chart provides a breakdown of batch change status outcome based on a combination of manual review configuration and error types present in the batch change: Manual Review Enabled? Errors in Batch? Status Outcome Yes Both fatal and non-fatal Hard stop Yes Fatal only Hard stop Yes Non-fatal only PendingReview Yes No PendingProcessing (will be or is being auto-processed) No Both fatal and non-fatal Hard stop No Fatal only Hard stop No Non-fatal only Failed No No PendingProcessing (will be or is being auto-processed) Note: if a user submits a batch change with allowManualReview set to false, the request will treat the request as though the VinylDNS instance is configured to have manual review disabled. Non-Fatal Errors Zone Discovery Failed Record Requires Manual Review Fatal Errors Invalid Domain Name Invalid Length Invalid Record Type Invalid IPv4 Address Invalid IPv6 Address Invalid IP Address Invalid TTL Invalid Batch Record Type Record Already Exists Record Does Not Exist CNAME Conflict User Is Not Authorized Record Name Not Unique In Batch Change Invalid Record Type In Reverse Zone Missing Owner Group Id Not a Member of Owner Group High Value Domain CNAME Cannot be the Same Name as Zone Name Non-Fatal Errors Zone Discovery Failed Error Message: Zone Discovery Failed: zone for \"<input>\" does not exist in VinylDNS. If zone exists, then it must be connected to in VinylDNS. Details: Given an inputName, VinylDNS will determine the record and zone name for the requested change. For most records, the record names are the same as the zone name (apex), or split at at the first ‘.’, so the inputName ‘rname.zone.name.com’ will be split into record name ‘rname’ and zone name ‘zone.name.com’ (or ‘rname.zone.name.com’ for both the record and zone name if it’s an apex record). For PTR records, there is logic to determine the appropriate reverse zone from the given IP address. If this logic cannot find a matching zone in VinylDNS, you will see this error. In that case, you need to connect to the zone in VinylDNS. Even if the zone already exists outside of VinylDNS, it has to be added to VinylDNS to modify records. VinylDNS also does not support dotted records for forward zones (eg. record baz.foo.bar. in zone bar.), so encountering this error could indicate that a zone needs to be created outside of VinylDNS and then connected to within VinylDNS. Record Requires Manual Review Error Message: Record set with name <input> requires manual review. Details: Based on a configurable list, VinylDNS will determine if the given inputName requires manual review before it can be processed. Fatal Errors Invalid Domain Name Error Message: Invalid domain name: \"<input>\", valid domain names must be letters, numbers, underscores, and hyphens, joined by dots, and terminate with a dot. Details: Fully qualified domain names, must be comprised of labels, separated by dots. A label is a combination of letters, digits, underscores, and hyphens. They must also be absolute, which means they end with a dot. Syntax: <domain> ::= <subdomain> | \" \" <subdomain> ::= <label> | <subdomain> \".\" <label> <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ] <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str> <let-dig-hyp> ::= <let-dig> | \"-\" <let-dig> ::= <letter> | <digit> <letter> ::= any one of the 52 alphabetic characters A through Z in upper case and a through z in lower case <digit> ::= any one of the ten digits 0 through 9 More info can be found at: RFC 1035, DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION, Section 2.3.1. Preferred name syntax Invalid Length Error Message: Invalid length: \"<input>\", length needs to be between <minLengthInclusive> and <maxLengthInclusive> characters. Details: The length of the input did not fit in the range in [minLengthInclusive, maxLengthInclusive]. Invalid Record Type Error Message: Invalid record type: \"<input>\", valid record types include <valid record types>. Details: The record type input must match one of the valid record types. Not all DNS record types are currently supported. Invalid IPv4 Address Error Message: Invalid IPv4 address: \"<input>\" Details: The IPv4 address input is not a valid IPv4 address. Accepted inputs must be in dotted-decimal notation, with four groups of three decimal digits, separated by periods. Leading zeros in groups can be omitted. Range: 0.0.0.0 - 255.255.255.255 Examples: 1.1.1.1 10.234.0.62 Invalid IPv6 Address Error Message: Invalid IPv6 address: \"<input>\". Details: The IPv6 address input is not a valid IPv6 address. Accepted inputs must be eight groups of four hexadecimal digits, separated by colons. Leading zeros in groups can be emitted. Consecutive groups of all zeros can be replaced by a double colon. Range: 0000:0000:0000:0000:0000:0000:0000:0000 - ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff Examples: 2001:0db8:0000:0000:0000:ff00:0042:8329 2001:0db8::ff00:0042:8329 2001:db8::ff00:42:8329 Invalid IP Address Error Message: Invalid IP address: \"<input>\". Details: The IP address input is not a valid IPv4 or IPv6 address. Invalid TTL Error Message: Invalid TTL: \"<input>\", must be a number between 30 and 2147483647. Details: Time-to-live must be a number in the range [30, 2147483647]. Invalid Batch Record Type Error Message: Invalid Batch Record Type: \"<input>\", valid record types for batch changes include <valid record types>. Details: The DNS record type is not currently supported for batch changes. Record Already Exists Error Message: Record \"<input>\" Already Exists: cannot add an existing record; to update it, issue a DeleteRecordSet then an Add. Details: A record with the given name already exists, and cannot be duplicated for the given type. Record Does Not Exist Error Message: Record \"<input>\" Does Not Exist: cannot delete a record that does not exist. Details: A record with the given name could not be found in VinylDNS. If the record exists in DNS, then you should sync the zone for that record to bring VinylDNS up to date with what is in the DNS backend. CNAME Conflict Error Message: CNAME conflict: CNAME record names must be unique. Existing record with name \"<name>\" and type \"<type>\" conflicts with this record. Details: A CNAME record with the given name already exists. CNAME records must have unique names. User Is Not Authorized Error Message: User \"<user>\" is not authorized. Details: User must either be in the admin group for the zone being changed, or have an ACL rule. Record Name Not Unique In Batch Change Error Message: Record \"<name>\" Name Not Unique In Batch Change: cannot have multiple \"<type>\" records with the same name. Details: Certain record types do not allow multiple records with the same name. If you get this error, it means you have illegally input two or more records with the same name and one of these types. Invalid Record Type In Reverse Zone Error Message: Invalid Record Type In Reverse Zone: record with name \"<name>\" and type \"<type>\" is not allowed in a reverse zone. Details: Not all record types are allowed in a DNS reverse zone. The given type is not supported. Missing Owner Group Id Error Message: Zone \"<zone name>\" is a shared zone, so owner group ID must be specified for record \"<record name>\". Details: You are trying to create a new record or update an existing unowned record in a shared zone. This requires a record owner group ID in the batch change. Not a Member of Owner Group Error Message: User \"<user name>\" must be a member of group \"<group ID>\" to apply this group to batch changes. Details: You must be a member of the group you are assigning for record ownership in the batch change. High Value Domain Error Message: Record Name \"<record name>\" is configured as a High Value Domain, so it cannot be modified. Details: You are trying to create a record with a name that is not permitted in VinylDNS. The list of high value domains is specific to each VinylDNS instance. You should reach out to your VinylDNS administrators for more information. CNAME at the Zone Apex is not Allowed Error Message: CNAME cannot be the same name as zone \"<zone_name>\". Details: CNAME records cannot be @ or the same name as the zone. FULL-REQUEST ERRORS Fail-request errors cause the batch change processing to abort immediately upon encounter. Invalid Batch Change Input Batch Change Not Found Malformed JSON Errors 1. INVALID BATCH CHANGE INPUT HTTP RESPONSE CODE Code description 400 Bad Request - There is a top-level issue with batch change, aborting batch processing. There are a series of different error messages that can be returned with this error code. EXAMPLE ERROR MESSAGES: Batch change contained no changes. Batch change must have at least one change, up to a maximum of <limit> changes. Cannot request more than <limit> changes in a single batch change request DETAILS: If there are issues with the batch change input data provided in the batch change request, errors will be returned and batch change validations will abort processing. BATCH CHANGE NOT FOUND HTTP RESPONSE CODE Code description 404 Not Found - batch change not found for specified ID in get batch change request. ERROR MESSAGE: Batch change with id <id> cannot be found DETAILS: The batch ID specified in the get batch change request does not exist. MALFORMED JSON ERRORS DETAILS: If there are issues with the JSON provided in a batch change request, errors will be returned (not in a single change format) and none of the batch change validations will run. EXAMPLE ERROR MESSAGES: { \"errors\": [ \"Missing BatchChangeInput.changes\" ] } { \"errors\": [ \"Missing BatchChangeInput.changes.inputName\", \"Missing BatchChangeInput.changes.type\", \"Missing BatchChangeInput.changes.ttl\" ] } { \"errors\": [ \"Invalid RecordType\"\" ] }" - } , - { - "title": "Batch Change Model", - "url": "/api/batchchange-model.html", - "content": "Batch Change Model Table of Contents Batch Change Information Batch Change Attributes Single Change Attributes Batch Change Example BATCH CHANGE INFORMATION Batch change is an alternative to submitting individual RecordSet changes and provides the following: The ability to accept multiple changes in a single API call. The ability to include records of multiple record types across multiple zones. Input names are entered as fully-qualified domain names (or IP addresses for PTR records), so users don’t have to think in record/zone context. All record validations are processed simultaneously. Fatal errors for any change in the batch will result in a 400 response and none will be applied. Support for manual review if enabled in your VinylDNS instance. Batch change will remain in limbo until a system administrator (ie. support or super user) either rejects it resulting in an immediate failure or approves it resulting in revalidation and submission for processing. Support for notifications when a batch change is rejected or implemented. A batch change consists of multiple single changes which can be a combination of SingleAddChanges and SingleDeleteRRSetChanges. Note: In the portal batch change is referred to as DNS Change. To update an existing record, you must delete the record first and add the record again with the updated changes. Batch changes are also susceptible to the following restrictions: Current supported record types for batch change are: A, AAAA, CNAME, and PTR. Batch change requests must contain at least one change. The maximum number of single changes within a batch change depends on the instance of VinylDNS. Contact your VinylDNS administrators to find the batch change limit for your instance. Access permissions will follow existing rules (admin group or ACL access). Note that an update (delete and add of the same record name, zone and record type combination) requires Write access. BATCH CHANGE ATTRIBUTES name type description userId string The unique identifier of the user that created the batch change. userName string The username of the user that created the batch change. comments string Optional comments about the batch change. createdTimestamp date-time The timestamp (UTC) when the batch change was created. changes Array of SingleChange Array of single changes within a batch change. A SingleChange can either be a SingleAddChange or a SingleDeleteRRSetChange. status BatchChangeStatus - PendingProcessing - at least one change in batch has not finished processing- Complete - all changes have been processed successfully- Failed - all changes failed during processing- PartialFailure - some changes have failed and the rest were successful- PendingReview - one or more changes requires manual approval/rejection by a system administrator (ie. super or support user) to proceed- Rejected - the batch change was rejected by a system administrator (ie. super or support user) and no changes were applied- Scheduled - the batch change is scheduled for a later date at which time it needs to be approved to proceed.- Cancelled - the PendingReview batch change was cancelled by its creator before review. id string The unique identifier for this batch change. ownerGroupId string Record ownership assignment. Required if any records in the batch change are in shared zones and are new or unowned. approvalStatus BatchChangeApprovalStatus Whether the batch change is currently awaiting manual review. Can be one of AutoApproved, PendingReview, ManuallyApproved, Rejected, or Cancelled. reviewerId string Optional unique identifier for the reviewer of the batch change. Required if batch change was manually rejected or approved. reviewerUserName string Optional user name for the reviewer of the batch change. Required if batch change was manually rejected or approved. reviewComment string Optional comment for the reviewer of the batch change. Only applicable if batch change was manually rejected or approved. reviewTimestamp date-time Optional timestamp (UTC) of when the batch change was manually reviewed. Required if batch change was manually rejected or approved. scheduledTime date-time Optional requested date and time to process the batch change. cancelledTimestamp date-time Optional date and time a batch change was cancelled by its creator. SINGLE CHANGE ATTRIBUTES A successful batch change response consists of a corresponding SingleAddChange or SingleDeleteRRSetChange for each batch change input. See the batch change create page for details on constructing a batch change request. SingleAddChange name type description changeType ChangeInputType Type of change input. Can either be an Add or DeleteRecordSet. See more details about behavior of changeType interaction. inputName string The fully-qualified domain name of the record which was provided in the create batch request. type RecordType Type of DNS record, supported records for batch changes are currently: A, AAAA, CNAME, and PTR. ttl long The time-to-live in seconds. record RecordData The data added for this record, which varies by record type. status SingleChangeStatus Status for this change. Can be one of: Pending, Complete, Failed, NeedsReview or Rejected. recordName string The name of the record. Record names for the apex will be match the zone name (including terminating dot). zoneName string The name of the zone. zoneId string The unique identifier for the zone. systemMessage string Conditional: Returns system message relevant to corresponding batch change input. recordChangeId string Conditional: The unique identifier for the record change; only returned on successful batch creation. recordSetId string Conditional: The unique identifier for the record set; only returned on successful batch creation, validationErrors Array of BatchChangeError Array containing any validation errors associated with this SingleAddChange. Note: These will only exist on NeedsReview or Rejected SingleChanges id string The unique identifier for this change. SingleDeleteRRSetChange name type description changeType ChangeInputType Type of change input. Can either be an Add or DeleteRecordSet. See more details about behavior of changeType interaction. inputName string The fully-qualified domain name of the record which was provided in the create batch request. type RecordType Type of DNS record, supported records for batch changes are currently: A, AAAA, CNAME, and PTR. record RecordData Optional. The data deleted for this record, which varies by record type. If not provided, the entire DNS recordset was deleted. status SingleChangeStatus Status for this change. Can be one of: Pending, Complete, Failed, NeedsReview or Rejected. recordName string The name of the record. Record names for the apex will be match the zone name (including terminating dot). zoneName string The name of the zone. zoneId string The unique identifier for the zone. systemMessage string Conditional: Returns system message relevant to corresponding batch change input. recordChangeId string Conditional: The unique identifier for the record change; only returned on successful batch creation. recordSetId string Conditional: The unique identifier for the record set; only returned on successful batch creation, validationErrors Array of BatchChangeError Array containing any validation errors associated with this SingleDeleteRRSetChange. Note: These will only exist on NeedsReview or Rejected SingleChanges id string The unique identifier for this change. ChangeType Values There are two valid changeTypes for a SingleChange: Add and DeleteRecordSet changeTypes can be used independently or combined to achieve the desired behavior described below. Create a new DNS record: Add with record data Delete an entire record set: 1. DeleteRecordSet without specifying existing record data or 2. DeleteRecordSet for each entry of the DNS record Delete a single entry from DNS record with multiple entries: DeleteRecordSet specifying existing record data Update an existing record set: 1. DeleteRecordSet specifying existing record data (single entry delete) or not specifying record data (full delete) and 2. Add with record data BATCH CHANGE EXAMPLE Successful batch change response example with a SingleAddChange and a SingleDeleteRRSetChange. { \"userId\": \"vinyl\", \"userName\": \"vinyl201\", \"comments\": \"this is optional\", \"createdTimestamp\": \"2018-05-08T18:46:34Z\", \"ownerGroupId\": \"f42385e4-5675-38c0-b42f-64105e743bfe\" \"changes\": [ { \"changeType\": \"Add\", \"inputName\": \"recordName.zoneName.\", \"type\": \"A\", \"ttl\": 3600, \"record\": { \"address\": \"1.1.1.1\" }, \"status\": \"Complete\", \"recordName\": \"recordName\", \"zoneName\": \"zoneName.\", \"zoneId\": \"8f8f649f-998e-4428-a029-b4ba5f5bd4ca\", \"recordChangeId\": \"4754ac4c-5f81-11e8-9c2d-fa7ae01bbebc\", \"recordSetId\": \"4754b084-5f81-11e8-9c2d-fa7ae01bbebc\", \"validationErrors\": [], \"id\": \"17350028-b2b8-428d-9f10-dbb518a0364d\" }, { \"changeType\": \"DeleteRecordSet\", \"inputName\": \"recordName.zoneName.\", \"type\": \"AAAA\", \"status\": \"Complete\", \"recordName\": \"recordName\", \"zoneName\": \"zoneName.\", \"zoneId\": \"9cbdd3ac-9752-4d56-9ca0-6a1a14fc5562\", \"recordChangeId\": \"4754b322-5f81-11e8-9c2d-fa7ae01bbebc\", \"recordSetId\": \"4754b084-5f81-11e8-9c2d-fa7ae01bbebc\", \"validationErrors\": [], \"id\": \"c29d33e4-9bee-4417-a99b-6e815fdeb748\" }, { \"changeType\": \"DeleteRecordSet\", \"inputName\": \"anotherRecordName.zoneName.\", \"type\": \"A\", \"record\": { \"address\": \"1.1.1.1\" }, \"status\": \"Complete\", \"recordName\": \"recordName\", \"zoneName\": \"zoneName.\", \"zoneId\": \"9cbdd3ac-9752-4d56-9ca0-6a1a14fc5562\", \"recordChangeId\": \"9c449026-cffe-4379-beb7-217b8a31aadd\", \"recordSetId\": \"e68776ab-f56f-41bf-a03e-c288b9469b53\", \"validationErrors\": [], \"id\": \"e68776ab-f56f-41bf-a03e-c288b9469b53\" } ], \"status\": \"Complete\", \"id\": \"937191c4-b1fd-4ab5-abb4-9553a65b44ab\", \"approvalStatus\": \"AutoApproved\" }" - } , - { - "title": "Cancel Batch Change", - "url": "/api/cancel-batchchange.html", - "content": "Cancel Batch Change Cancels a batch change that is PendingReview. Only the user who created the batch change can cancel it. Note: If manual review is disabled in the VinylDNS instance, users trying to access this endpoint will encounter a 404 Not Found response since it will not exist. HTTP REQUEST POST /zones/batchrecordchanges/{id}/cancel HTTP REQUEST PARAMS name type required? description id string yes Unique identifier assigned to each created batch change. HTTP RESPONSE TYPES Code description 200 OK - The batch change is returned in response body. 403 Forbidden - The user does not have the access required to perform the action. 404 Not Found - Batch change not found. HTTP RESPONSE ATTRIBUTES See Batch Change Model attributes" - } , - { - "title": "API Configuration Guide", - "url": "/operator/config-api.html", - "content": "API Configuration Guide Note: ALL configuration assumes a vinyldns namespace. For example, sqs settings would be under vinyldns.sqs. Configuration Configuration Overview Configuration API Server Queue Configuration Database Configuration Cryptography Additional Configuration Settings Full Example Config There are a lot of configuration settings in VinylDNS. So much so that it may seem overwhelming to configure vinyldns to your environment. This document describes the configuration settings, highlighting the settings you are most likely to change. All of the configuration settings are captured at the end. It is important to note that the api and portal have different configuration. We will review the configuration for each separately. Configuration Overview How do we config? All configuration is done using Typesafe Config. It provides a means to specifying default configurations, and overriding the configured values in a number of ways: The default configuration provides “safe” default values for all configuration. This makes it possible for you to only change the configuration values that you need to, and assume the default for the rest. This can typically be found in a file named reference.conf. The Typesafe Config library manages populating unspecified values for you automatically. You can override the reference.conf file by providing your own application.conf file when the system starts up. We will review how to do that in the sections that follow. You can override individual configuration properties when the application starts up using standard jvm arguments. For example, you can specify -Dmy.config.value=42, and that will override both application.conf and reference.conf (defaults) You can further override configuration properties with environment variables. The Typesafe Config provides special syntax that allows you to use environment variables. You can make the environment variable optional (meaning use it if it is there) or required (fail to start up without the environment variable). We will illustrate use of environment variables in this guide. Using Environment Variables We strongly recommend that you use environment variables in particular for secrets. Laying down environment variables in a flat file is a security vulnerability for your installation. To demonstrate environment variable usage, here is a following snippet… queue.settings { access-key = ${AWS_ACCESS_KEY} secret-key = ${AWS_SECRET_ACCESS_KEY} signing-region = ${SQS_REGION} service-endpoint = ${SQS_SERVICE_ENDPOINT} queue-name = ${SQS_QUEUE_NAME} } In the example, if any of the values in ${xxx} are not found in the environment, the application will not start up! Configuring API Server The API configuration has a lot of values, the important ones reviewed here. There are several configuration settings that are specific to your environment. The most important configuration is around your system dependencies. Presently, these are your settings for: AWS SQS MySQL Queue Configuration VinylDNS supports both SQS and MySQL queue implementations. There are a couple of implementation-dependent settings that need to be specified: messages-per-poll: Number of messages retrieved in a single queue receive request. Valid values are 1 through 10 ( default). polling-interval: Interval to delay between each poll for messages. If using SQS, be sure to follow the AWS SQS Setup Guide first to get the values you need to configure here. If using MySQL, follow the MySQL Setup Guide first to get the values you need to configure here. The following in a sample SQS config: vinyldns { queue { class-name = \"vinyldns.sqs.queue.SqsMessageQueueProvider\" messages-per-poll = 10 polling-interval = 250.millis # connection information to SQS settings { # AWS access key and secret. access-key = \"x\" secret-key = \"x\" # Regional endpoint to make your requests (eg. 'us-west-2', 'us-east-1', etc.). This is the region where your queue is housed. signing-region = \"x\" # Endpoint to access queue service-endpoint = \"http://vinyldns-elasticmq:9324/\" # Queue name. Should be used in conjunction with service endpoint, rather than using a queue url which is subject to change. queue-name = \"vinyldns\" } } } The following is a sample MySQL queue config: queue { class-name = \"vinyldns.mysql.queue.MySqlMessageQueueProvider\" polling-interval = 250.millis messages-per-poll = 10 max-retries = 50 # Override max retries; default = 100 settings = { name = \"vinyldns\" driver = \"org.mariadb.jdbc.Driver\" migration-url = \"jdbc:mariadb://localhost:19004/?user=root&password=pass\" url = \"jdbc:mariadb://localhost:19004/vinyldns?user=root&password=pass\" user = \"root\" password = \"pass\" # see https://github.com/brettwooldridge/HikariCP connection-timeout-millis = 1000 idle-timeout = 10000 max-lifetime = 30000 maximum-pool-size = 5 minimum-idle = 0 my-sql-properties = { cachePrepStmts=true prepStmtCacheSize=250 prepStmtCacheSqlLimit=2048 rewriteBatchedStatements=true } } } Database Configuration VinylDNS supports a MySQL database. You can enable all repos in a single backend, or have a mix of the two. For each backend, you need to configure the table(s) that should be loaded. If using MySQL, follow the MySQL Setup Guide first to get the values you need to configure here. vinyldns { # this list should include only the datastores being used by your instance data-stores = [\"mysql\"] mysql { # this is the path to the mysql provider. This should not be edited # from the default in reference.conf class-name = \"vinyldns.mysql.repository.MySqlDataStoreProvider\" settings { # the name of the database, recommend to leave this as is name = \"vinyldns\" # the jdbc driver, recommended to leave this as is driver = \"org.mariadb.jdbc.Driver\" # the URL used to create the schema, typically this will be without the \"database\" name migration-url = \"jdbc:mariadb://localhost:19002/?user=root&password=pass\" # the main connection URL url = \"jdbc:mariadb://localhost:19002/vinyldns?user=root&password=pass\" # the user to connect to MySQL user = \"root\" # the password to connect to MySQL password = \"pass\" ## see https://github.com/brettwooldridge/HikariCP for more detail on the following fields # the maximum number of connections to scale the connection pool to maximum-pool-size = 20 # the maximum number of milliseconds to wait for a connection from the connection pool connection-timeout-millis = 1000 # the minimum number of idle connections that HikariCP tries to maintain in the pool minimum-idle = 10 # the maximum number of milliseconds that a connection is can sit idle in the pool idle-timeout = 10000 # The max lifetime of a connection in a pool. Should be several seconds shorter than the database imposed connection time limit max-lifetime = 600000 # controls whether JMX MBeans are registered register-mbeans = true # my-sql-properties allows you to include any additional mysql performance settings you want. # Note that the properties within my-sql-properties must be camel case! # see https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration for guidance my-sql-properties { prepStmtCacheSize = 300 prepStmtCacheSqlLimit = 2048 cachePrepStmts = true useServerPrepStmts = true rewriteBatchedStatements = true } } repositories { # all repositories with config sections here will be enabled in mysql zone { # no additional settings for repositories enabled in mysql } batch-change { } user { } record-set { } } } } Cryptography Settings VinylDNS uses symmetric cryptography in order to encrypt/decrypt sensitive information in the system. This includes TSIG keys and user secrets. Cryptography is used in both the portal as well as the api. Cryptography is pluggable, meaning you can bring your own crypto with you. All that is required is to provide an implementation of CryptoAlgebra using a crypto library of choice. The default implementation is NoOpCrypto, which does not do any encryption (not recommended for production). VinylDNS provides a cryptography implementation called JavaCrypto that you can use for production. The example that follows illustrates using the provided JavaCrypto. If you create your own implementation, you have to build your jar and make it (and all dependencies) available to the VinylDNS API and the VinylDNS portal. The following are the configuration settings for crypto. Notice here the only thing we see is the type. The type is the fully qualified class name for the CryptoAlgebra you will be using. If your crypto implementation requires additional settings, they will be configured inside the crypto element, adjacent to the type. vinyldns { crypto { type = \"vinyldns.core.crypto.JavaCrypto\" secret = \"8B06A7F3BC8A2497736F1916A123AA40E88217BE9264D8872597EF7A6E5DCE61\" } } Default Zone Connections VinylDNS has three ways of indicating zone connections: Global default connection applies to all zones unless overridden by one of the following connections. This configuration is required. Backends allows you to specify zone connection information for an individual zone by choosing a pre-configured zone connection. This configuration is optional. Zone level override allows you to specify zone update and transfer connection information for each zone. More information is in the Zone Model. VinylDNS has 2 connections for each zone: The DDNS connection - used for making DDNS updates to the zone The Transfer connection - used for making AXFR requests for zone syncing with the DNS backend VinylDNS also ties in testing network connectivity to the default zone connection’s primary server into its API health checks. A value for the health check connection timeout in milliseconds can be specified using health-check-timeout; a default value of 10000 will be used if not provided. vinyldns { # timeout for DNS backend connectivity health check health-check-timeout = 5000 # the DDNS connection information for the default dns backend defaultZoneConnection { # this is not really used, but must be set, usually set to the keyName itself, or a descriptive name if you are interested name = \"vinyldns.\" # the name of the TSIG key keyName = \"vinyldns.\" # the TSIG secret key key = \"nzisn+4G2ldMn0q1CV3vsg==\" # the host name or IP address, note you can add a port if not using the default by settings hostname:port primaryServer = \"ddns1.foo.bar.com\" # the key algorithm to use: HMAC-MD5, HMAC-SHA1, HMAC-SHA224, HMAC-SHA256, HMAC-SHA384, HMAC-SHA512 algorithm = \"HMAC-MD5\" } # the AXFR connection information for the default dns backend defaultTransferConnection { name = \"vinyldns.\" keyName = \"vinyldns.\" key = \"nzisn+4G2ldMn0q1CV3vsg==\" primaryServer = \"localhost:19001\" algorithm = \"HMAC-MD5\" } } # Zone Connection Data, ID can be specified in a zone to override the global default configuration backends = [ { id = \"test-backend-id\" zone-connection { name = \"vinyldns.\" key-name = \"vinyldns.\" key = \"nzisn+4G2ldMn0q1CV3vsg==\" primary-server = \"127.0.0.1:19001\" algorithm = \"HMAC-MD5\" } transfer-connection { name = \"vinyldns.\" key-name = \"vinyldns.\" key = \"nzisn+4G2ldMn0q1CV3vsg==\" primary-server = \"127.0.0.1:19001\" algorithm = \"HMAC-MD5\" } } ] Additional Configuration Settings Approved Name Servers When running a large DNS installation, allowing users the ability to self-manage zone delegations can lead to a lot of problems when not done properly. Also, allowing delegation to untrusted DNS servers can be a security risk. To “lock down” zone delegation, you can configure name servers that you trust, so zone delegation is controlled. The entries in the list can be host names, IP addresses, or regular expressions. approved-name-servers = [ \"172.17.42.1.\", \"ddns1.foo.bar.\", \".*awsdns.*\" ] Processing Disabled The processing disabled flag can be used if doing a blue/green deployment. When processing is disabled, the VinylDNS engine will not be actively polling the message queue for messages. processing-disabled = false | true Color For blue-green deployments, you can configure the color of the current node. Not applicable to every environment. color = \"green\" Version Version of the application that is deployed. Currently, this is a configuration value. version = \"0.8.0\" Note: You can get installation information including color, version, default key name, and processing-disabled by hitting the status endpoint GET /status HTTP Host and Port To specify what host and port to bind to when starting up the API server, default is 9000. rest { host = \"0.0.0.0\" port = 9000 } Sync Delay VinylDNS uses a “sync-delay” setting that prevents users from syncing their zones too frequently. The settings is inspected per zone, and is the number of milliseconds since the last sync to wait before allowing another sync for that zone. sync-delay = 10000 Notifiers VinylDNS provides the ability to send notifications via configured notifiers when a batch change is either implemented or rejected. Notifiers in VinylDNS are designed to be pluggable (ie. bring-your-own-implementation), granting users the flexibility to implement their own which can smoothly integrate into their instance. Setup requires a notifiers key which contains all of the configured notifiers that will be used by the running instance. notifiers = [\"email\", \"sns\"] E-mail notifier Configuration for the e-mail notifier appears like the following: email = { # Path to notifier provider implementation class-name = \"vinyldns.api.notifier.email.EmailNotifierProvider\" settings = { # Sender address for e-mail notifications from = \"Sender <do-not-reply@example.sender>\" smtp { # Host SMTP server host = \"example.host\" } } } Note that settings.from and settings.smtp are both required, though the smtp values requirements depend on the specific exchange service that you are interfacing with. Below is an example e-mail notification: AWD Simple Notification Service (SNS) notifier Configuration for the AWS SNS notifier appears like the following: sns { # Path to notifier provider implementation class-name = \"vinyldns.api.notifier.sns.SnsNotifierProvider\" settings { # SNS topic Amazon Resource Name (ARN) topic-arn = \"arn:aws:sns:us-east-1:000000000000:batchChanges\" # AWS access key and secret access-key = \"vinyldnsTest\" secret-key = \"notNeededForSnsLocal\" # Endpoint to access SNS service-endpoint = \"http://127.0.0.1:19006\" # Regional endpoint to make your requests (eg. 'us-west-2', 'us-east-1', etc.). This is the region where your SNS is housed. signing-region = \"us-east-1\" } } Batch Manual Review Enabled Configuration setting that determines whether batch changes with non-fatal errors can be reviewed rather than failing immediately. When enabling manual review, the expectation is that a DNS technician is actively querying and addressing batch change requests that are in a manual review state. If your process flow does not accommodate this expectation, we advise disabling manual review. manual-batch-review-enabled = true Manual Review Domains Configuration setting that determines what Batch Change/DNS Change input names require manual review if manual-batch-review-enabled is set to true. If manual-batch-review-enabled is set to false any input names that match entries in the configured list will be treated as fatal errors. manual-review-domains = { domain-list = [ \"needs-review.*\" ] ip-list = [ \"192.0.2.254\", \"192.0.2.255\", \"fd69:27cc:fe91:0:0:0:ffff:1\", \"fd69:27cc:fe91:0:0:0:ffff:2\" ] zone-name-list = [ \"zone.requires.review.\" ] } Scheduled Batch Changes Enabled Configuration setting that determines if users are able to make Batch Changes with a scheduled time. manual-batch-review-enabled must be enabled as well. If enabled, a VinylDNS administrator cannot approve the Batch Change until after the scheduled time. An administrator could also reject the Batch Change. scheduled-changes-enabled = true IPv6 Zone Discovery Boundaries Configuration setting that determines the range that will be searched for in reverse IPv6 Zone Discovery. This allows you to limit the search for what is appropriate for your organization. For example, min = 2, max = 3 will only search in zones in the form X.X.ip6.arpa. and X.X.X.ip6.arpa.. Note the following constraints: 0 < min <= max <= 32. If your organization only makes zone cuts at one point, you may set min == max. The default values if omitted are min = 5, max = 20. v6-discovery-nibble-boundaries { min = 5 max = 20 } Full Example Config # The default application.conf is not intended to be used in production. It assumes a docker-compose # setup for all of the services. Provide your own application.conf on the docker mount with your # own settings vinyldns { queue { class-name = \"vinyldns.sqs.queue.SqsMessageQueueProvider\" messages-per-poll = 10 polling-interval = 250.millis settings { # AWS access key and secret. access-key = \"x\" secret-key = \"x\" # Regional endpoint to make your requests (eg. 'us-west-2', 'us-east-1', etc.). This is the region where your queue is housed. signing-region = \"x\" # Endpoint to access queue service-endpoint = \"http://localhost:9324/\" # Queue name. Should be used in conjunction with service endpoint, rather than using a queue url which is subject to change. queue-name = \"vinyldns\" } } # host and port the server binds to. This should not be changed rest { host = \"0.0.0.0\" port = 9000 } # The maximum number of records VinylDNS will load when syncing a DNS Zone # this is to prevent possible out of memory errors when loading a Zone # this does not stop the zone from existing in DNS, but you will not be able to manage it in VinylDNS if the number of records exceeds the max max-zone-size = 60000 # the delay between zone syncs so we are not syncing too often sync-delay = 10000 # crypto settings for symmetric cryptography of secrets in the system # Note: for production systems secrets should not live in plain text in a file crypto { type = \"vinyldns.core.crypto.NoOpCrypto\" } # both datastore options are in use data-stores = [\"mysql\"] mysql { class-name = \"vinyldns.mysql.repository.MySqlDataStoreProvider\" settings { name = \"vinyldns\" driver = \"org.mariadb.jdbc.Driver\" migration-url = \"jdbc:mariadb://localhost:19002/?user=root&password=pass\" url = \"jdbc:mariadb://localhost:19002/vinyldns?user=root&password=pass\" user = \"root\" password = \"pass\" maximum-pool-size = 20 minimum-idle = 10 connection-timeout-millis = 1000 idle-timeout = 10000 max-lifetime = 600000 register-mbeans = true my-sql-properties { prepStmtCacheSize = 300 prepStmtCacheSqlLimit = 2048 cachePrepStmts = true useServerPrepStmts = true rewriteBatchedStatements = true } } repositories { zone { } batch-change { } user { } record-set { } group { } membership { } group-change { } zone-change { } record-change { } } } # the DDNS connection information for the default dns backend defaultZoneConnection { name = \"vinyldns.\" keyName = \"vinyldns.\" key = \"nzisn+4G2ldMn0q1CV3vsg==\" primaryServer = \"localhost:19001\" algorithm = \"HMAC-MD5\" } # the AXFR connection information for the default dns backend defaultTransferConnection { name = \"vinyldns.\" keyName = \"vinyldns.\" key = \"nzisn+4G2ldMn0q1CV3vsg==\" primaryServer = \"localhost:19001\" algorithm = \"HMAC-MD5\" } # the max number of changes in a single batch change. Change carefully as this has performance # implications batch-change-limit = 1000 # notifier configuration notifiers = [\"email\", \"sns\"] email = { # Path to notifier provider implementation class-name = \"vinyldns.api.notifier.email.EmailNotifierProvider\" settings = { # Sender address for e-mail notifications from = \"Sender <do-not-reply@example.sender>\" smtp { # Host SMTP server host = \"example.host\" } } sns { # Path to notifier provider implementation class-name = \"vinyldns.api.notifier.sns.SnsNotifierProvider\" settings { # SNS topic Amazon Resource Name (ARN) topic-arn = \"arn:aws:sns:us-east-1:000000000000:batchChanges\" # AWS access key and secret access-key = \"vinyldnsTest\" secret-key = \"notNeededForSnsLocal\" # Endpoint to access SNS service-endpoint = \"http://127.0.0.1:19006\" # Regional endpoint to make your requests (eg. 'us-west-2', 'us-east-1', etc.). This is the region where your SNS is housed. signing-region = \"us-east-1\" } } # true if you want to enable manual review for non-fatal errors manual-batch-review-enabled = true # true if you want to allow Batch Changes to be scheduled. manual-batch-review-enabled must also be true. scheduled-changes-enabled = true # types of unowned records that users can access in shared zones shared-approved-types = [\"A\", \"AAAA\", \"CNAME\", \"PTR\", \"TXT\"] # FQDNs / IPs that cannot be modified via VinylDNS # regex-list: list of regular expressions matching any FQDN that are not allowed to be modified by this VinylDNS instance # ip-list: list of IP addresses that cannot be modified by this VinylDNS instance high-value-domains = { regex-list = [ \"high-value-domain.*\" ] ip-list = [ \"192.0.2.252\", \"192.0.2.253\", \"fd69:27cc:fe91:0:0:0:0:ffff\", \"fd69:27cc:fe91:0:0:0:ffff:0\" ] } # FQDNS / IPs / zone names that require manual review when submitted through Batch Change/DNS Change # Treated as a fatal error if manual review is not enabled manual-review-domains = { domain-list = [ \"needs-review.*\" ] ip-list = [ \"192.0.2.254\", \"192.0.2.255\", \"fd69:27cc:fe91:0:0:0:ffff:1\", \"fd69:27cc:fe91:0:0:0:ffff:2\" ] zone-name-list = [ \"zone.requires.review.\" ] } # Zone Connection Data backends = [ { id = \"test-backend-id\" zone-connection { name = \"vinyldns.\" key-name = \"vinyldns.\" key = \"nzisn+4G2ldMn0q1CV3vsg==\" primary-server = \"127.0.0.1:19001\" algorithm = \"HMAC-MD5\" } transfer-connection { name = \"vinyldns.\" key-name = \"vinyldns.\" key = \"nzisn+4G2ldMn0q1CV3vsg==\" primary-server = \"127.0.0.1:19001\" algorithm = \"HMAC-MD5\" } } ] } # Akka settings, these should not need to be modified unless you know akka http really well. akka { loglevel = \"INFO\" loggers = [\"akka.event.slf4j.Slf4jLogger\"] logging-filter = \"akka.event.slf4j.Slf4jLoggingFilter\" logger-startup-timeout = 30s } akka.http { server { # The time period within which the TCP binding process must be completed. # Set to `infinite` to disable. bind-timeout = 5s # Show verbose error messages back to the client verbose-error-messages = on } parsing { # akka-http doesn't like the AWS4 headers illegal-header-warnings = on } } }" - } , - { - "title": "Portal Configuration Guide", - "url": "/operator/config-portal.html", - "content": "Portal Configuration Guide The portal configuration is much smaller than the API Server. Note: Unlike the API server, not all configuration resides under a vinyldns namespace. Configuration Database Configuration LDAP Cryptography Custom Links Additional Configuration Settings Full Example Config Database Configuration VinylDNS supports a MySQL backend (see API Database Configuration). Follow the MySQL Setup Guide first to get the values you need to configure here. The Portal uses the following tables: user userChanges Note that the user table is shared between the API and the portal, and must be configured with the same values in both configs: vinyldns { # this list should include only the datastores being used by your portal instance (user and userChange repo) data-stores = [\"mysql\"] mysql { # this is the path to the mysql provider. This should not be edited # from the default in reference.conf class-name = \"vinyldns.mysql.repository.MySqlDataStoreProvider\" settings { # the name of the database, recommend to leave this as is name = \"vinyldns\" # the jdbc driver, recommended to leave this as is driver = \"org.mariadb.jdbc.Driver\" # the URL used to create the schema, typically this will be without the \"database\" name migration-url = \"jdbc:mariadb://localhost:19002/?user=root&password=pass\" # the main connection URL url = \"jdbc:mariadb://localhost:19002/vinyldns?user=root&password=pass\" # the user to connect to MySQL user = \"root\" # the password to connect to MySQL password = \"pass\" ## see https://github.com/brettwooldridge/HikariCP for more detail on the following fields # the maximum number of connections to scale the connection pool to maximum-pool-size = 20 # the maximum number of milliseconds to wait for a connection from the connection pool connection-timeout-millis = 1000 # the minimum number of idle connections that HikariCP tries to maintain in the pool minimum-idle = 10 # the maximum number of milliseconds that a connection is can sit idle in the pool idle-timeout = 10000 # The max lifetime of a connection in a pool. Should be several seconds shorter than the database imposed connection time limit max-lifetime = 600000 # controls whether JMX MBeans are registered register-mbeans = true # my-sql-properties allows you to include any additional mysql performance settings you want. # Note that the properties within my-sql-properties must be camel case! # see https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration for guidance my-sql-properties { prepStmtCacheSize = 300 prepStmtCacheSqlLimit = 2048 cachePrepStmts = true useServerPrepStmts = true rewriteBatchedStatements = true } } repositories { # all repositories with config sections here will be enabled in mysql user { # no additional settings for repositories enabled in mysql } } } } LDAP Be sure to follow the LDAP Setup Guide first to get the values you need to configure here. LDAP configuration connects VinylDNS to your Directory where user information is stored. The default value for user sync enabled is false and user sync hours polling interval is 24 (max value). If the hours polling interval is configured higher than 24, 24 hours will be used. LDAP { # The name of the user to connect VinylDNS to LDAP user=\"test\" # The password for the user to connect VinylDNS to LDAP password=\"test\" # The domain for the user connecting VinylDNS to LDAP domain=\"test\" # One or more search bases to find users. If users come from multiple domains, list them here searchBase = [{organization = \"someDomain\", domainName = \"DC=test,DC=test,DC=com\"}, {organization = \"anotherDomain\", domainName = \"DC=test,DC=com\"}] # Connection information to LDAP context { initialContextFactory = \"com.sun.jndi.ldap.LdapCtxFactory\" securityAuthentication = \"simple\" # Set this to point to your LDAP providerUrl = \"ldaps://somedomain.com:9999\" } user-sync { enabled = true # Default value is false hours-polling-interval = 12 # Default value is 24 } } Cryptography Settings The Portal encrypts user secrets at rest using the same mechanism as the API server. Note: It is extremely important that these settings match the API server, otherwise the API server will not be able to decrypt user secrets and your installation will fail! Cryptography is pluggable, meaning you can bring your own crypto with you. All that is required is to provide an implementation of CryptoAlgebra using a crypto library of choice. The default implementation is NoOpCrypto, which does not do any encryption (not recommended for production). The following are the configuration settings for crypto. Notice here the only thing we see is the type. The type is the fully qualified class name for the CryptoAlgebra you will be using. If your crypto implementation requires additional settings, they will be configured inside the crypto element, adjacent to the type. crypto { type = \"vinyldns.core.crypto.JavaCrypto\" secret = \"8B06A7F3BC8A2497736F1916A123AA40E88217BE9264D8872597EF7A6E5DCE61\" } Custom Links Custom links display either on the nav bar once logged in, or on the log in screen. These links are useful to point to internal documentation and procedures. For example, how to raise certain tickets with engineering, or internal slack channels. # an array of links links = [ { # indicates that this link should be display on the sidebar once logged in displayOnSidebar = true # display this link also on the login screen displayOnLoginScreen = true # text to display for the link title = \"API Documentation\" # the hyperlink address being linked to href = \"https://vinyldns.io\" # a fa icon to display icon = \"fa fa-file-text-o\" } ] Additional Configuration Settings Play Secret The play secret must be set to a secret value, and should be an environment variable # See https://www.playframework.com/documentation/latest/ApplicationSecret for more details. play.http.secret.key = \"vinyldnsportal-change-this-for-production\" Test Login The test login should not be used for production environments. It is useful to tinker with VinylDNS. If this setting is true, then you can login with testuser and testpassword. Logging in using the testuser will not contact LDAP. portal.test_login = false HTTP Port The HTTP Port that the Portal server will bind to http.port=9001 Shared Zones Display / Record Owner Selection Necessary to enable shared zones submission and record ownership shared-display-enabled = true Batch Change Limit How many changes are allowable in a single DNS change request batch-change-limit = 1000 Manual Review Enabled Triggers the manual review process for certain DNS requests manual-batch-review-enabled = true Scheduled Changes Allows users to schedule changes to be run sometime in the future scheduled-changes-enabled = true Full Example Config # This is the main configuration file for the application. # ~~~~~ # Secret key # ~~~~~ # The secret key is used to secure cryptographics functions. # # This must be changed for production, but we recommend not changing it in this file. # # See https://www.playframework.com/documentation/latest/ApplicationSecret for more details. play.http.secret.key = \"vinyldnsportal-change-this-for-production\" # The application languages # ~~~~~ play.i18n.langs = [ \"en\" ] portal.vinyldns.backend.url = \"http://vinyldns-api:9000\" portal.test_login = false # configuration for the users and groups store data-stores = [\"mysql\"] mysql { class-name = \"vinyldns.mysql.repository.MySqlDataStoreProvider\" settings { name = \"vinyldns\" driver = \"org.mariadb.jdbc.Driver\" migration-url = \"jdbc:mariadb://localhost:19002/?user=root&password=pass\" url = \"jdbc:mariadb://localhost:19002/vinyldns?user=root&password=pass\" user = \"root\" password = \"pass\" maximum-pool-size = 20 minimum-idle = 10 connection-timeout-millis = 1000 idle-timeout = 10000 max-lifetime = 600000 register-mbeans = true my-sql-properties { prepStmtCacheSize = 300 prepStmtCacheSqlLimit = 2048 cachePrepStmts = true useServerPrepStmts = true rewriteBatchedStatements = true } } repositories { user { } } } } play.filters.enabled += \"play.filters.csrf.CSRFFilter\" # Expire session after 10 hours play.http.session.maxAge = 10h # session secure should be false in order to run properly locally, this is set properly on deployment play.http.session.secure = false play.http.session.httpOnly = true # use no-op by default crypto { type = \"vinyldns.core.crypto.NoOpCrypto\" } http.port=9001 links = [ { displayOnSidebar = true displayOnLoginScreen = true title = \"API Documentation\" href = \"https://vinyldns.io\" icon = \"fa fa-file-text-o\" } ]" - } , - { - "title": "Connect to your Zone", - "url": "/portal/connect-to-zone.html", - "content": "Connect to your Zone Once your zone is setup for use with VinylDNS, you can use the VinylDNS portal to connect to it. If you don’t already have an admin group in VinylDNS for your zone select the Groups link in the navigation and create an admin group for your zone. Members of the group will have full access to the zone. See Manage Access for more details. Select the Zones link from the navigation, then click the Connect button. This will show the Connect to a Zone form. Enter the full name of the zone, example “test.sys.example.com” Enter the email distribution list for the zone. This is typically a distribution list email for the team that owns the zone. Select the admin group for the zone. If you do not have any custom TSIG keys, you can leave the connection information empty. If you do have custom TSIG keys, read the section on Understand Connections. Click the Connect button at the bottom of the form. You may have to click the Refresh button from the zone list to see your new zone. If you see error messages, please consult the FAQ." - } , - { - "title": "Understand Connections", - "url": "/portal/connections.html", - "content": "Understand Connections VinylDNS provides the ability to specify two different connections to the backend DNS servers. The primary connection is used for issuing DNS updates The transfer connection is used for syncing DNS data with VinylDNS If you do not have any keys, then you can leave this information empty. VinylDNS will assume a set of default keys that should provide the access VinylDNS needs to manage your zone. If you have an existing TSIG key that you are using for issuing DDNS updates to DNS, and you wish to continue to use it, you must request that your zone be setup to allow transfers from VinylDNS. Note: If you make any changes outside of VinylDNS they will not be reflected in VinylDNS unless you manually sync the zone. If you have an existing TSIG key that you are using for issuing DDNS updates, and you no longer need the key, please contact your VinylDNS administrators to ensure that the key is revoked and the zone is setup with the default VinylDNS TSIG key. Once your key is revoked, you can leave the connections empty in which case VinylDNS will assume the default keys and they should work." - } , - { - "title": "Contributing", - "url": "/extra_md/contributing.html", - "content": "Contributing to VinylDNS The following are a set of guidelines for contributing to VinylDNS and its associated repositories. Table of Contents Code of Conduct Issues Working on an Issue Submitting an Issue Discussion Process Pull Requests General Flow Pull Request Requirements Commit Messages Testing Documentation Edits Style Guides License Header Checks Contributor License Agreement Modifying your Pull Request Pull Request Approval Code of Conduct This project and everyone participating in it are governed by the VinylDNS Code Of Conduct. By participating, you agree to this Code. Issues Work on VinylDNS is tracked by GitHub Issues. To contribute to VinylDNS, you can join the discussion on an issue, submit a Pull Request to resolve the issue, or make an issue of your own. VinylDNS issues are generally labeled as bug reports, feature requests, or maintenance requests. Working on an Issue If you would like to contribute to VinylDNS, you can look through good first issue and help wanted issues. We keep a list of these issues around to encourage participation in building the platform. In the issue list, you can chose “ Labels” and choose a specific label to narrow down the issues to review. Beginner issues: only require a few lines of code to complete, rather isolated to one or two files. A good way to get through changing and testing your code, and meet everyone! Help wanted issues: these are more involved than beginner issues, are items that tend to come near the top of our backlog but not necessarily in the current development stream. Besides those issues, you can sort the issue list by number of comments to find one that may be of interest. You do not have to limit yourself to only good first issue or help wanted issues. When resolving an issue, you generally will do so by making a Pull Request, and adding a link to the issue. Before choosing an issue, see if anyone is assigned or has indicated they are working on it (either in comment or via Pull Request). If that is the case, then instead of making a Pull Request of your own, you can help out by reviewing their Pull Request. Submitting an Issue When submitting an issue you will notice there are three issue templates to choose from. Before making any issue, please go search the issue list (open and closed issues) and check to see if a similar issue has been made. If so, we ask that you do not duplicate an issue, but feel free to comment on the existing issue with additional details. Bug report: If you find a bug in the project you can report it with this template and the VinylDNS team will take a look at it. Please be as detailed as possible as it will help us recreate the bug and figure out what exactly is going on. If you are unsure whether what you found is a bug, we encourage you to first pop in our discussion board, and we can help determine if what you’re seeing is unexpected behavior, and if it is we will direct to make the bug report. Feature request: Use this template if you have something you wish to be added to the project. Please be detailed when describing why you are requesting the feature, what you want it to do, and alternative solutions you have considered. Discussion Process Some issues may require discussion with the community before proceeding to implementation. This can happen if the issue is a larger change, for example a big refactoring or new feature. The VinylDNS maintainers may label an issue for ** Discussion** in order to solicit more detail before proceeding. If the issue is straightforward and/or well documented, it can be implemented immediately by the submitter. If the submitter is unable to make the changes required to address the issue, the VinylDNS maintainers will prioritize the work in our backlog. Pull Requests Contributions to VinylDNS are generally made via Github Pull Requests. Most Pull Requests are related to an issue, and will have a link to the issue in the Pull Request. General Flow We follow the standard GitHub Flow for taking code contributions. The following is the process typically followed: Create a fork of the repository that you want to contribute code to Clone your forked repository to your local machine In your local machine, add a remote to the “main” repository, we call this “upstream” by running git remote add upstream https://github.com/vinyldns/vinyldns.git. Note: you can also use ssh instead of https Create a local branch for your work git checkout -b your-user-name/user-branch-name. Add whatever your GitHub user name is before whatever you want your branch to be. Begin working on your local branch Be sure to add necessary unit, integration, and functional tests, see the Testing section of the Developer Guide. Make sure you run all builds before posting a Pull Request! It’s faster to run everything locally rather than waiting for the build server to complete its job. See DEVELOPER_GUIDE.md for information on local development. When you are ready to contribute your code, run git push origin your-user-name/user-branch-name to push your changes to your own fork Go to the VinylDNS main repository (or whatever repo you are contributing to) and you will see your change waiting and a link to “Create a Pull Request”. Click the link to create a Pull Request. Be as detailed as possible in the description of your Pull Request. Describe what you changed, why you changed it, and give a detailed list of changes and impacted files. If your Pull Request is related to an existing issue, be sure to link the issue in the Pull Request itself, in addition to the Pull Request description. You will receive comments on your Pull Request. Use the Pull Request as a dialog on your changes. Pull Request Requirements Commit Messages Limit the first line to 72 characters or fewer. Use the present tense (“Add validation” not “Added validation”). Use the imperative mood (“Move database call” not “Moves database call”). Reference issues and other pull requests liberally after the first line. Use GitHub Auto Linking to link your Pull Request to other issues. Use markdown syntax as much as you want Testing When making changes to the VinylDNS codebase, be sure to add necessary unit, integration, and functional tests. For specifics on our tests, see the Testing section of the Developer Guide. Documentation Edits Documentation for the VinylDNS project lives in files such as this one in the root of the project directory, as well as in modules/docs/src/main/mdoc for the docs you see on vinyldns.io. Many changes, such as those that impact an API endpoint, config, portal usage, etc, will also need corresponding documentation edited to prevent it from going stale. The VinylDNS gh-pages branch README has information on how to run and edit the documentation page. Style Guides For Scala code we use Scalastyle. The configs are scalastyle-config.xml and scalastyle-test-config.xml for source code and test code respectively We have it set to fail builds if the styling rules are not followed. For example, one of our rules is that all lines must be <= 120 characters, and a build will fail if that is violated. For our python code that we use for functional testing, we generally try to follow PEP 8 License Header Checks VinylDNS is configured with sbt-header. All existing scala files have the appropriate header. To add or check for headers, follow these steps: API You can check for headers in the API in sbt with: > ;project api;headerCheck;test:headerCheck;it:headerCheck If you add a new file, you can add the appropriate header in sbt with: > ;project api;headerCreate;test:headerCreate;it:headerCreate Portal You can check for headers in the Portal in sbt with: > ;project portal;headerCheck;test:headerCheck;checkJsHeaders If you add a new file, you can add the appropriate header in sbt with: > ;project portal;headerCreate;test:headerCreate;createJsHeaders Contributor License Agreement Before Comcast merges your code into the project you must sign the Comcast Contributor License Agreement (CLA). If you haven’t previously signed a Comcast CLA, you’ll automatically be asked to when you open a pull request. Alternatively, we can send you a PDF that you can sign and scan back to us. Please create a new GitHub issue to request a PDF version of the CLA. Modifying your Pull Requests Often times, you will need to make revisions to your Pull Requests that you submit. This is part of the standard process of code review. There are different ways that you can make revisions, but the following process is pretty standard. Sync with upstream first. git checkout master && git fetch upstream && git rebase upstream master && git push origin master Checkout your branch on your local git checkout your-user-name/user-branch-name Sync your branch with latest git rebase master. Note: If you have merge conflicts, you will have to resolve them Revise your Pull Request, making changes recommended in the comments / code review Stage and commit these changes on top of your existing commits When all tests pass, git push origin your-user-name/user-branch-name to revise your commit. Note: If you rebased or altered the commit history, you will have to force push with a -f flag. GitHub automatically recognizes the update and will re-run verification on your Pull Request! Pull Request Approval A pull request must satisfy our pull request requirements Afterwards, if a Pull Request is approved, a maintainer of the project will merge it. If you are a maintainer, you can merge your Pull Request once you have the approval of at least 2 other maintainers. Note: The first time you make a Pull Request, add yourself to the authors list here as part of the Pull Request" - } , - { - "title": "Create a Group", - "url": "/portal/create-a-group.html", - "content": "Create a group In the Groups area of the site select the New Group button. This will bring up a form. Enter a name for the group, email address and an optional description. Select the Create button to submit the group information. If all fields are valid you’ll see the group listed in the table on the screen when the form closes." - } , - { - "title": "Create Batch Change", - "url": "/api/create-batchchange.html", - "content": "Create Batch Change Creates a batch change with SingleAddChanges and/or SingleDeleteRRSetChanges across different zones. A delete and add of the same record will be treated as an update on that record set. Regardless of the input order in the batch change, all deletes for the same recordset will be logically applied before the adds. Current supported record types for creating a batch change are: A, AAAA, CNAME, MX, PTR, TXT. A batch must contain at least one change and no more than 20 changes. Supported record types for records in shared zones may vary. Contact your VinylDNS administrators to find the allowed record types. This does not apply to zone administrators or users with specific ACL access rules. HTTP REQUEST POST /zones/batchrecordchanges?allowManualReview={true | false} Note that the batch change request inputs are a subset of the full batch change model. HTTP REQUEST PARAMS name type required? description comments string no Optional comments about the batch change. changes Array of ChangeInput yes Set of ChangeInputs in the batch change. A ChangeInput is an AddChangeInput or DeleteChangeInput. Type is inferred from specified changeType. ownerGroupId string sometimes Record ownership assignment. Required if any records in the batch change are in shared zones and are new or unowned. scheduledTime date-time no Optional datetime. Stored as UTC. Batch change will not be processed until after the scheduled time. Required format is an ISO 8601 date time string. allowManualReview boolean no Optional override to control whether manual review is enabled for the batch change request. Default value is true. Must be passed in as a query parameter, not in the request body. AddChangeInput name type required? description changeType ChangeInputType yes Type of change input. Must be set to Add for AddChangeInput. inputName string yes The fully qualified domain name of the record being added. For PTR, the input name is a valid IPv4 or IPv6 address. type RecordType yes Type of DNS record. Supported records for batch changes are currently: A, AAAA, CNAME, and PTR. ttl long no The time-to-live in seconds. The minimum and maximum values are 30 and 2147483647, respectively. If excluded, this will be set to the system default for new adds, or the existing TTL for updates record RecordData yes The data for the record. DeleteChangeInput name type required? description changeType ChangeInputType yes Type of change input. Must be DeleteRecordSet for DeleteChangeInput. inputName string yes The fully qualified domain name of the record being deleted. type RecordType yes Type of DNS record. Supported records for batch changes are currently: A, AAAA, CNAME, and PTR. record RecordData no The data for the record. If specified, only this DNS entry for the existing DNS recordset will be deleted; if unspecified, the entire DNS recordset will be deleted. EXAMPLE HTTP REQUEST { \"comments\": \"this is optional\", \"ownerGroupId\": \"f42385e4-5675-38c0-b42f-64105e743bfe\", \"changes\": [ { \"inputName\": \"example.com.\", \"changeType\": \"Add\", \"type\": \"A\", \"ttl\": 3600, \"record\": { \"address\": \"1.1.1.1\" } }, { \"inputName\": \"192.0.2.195\", \"changeType\": \"Add\", \"type\": \"PTR\", \"ttl\": 3600, \"record\": { \"ptrdname\": \"ptrdata.data.\" } }, { \"inputName\": \"cname.example.com.\", \"changeType\": \"DeleteRecordSet\", \"type\": \"CNAME\" }, { \"inputName\": \"update.another.example.com.\", \"changeType\": \"DeleteRecordSet\", \"type\": \"AAAA\", \"record\": { \"address\": \"2:3:4:5:6:7:8:9\" } }, { \"inputName\": \"update.another.example.com.\", \"changeType\": \"Add\", \"type\": \"AAAA\", \"ttl\": 4000, \"record\": { \"address\": \"1:2:3:4:5:6:7:8\" } } ] } The first two items in the changes list are SingleAddChanges of an A record and a PTR record. Note that for the PTR record, the inputName is a valid IP address. The third item is a delete of a CNAME record. The last two items represent an update (delete & add) of an AAAA record with the fully qualified domain name “update.another.example.com.”. HTTP RESPONSE TYPES Code description 202 Accepted - The batch change is validated and is returned in the response body. Based on status, the batch will either be sent for immediate backend processing (PendingProcessing) or pending manual review (PendingReview). 400 Bad Request - Error in the batch change. See Batch Change Errors page. 403 Forbidden - The user does not have the access required to perform the action. 413 Request Entity Too Large - Cannot request more than changes in a single batch change request. 422 Unprocessable Entity - the batch does not contain any changes, thus cannot be processed. A batch change goes through numerous validations before it is processed. This results in corresponding BadRequest or error responses. View the full list of batch change errors here. HTTP RESPONSE ATTRIBUTES On success, the response from create batch change includes the fields the user input, as well as some additional information provided by the system. This response is the same as that of get batch change. EXAMPLE RESPONSE { \"userId\": \"vinyl\", \"userName\": \"vinyl201\", \"comments\": \"this is optional\", \"createdTimestamp\": \"2018-05-09T14:19:34Z\", \"ownerGroupId\": \"f42385e4-5675-38c0-b42f-64105e743bfe\" \"changes\": [ { \"changeType\": \"Add\", \"inputName\": \"example.com.\", \"type\": \"A\", \"ttl\": 3600, \"record\": { \"address\": \"1.1.1.1\" }, \"status\": \"Pending\", \"recordName\": \"example.com.\", \"zoneName\": \"example.com.\", \"zoneId\": \"74e93bfc-7296-4b86-83d3-1ffcb0eb3d13\", \"validationErrors\": [], \"id\": \"7573ca11-3e30-45a8-9ba5-791f7d6ae7a7\" }, { \"changeType\": \"Add\", \"inputName\": \"192.0.2.195\", \"type\": \"PTR\", \"ttl\": 3600, \"record\": { \"ptrdname\": \"ptrdata.data.\" }, \"status\": \"Pending\", \"recordName\": \"195\", \"zoneName\": \"2.0.192.in-addr.arpa.\", \"zoneId\": \"7fd52634-5a0c-11e8-9c2d-fa7ae01bbebc\", \"validationErrors\": [], \"id\": \"bece5338-5a0c-11e8-9c2d-fa7ae01bbebc\" }, { \"changeType\": \"DeleteRecordSet\", \"inputName\": \"cname.example.com.\", \"type\": \"CNAME\", \"status\": \"Pending\", \"recordName\": \"cname\", \"zoneName\": \"example.com.\", \"zoneId\": \"74e93bfc-7296-4b86-83d3-1ffcb0eb3d13\", \"validationErrors\": [], \"id\": \"02048500-5a0d-11e8-a10f-fa7ae01bbebc\" }, { \"changeType\": \"DeleteRecordSet\", \"inputName\": \"update.example.com.\", \"type\": \"AAAA\", \"status\": \"Pending\", \"recordName\": \"update\", \"zoneName\": \"example.com.\", \"zoneId\": \"74e93bfc-7296-4b86-83d3-1ffcb0eb3d13\", \"validationErrors\": [], \"id\": \"1cee1c78-5a0d-11e8-9c2d-fa7ae01bbebc\" }, { \"changeType\": \"Add\", \"inputName\": \"update.another.example.com.\", \"type\": \"AAAA\", \"ttl\": 3600, \"record\": { \"address\": \"1:2:3:4:5:6:7:8\" }, \"status\": \"Pending\", \"recordName\": \"update\", \"zoneName\": \"another.example.com.\", \"zoneId\": \"7fd52634-5a0c-11e8-9c2d-fa7ae01bbebc\", \"validationErrors\": [], \"id\": \"43dd1226-5a0d-11e8-9c2d-fa7ae01bbebc\" } ], \"status\": \"PendingProcessing\", \"id\": \"02bd95f4-a32c-443b-82eb-54dbaa55b31a\" }" - } , - { - "title": "Create Group", - "url": "/api/create-group.html", - "content": "Create Group Creates a Group in VinylDNS HTTP REQUEST POST /groups HTTP REQUEST PARAMS name type required? description name string yes The name of the group. Should be one word, use hyphens if needed but no spaces email string yes The email distribution list for the group description string no A short description of the group if more info is needed other than the name members Array of User id objects yes Set of User ids in the group admins Array of User id objects yes Set of User ids that are admins of the group. All admin user ids should also be in the members array EXAMPLE HTTP REQUEST { \"name\": \"some-group\", \"email\": \"test@example.com\", \"description\": \"an example group\", \"members\": [ { \"id\": \"2764183c-5e75-4ae6-8833-503cd5f4dcb0\" } ], \"admins\": [ { \"id\": \"2764183c-5e75-4ae6-8833-503cd5f4dcb0\" } ] } HTTP RESPONSE TYPES Code description 200 OK - The group has been created and the group info is returned in the response body 400 Bad Request - The group was invalid 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 404 Not Found - A user id was not found 409 Conflict - A group with the same name already exists HTTP RESPONSE ATTRIBUTES name type description id string Unique UUID of the group name string The name of the group email string The email distribution list of the group description string The group description, the group will not have this attribute if it was not included in the create request created string The timestamp (UTC) the group was created status string Active or Deleted, in this case Active members Array of User ID objects IDs of members of the group including admins admins Array of User ID objects IDs of admins of the group EXAMPLE RESPONSE { \"id\": \"6f8afcda-7529-4cad-9f2d-76903f4b1aca\", \"name\": \"some-group\", \"email\": \"test@example.com\", \"description\": \"an example group\", \"created\": \"2017-03-02T15:29:21Z\", \"status\": \"Active\", \"members\": [ { \"id\": \"2764183c-5e75-4ae6-8833-503cd5f4dcb0\" } ], \"admins\": [ { \"id\": \"2764183c-5e75-4ae6-8833-503cd5f4dcb0\" } ] }" - } , - { - "title": "Create RecordSet", - "url": "/api/create-recordset.html", - "content": "Create RecordSet Creates a RecordSet in a specified zone HTTP REQUEST POST /zones/{zoneId}/recordsets HTTP REQUEST PARAMS name type required? description zoneId string yes id of the zone where the recordset belongs name string yes the name of the recordset being updated type string yes the type of recordset ttl integer yes the TTL in seconds records array of record data yes record data for recordset, see RecordSet Model ownerGroupId string no Record ownership assignment, applicable if the recordset is in a shared zone EXAMPLE HTTP REQUEST { \"name\": \"foo\", \"type\": \"A\", \"ttl\": 300, \"records\": [ { \"address\": \"10.10.10.10\" } ], \"zoneId\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"ownerGroupId\": \"f42385e4-5675-38c0-b42f-64105e743bfe\" } HTTP RESPONSE TYPES Code description 202 Accepted - The record set is valid and has been accepted for processing; the record set change resource is returned 400 Bad Request - The zone specified is not Active; typically because the zone has no connection information 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 403 Forbidden - The user does not have the access required to perform the action 404 Not Found - the zone with the id specified was not found 409 Conflict - A record set with the same name and type already exists in the zone 422 Unprocessable Entity HTTP RESPONSE ATTRIBUTES name type description zone map Contains information about the zone when the change was created recordSet map Contains the recordset model userId string The user id that initiated the change changeType string Type of change requested (Create, Update, Delete); in this case Create created string The timestamp (UTC) the change was initiated id string The ID of the change. This is not the ID of the recordset status RecordSetChangeStatus The status of the change (Pending, Complete, or Failed) singleBatchChangeIds array of SingleBatchChange Id objects If the recordset change was part of a batch change, the IDs of the single changes that comprise the recordset change EXAMPLE RESPONSE { \"zone\": { \"name\": \"vinyl.\", \"email\": \"test@test.com\", \"status\": \"Active\", \"created\": \"2017-02-23T14:52:44Z\", \"id\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"account\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\", \"shared\": false, \"acl\": { \"rules\": [ ] }, \"adminGroupId\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\" }, \"recordSet\": { \"type\": \"A\", \"zoneId\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"name\": \"foo\", \"ttl\": 300, \"status\": \"Pending\", \"created\": \"2017-02-23T14:58:54Z\", \"records\": [ { \"address\": \"10.10.10.10\" } ], \"id\": \"9a41b99c-8e67-445f-bcf3-f9c7cd1f2357\", \"account\": \"0215d410-9b7e-4636-89fd-b6b948a06347\", \"ownerGroupId\": \"f42385e4-5675-38c0-b42f-64105e743bfe\", \"ownerGroupName\": \"Shared Group\" }, \"userId\": \"0215d410-9b7e-4636-89fd-b6b948a06347\", \"changeType\": \"Create\", \"status\": \"Pending\", \"created\": \"2017-02-23T14:58:54Z\", \"id\": \"fef81f0b-f439-462d-88df-c773d3686c9b\", \"singleBatchChangeIds\": [] }" - } , - { - "title": "Create Zone", - "url": "/api/create-zone.html", - "content": "Create Zone Connects user to an existing zone. User must be a member of the group that has access to the zone. Connection info is optional, if no info is provided the default VinylDNS connections will be used HTTP REQUEST POST /zones HTTP REQUEST PARAMS zone fields - adminGroupId, name, and email are required - refer to zone model EXAMPLE HTTP REQUEST { \"adminGroupId\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\", \"name\": \"dummy.\", \"email\": \"test@example.com\" } HTTP RESPONSE TYPES Code description 202 Accepted - The zone change is queued and is returned in the response body 400 Bad Request - Connection failed, or group did not have access to the zone 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 403 Forbidden - the user does not have the access required to perform the action 409 Conflict - Zone already connected to HTTP RESPONSE ATTRIBUTES name type description status string Status of zone change zone map Refer to zone model created string The timestamp (UTC) the change was initiated changeType string Type of change requested (Create, Update, Sync, Delete); in this case Create userId string The user id that initiated the change id string The ID of the change. This is not the ID of the zone EXAMPLE RESPONSE { \"status\": \"Pending\", \"zone\": { \"status\": \"Pending\", \"account\": \"test_group\", \"name\": \"488e6063-7832-40f6-87d3-87dae50c690a.\", \"created\": \"2016-12-28T18:00:32Z\", \"adminGroupId\": \"test-group-id\", \"email\": \"test@test.com\", \"shared\": false, \"acl\": { \"rules\": [ ] }, \"id\": \"8ba20b72-cfdb-49d3-9216-9100aeaee7fc\" }, \"created\": \"2016-12-28T18:00:32Z\", \"changeType\": \"Create\", \"userId\": \"vinyl\", \"id\": \"dd449c27-bed5-4cd5-95e6-4c54fb20d930\" }" - } , - { - "title": "Credentials", - "url": "/portal/credentials.html", - "content": "Credentials In order to use tooling to access VinylDNS, all users must download their credentials from the VinylDNS portal. The credentials are located in the User Menu in the top right corner of the site after login. Regenerate Credentials If your credentials are compromised you can generate new ones. In the User Menu select Regenerate Credentials. Regenerating your credentials will invalidate your previous credentials. If you are using any VinylDNS tools beyond the portal you can then select Download Credentials to retrieve your new credentials and update the tools you use." - } , - { - "title": "Delete Group", - "url": "/api/delete-group.html", - "content": "Delete Group Deletes a Group in VinylDNS HTTP REQUEST DELETE /groups/{groupId} HTTP RESPONSE TYPES Code description 200 OK - The group has been delete and the group info is returned in the response body 400 Bad Request - The group could not be deleted 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 403 Forbidden - The user does not have the access required to perform the action 404 Not Found - The group was not found HTTP RESPONSE ATTRIBUTES name type description id string Unique UUID of the group name map The name of the group email string The email distribution list of the group description string The group description, the group will not have this attribute if it was not set created string The timestamp (UTC) the group was created status string Active or Deleted, in this case Deleted members Array of User ID objects IDs of members of the group including admins admins Array of User ID objects IDs of admins of the group EXAMPLE RESPONSE { \"id\": \"6f8afcda-7529-4cad-9f2d-76903f4b1aca\", \"name\": \"some-group\", \"email\": \"test@example.com\", \"created\": \"2017-03-02T15:29:21Z\", \"status\": \"Deleted\", \"members\": [ { \"id\": \"2764183c-5e75-4ae6-8833-503cd5f4dcb0\" }, { \"id\": \"c8630ebc-0af2-4c9a-a0a0-d18c590ed03e\" } ], \"admins\": [ { \"id\": \"2764183c-5e75-4ae6-8833-503cd5f4dcb0\" } ] }" - } , - { - "title": "Delete RecordSet", - "url": "/api/delete-recordset.html", - "content": "Delete RecordSet Delete a RecordSet in a specified zone HTTP REQUEST DELETE /zones/{zoneId}/recordsets/{recordSetId} HTTP RESPONSE TYPES Code description 202 Accepted - the delete is valid and has been accepted for processing; the record set change resource is returned in the response body 400 Bad Request - the zone being updated is not active; typically because the connection information does not exist for the zone 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 403 Forbidden - The user does not have the access required to perform the action 404 Not Found - Zone or RecordSet not found 409 Conflict - There is an existing pending change against this zone HTTP RESPONSE ATTRIBUTES name type description zone map Contains information about the zone when the change was created recordSet map Contains the recordset model userId string The user ID that initiated the change changeType string Type of change requested (Create, Update, Delete); in this case Delete created string The timestamp (UTC) the change was initiated id string The ID of the change. This is not the ID of the recordset EXAMPLE RESPONSE { \"zone\": { \"name\": \"vinyl.\", \"email\": \"test@test.com\", \"status\": \"Active\", \"created\": \"2017-02-23T14:52:44Z\", \"updated\": \"2017-02-23T15:12:33Z\", \"id\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"account\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\", \"shared\": false, \"acl\": { \"rules\": [] }, \"adminGroupId\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\", \"latestSync\": \"2017-02-23T15:12:33Z\" }, \"recordSet\": { \"type\": \"A\", \"zoneId\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"name\": \"foo\", \"ttl\": 38400, \"status\": \"PendingDelete\", \"created\": \"2017-02-23T15:12:33Z\", \"updated\": \"2017-02-23T15:18:27Z\", \"records\": [ { \"address\": \"2.2.2.2\" } ], \"id\": \"da57c384-d6e8-4166-986d-2ca9d483f760\", \"account\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\" }, \"userId\": \"0215d410-9b7e-4636-89fd-b6b948a06347\", \"changeType\": \"Delete\", \"status\": \"Pending\", \"created\": \"2017-02-23T15:18:27Z\", \"updates\": { \"type\": \"A\", \"zoneId\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"name\": \"foo\", \"ttl\": 38400, \"status\": \"Active\", \"created\": \"2017-02-23T15:12:33Z\", \"records\": [ { \"address\": \"2.2.2.2\" } ], \"id\": \"da57c384-d6e8-4166-986d-2ca9d483f760\", \"account\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\" }, \"id\": \"c46cf622-285f-4f1b-b5b2-993a5a51ea5b\" }" - } , - { - "title": "Delete Zone", - "url": "/api/delete-zone.html", - "content": "Delete Zone Abandons an existing zone that has already been connected to. The zone will be disconnected from VinylDNS, but the RecordSets still exist in the backend DNS zone. To delete the RecordSets see Delete RecordSet Note: We do not recommend that you abandon zones, as your zone history will be lost after the Delete. This endpoint is provided in certain situations where a zone was incorrectly started. HTTP REQUEST DELETE /zones/{zoneId} HTTP RESPONSE TYPES Code description 202 Accepted - The change has been queued and is returned in the response body 400 Bad Request - Zone was not empty and contains records 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 403 Forbidden - The user does not have the access required to perform the action 404 Not Found - Zone not found 409 Conflict - Zone is unavailable HTTP RESPONSE ATTRIBUTES name type description zone map Zone being deleted userId string The user id that initiated the change changeType string Type of change requested (Create, Update, Sync, Delete); in this case Delete created string The timestamp (UTC) the change was initiated id string The ID of the change. This is not the ID of the zone status string The status of the zone change EXAMPLE RESPONSE { \"status\": \"Pending\", \"zone\": { \"status\": \"Deleted\", \"updated\": \"2016-12-28T18:45:53Z\", \"name\": \"443ad9ff-8f38-4540-b53f-e23a35fdfc28.\", \"adminGroupId\": \"test-group-id\", \"created\": \"2016-12-28T18:45:53Z\", \"account\": \"test_group\", \"email\": \"test@test.com\", \"shared\": false, \"acl\": { \"rules\": [] }, \"id\": \"4995e883-f314-4c5f-8ee8-75003ca08ab0\" }, \"created\": \"2016-12-28T18:45:53Z\", \"changeType\": \"Delete\", \"userId\": \"vinyl\", \"id\": \"89c463e3-1615-42f7-8299-a0ca7ccea439\" }" - } , - { - "title": "DNS Changes", - "url": "/portal/dns-changes.html", - "content": "DNS Changes DNS Changes is an alternative to submitting individual RecordSet changes and provides the following: The ability to include records of multiple record types across multiple zones. Input names are entered as fully-qualified domain names (or IP addresses for PTR records), so users don’t have to think in record/zone context. Note: DNS Change is portal-only terminology. The API equivalent is batch change. Access Access permissions will follow existing rules (admin group or ACL access). Note that an update (delete and add of the same record name or delete of single entry of multi-record DNS record set, zone and record type combination) requires Write or Delete access. Records in shared zones. All users are permitted to create new records or update unowned records in shared zones. Supported record types Current supported record types for DNS change are: A, AAAA, CNAME, PTR, TXT, and MX. Additionally, there are A+PTR and AAAA+PTR types that will be processed as separate A (or AAAA) and PTR changes in the VinylDNS backend. Deletes for A+PTR and AAAA+PTR require Input Name and Record Data. Supported record types for records in shared zones may vary. Contact your VinylDNS administrators to find the allowed record types. This does not apply to zone administrators or users with specific ACL access rules. Requirements DNS change requests must contain at least one change. The maximum number of single changes within a DNS change varies by instance of VinylDNS. Contact your VinylDNS administrators to find the DNS change limit for your instance. To update an existing record, you must delete the record first and add all expected records within the same request; a delete and add of the same record set within a DNS change request will be processed as an update. When creating a new record in a shared zone, or updating an existing unowned record, a record owner group is required. Once the owner group is assigned only users in that group, zone admins, and users with ACL permissions can modify the record. Create a DNS Change Go to the DNS Changes section of the site. Select the New DNS Change button. Add a description. Add record changes in one of two ways: Select the Add a Change button to add additional rows for data entry as needed. Select the Import CSV button to choose and upload a CSV file of the record changes. See DNS Change CSV Import for more information. Select the submit button. Confirm your submission. If your submission was successful you’ll redirect to the DNS Change summary page where you will see the status of the DNS Change request overall and of the individual records in the DNS Change. If there are errors in the DNS Change you will remain on the form with prompts to correct errors before you attempt to submit again. DNS Change CSV Import Download a sample CSV here The header row is required. The order of the columns is Change Type, Record Type, Input Name, TTL, Record Data. The TTL field is optional for each record, but the column is still required. If TTL is empty VinylDNS will use the existing TTL value for record updates or the default TTL value for new records. Review a DNS Change You can review your submitted DNS Change requests by selecting the linked DNS Change ID or View button for the DNS Change on the main page of the DNS Changes section in the portal." - } , - { - "title": "FAQ", - "url": "/faq.html", - "content": "VinylDNS FAQ Frequently Asked Questions Can I create a zone in VinylDNS? How do I know my zone ID? How can I create a record with the same name as my zone? When I try to connect to my zone, I am seeing REFUSED When I try to connect to my zone, I am seeing NOTAUTH When I try to connect to my zone, I am seeing “dotted host” errors When I try to connect to my zone, I am seeing “invalid name server” errors How do I get API credentials? How are requests authenticated to the VinylDNS API? 1. Can I create a zone in VinylDNS? To get started with VinylDNS, you must have an existing DNS zone. VinylDNS currently does not create zones, rather it connects to existing zones. 2. How do I know my zone ID? When viewing your zone in the portal, the zone ID is listed in the Manage Zone tab of your zone. This ID is also present in the URL (if on that page it’s the ID after /zones/). 3. How can I create a record with the same name as my zone? To create a record with the same name as your zone, you have to use the special @ character for the record name when you create your record set. You cannot create CNAME records with @ as those are not supported. While some DNS services like Route 53 support an ALIAS record type that does support a CNAME style @, ALIAS are not an official standard yet. All other record types should be fine using the @ symbol. 4. When I try to connect to my zone, I am seeing REFUSED When VinylDNS connects to a zone, it first validates that the zone is suitable for use in VinylDNS. To do so, it tests that the connections work, and that the zone data is valid. REFUSED indicates that VinylDNS could not do a zone transfer to load the DNS records for examination. A few reasons for this are: The Transfer Connection you entered is invalid. Please verify that the TSIG information you entered works. You can attempt to do a dig and request a zone transfer from the command line. You did not setup a Transfer Connection, but the VinylDNS default keys do not have transfer access to your zone. Steps must be taken outside of VinylDNS. 5. When I try to connect to my zone, I am seeing NOTAUTH NOTAUTH indicates that the primary connection that VinylDNS uses to validate the zone is not working. The reasons are: The Connection you entered is invalid. Please verify that the TSIG information you entered works. You did not setup a Connection, but the VinylDNS default keys do not have update access to your zone. Steps must be taken outside of VinylDNS. 6. When I try to connect to my zone, I am seeing “dotted host” errors VinylDNS validates zones upon connect. One validation is to make sure that there are no “dotted” host. A “dotted host” is a record label inside of a zone that has a “dot” in it’s name, but is not part of a subdomain of the zone. For example, “foo.bar.example.com” is invalid, and considered a “dotted host”, if it lives inside of the “example.com” DNS zone. For this to be a valid record, this label would need to be a record named “foo” inside of the “bar.example.com” zone. You will not be able to use VinylDNS for zones with dotted hosts until they are remediated. All remediation steps must be taken outside of VinylDNS. If possible, use dashes instead of dots. In the example, you can have “foo-bar.example.com” 7. When I try to connect to my zone, I am seeing “invalid Name Server” errors One of the validations VinylDNS performs is to make sure the name servers that are in use in the zone are in a list of approved name servers. If your zone is hosted on name servers that are not in this list, you will not be able to use VinylDNS to manage your zone. 8. How do I get API credentials? After logging in to the portal, click your username at the top right and select Download API Credentials. If you need new API credentials select Regenerate Credentials. This will invalidate your previous credentials. If you use any VinylDNS tools beyond the portal you will need to provide those tools with your new credentials. 9. How are requests authenticated to the VinylDNS API? Refer to API Authentication." - } , - { - "title": "Get Batch Change", - "url": "/api/get-batchchange.html", - "content": "Get Batch Change Retrieves a batch change given the batch change ID. Only the user who created a batch change and VinylDNS administrators will have access to get it. HTTP REQUEST GET /zones/batchrecordchanges/{id} HTTP REQUEST PARAMS name type required? description id string yes Unique identifier assigned to each created batch change. HTTP RESPONSE TYPES Code description 200 OK - The batch change is returned in response body. 403 Forbidden - The user does not have the access required to perform the action. 404 Not Found - Batch change not found. HTTP RESPONSE ATTRIBUTES name type description userId string The unique identifier of the user that created the batch change. userName string The username of the user that created the batch change. comments string Optional comments about the batch change. createdTimestamp date-time The timestamp (UTC) when the batch change was created. changes Array of SingleChange Array of single changes within a batch change. A SingleChange can either be a SingleAddChange or a SingleDeleteRRSetChange. status BatchChangeStatus Status of the batch change. id string The unique identifier for this batch change. scheduledTime date-time Optional requested date and time to process the batch change. approvalStatus BatchChangeApprovalStatus Approval status of the batch change. reviewerId string Optional identifier of reviewer if batch change required manual review reviewComment string Optional comment by reviewer if batch change required manual review reviewTimestamp date-time Optional timestamp (UTC) when the batch change was reviewed if manual review was required. cancelledTimestamp date-time Optional timestamp (UTC) if the batch change was cancelled by the creator EXAMPLE RESPONSE { \"userId\": \"vinyl\", \"userName\": \"vinyl201\", \"comments\": \"this is optional\", \"createdTimestamp\": \"2018-05-09T14:19:34Z\", \"changes\": [ { \"changeType\": \"Add\", \"inputName\": \"parent.com.\", \"type\": \"A\", \"ttl\": 200, \"record\": { \"address\": \"4.5.6.7\" }, \"status\": \"Pending\", \"recordName\": \"parent.com.\", \"zoneName\": \"parent.com.\", \"zoneId\": \"74e93bfc-7296-4b86-83d3-1ffcb0eb3d13\", \"recordChangeId\": \"a07299ce-5f81-11e8-9c2d-fa7ae01bbebc\", \"recordSetId\": \"a0729f00-5f81-11e8-9c2d-fa7ae01bbebc\", \"id\": \"7573ca11-3e30-45a8-9ba5-791f7d6ae7a7\" }, { \"changeType\": \"DeleteRecordSet\", \"inputName\": \"deleting.parent.com.\", \"type\": \"CNAME\", \"status\": \"Pending\", \"recordName\": \"deleting\", \"zoneName\": \"parent.com.\", \"zoneId\": \"74e93bfc-7296-4b86-83d3-1ffcb0eb3d13\", \"recordChangeId\": \"bed15986-5f82-11e8-9c2d-fa7ae01bbebc\", \"recordSetId\": \"c089e52c-5f82-11e8-9c2d-fa7ae01bbebc\", \"id\": \"7573ca11-3e30-45a8-9ba5-791f7d6ae7a7\" } ], \"status\": \"PendingProcessing\", \"id\": \"02bd95f4-a32c-443b-82eb-54dbaa55b31a\" }" - } , - { - "title": "Get Group", - "url": "/api/get-group.html", - "content": "Get Group Gets a group that you are a part of HTTP REQUEST GET /groups/{groupId} HTTP RESPONSE TYPES Code description 200 OK - The group is returned in the response body 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 404 Not Found - The group was not found HTTP RESPONSE ATTRIBUTES name type description id string Unique UUID of the group name map The name of the group email string The email distribution list of the group description string The group description, the group may not have this field if it was not set created string The timestamp (UTC) the group was created status string Active or Deleted members Array of User Id objects Ids of members of the group including admins admins Array of User Id objects Ids of admins of the group EXAMPLE RESPONSE { \"id\": \"6f8afcda-7529-4cad-9f2d-76903f4b1aca\", \"name\": \"some-group\", \"email\": \"test@example.com\", \"created\": \"2017-03-02T15:29:21Z\", \"status\": \"Active\", \"members\": [ { \"id\": \"2764183c-5e75-4ae6-8833-503cd5f4dcb0\" }, { \"id\": \"c8630ebc-0af2-4c9a-a0a0-d18c590ed03e\" } ], \"admins\": [ { \"id\": \"2764183c-5e75-4ae6-8833-503cd5f4dcb0\" } ] }" - } , - { - "title": "Get RecordSet Change", - "url": "/api/get-recordset-change.html", - "content": "Get RecordSet Change RecordSet changes (Create, Update, Delete) are not immediately applied to the DNS backend; they are queued up for processing. Most changes are applied within a few seconds. When you submit a change for processing, the response is a Change model. You can use the information in that change model in order to poll for the status of the change until it completes (status = Complete) or fails (status = Failed) HTTP REQUEST GET /zones/{zoneId}/recordsets/{recordSetId}/changes/{recordChangeId} HTTP RESPONSE TYPES Code description 200 OK - The record set change is returned in the response body 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 403 Forbidden - The user does not have the access required to perform the action 404 Not Found - The zone, record set, or change was not found HTTP RESPONSE ATTRIBUTES name type description zone map Contains information about the zone when the change was created recordSet map Contains the recordset model userId string The user ID that initiated the change changeType string Type of change requested (Create, Update, or Delete) created string The timestamp (UTC) the change was initiated id string The ID of the change. This is not the ID of the recordset status RecordSetChangeStatus The status of the change (Pending, Complete, or Failed) singleBatchChangeIds array of SingleBatchChange ID objects If the recordset change was part of a batch change, the IDs of the single changes that comprise the recordset change EXAMPLE RESPONSE { \"zone\": { \"name\": \"vinyl.\", \"email\": \"test@test.com\", \"status\": \"Active\", \"created\": \"2017-02-23T14:52:44Z\", \"id\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"account\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\", \"shared\": false, \"acl\": { \"rules\": [ ] }, \"adminGroupId\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\" }, \"recordSet\": { \"type\": \"A\", \"zoneId\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"name\": \"foo\", \"ttl\": 300, \"status\": \"Pending\", \"created\": \"2017-02-23T14:58:54Z\", \"records\": [ { \"address\": \"10.10.10.10\" } ], \"id\": \"9a41b99c-8e67-445f-bcf3-f9c7cd1f2357\", \"account\": \"0215d410-9b7e-4636-89fd-b6b948a06347\" }, \"userId\": \"0215d410-9b7e-4636-89fd-b6b948a06347\", \"changeType\": \"Create\", \"status\": \"Pending\", \"created\": \"2017-02-23T14:58:54Z\", \"id\": \"fef81f0b-f439-462d-88df-c773d3686c9b\", \"singleBatchChangeIds\": [] }" - } , - { - "title": "Get RecordSet", - "url": "/api/get-recordset.html", - "content": "Get RecordSet Gets a RecordSet in a specified zone HTTP REQUEST GET /zones/{zoneId}/recordsets/{recordSetId} HTTP RESPONSE TYPES Code description 200 OK - The record set is returned 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 403 Forbidden - The user does not have the access required to perform the action 404 Not Found - The zone with the id specified was not found, or the record set with id was not found HTTP RESPONSE ATTRIBUTES The returned json object has all the fields from the RecordSet as well as an added accessLevel field name type description type string Type of record set zoneId string The zone the record is stored in name string The name of the record set ttl integer The TTL of the record set in seconds status string The status of the record set created string The timestamp (UTC) the change was initiated updated string The timestamp (UTC) the change was last updated records array of record data Array of record data objects id string The unique ID of the record set account string DEPRECATED the ID of the account that created the record set accessLevel string accessLevel that user has to record set based off acl rules and whether or not user is in Zone Admin Group ownerGroupId string Record ownership assignment, if found, applicable if the recordset is in a shared zone ownerGroupName string Name of assigned owner group, if found EXAMPLE RESPONSE { \"type\": \"A\", \"zoneId\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"name\": \"already-exists\", \"ttl\": 38400, \"status\": \"Active\", \"created\": \"2017-02-23T15:12:41Z\", \"updated\": \"2017-02-23T15:12:41Z\", \"records\": [ { \"address\": \"6.6.6.1\" } ], \"id\": \"dd9c1120-0594-4e61-982e-8ddcbc8b2d21\", \"account\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\", \"accessLevel\": \"Delete\", \"ownerGroupId\": \"f42385e4-5675-38c0-b42f-64105e743bfe\", \"ownerGroupName\": \"Shared Group\" }" - } , - { - "title": "Get Zone by ID", - "url": "/api/get-zone-by-id.html", - "content": "Get Zone by ID Retrieves a zone with the matching zone ID HTTP REQUEST GET /zones/{zoneId} HTTP RESPONSE TYPES Code description 200 OK - Successful lookup, the zone is returned in the response body 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 403 Forbidden - The user does not have the access required to perform the action 404 Not Found - Zone not found HTTP RESPONSE ATTRIBUTES name type description zone map refer to zone model EXAMPLE RESPONSE { \"zone\": { \"status\": \"Active\", \"account\": \"6baa85ad-267f-44ff-b535-818b7d7a2467\", \"name\": \"system-test.\", \"created\": \"2016-12-28T18:12:09Z\", \"adminGroupId\": \"6baa85ad-267f-44ff-b535-818b7d7a2467\", \"email\": \"test@example.com\", \"connection\": { \"primaryServer\": \"127.0.0.1:5301\", \"keyName\": \"vinyl.\", \"name\": \"system-test.\", \"key\": \"OBF:1:B2cetOaRf1YAABAAek/w22XyKAleCRjA/hZO9fkNtNufPIRWTYHXviAk9GjrfcFOG9nNuB==\" }, \"transferConnection\": { \"primaryServer\": \"127.0.0.1:5301\", \"keyName\": \"vinyl.\", \"name\": \"system-test.\", \"key\": \"OBF:1:PNt2k1nYkC0AABAAePpNMrDp+4C4GDbicWWlAqB5c4mKoKhvfpiWY1PfuRCVzSAeXydztB==\" }, \"shared\": true, \"acl\": { \"rules\": [] }, \"id\": \"0f2fcece-b4ee-4982-b671-e5946f7db81d\", \"latestSync\": \"2016-12-16T15:27:26Z\" } }" - } , - { - "title": "Get Zone by Name", - "url": "/api/get-zone-by-name.html", - "content": "Get Zone by Name Retrieves a zone with the matching zone name HTTP REQUEST GET /zones/name/{zoneName} HTTP RESPONSE TYPES Code description 200 OK - Successful lookup, the zone is returned in the response body 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 403 Forbidden - The user does not have the access required to perform the action 404 Not Found - Zone not found HTTP RESPONSE ATTRIBUTES name type description zone map refer to zone model EXAMPLE RESPONSE { \"zone\": { \"status\": \"Active\", \"account\": \"6baa85ad-267f-44ff-b535-818b7d7a2467\", \"name\": \"system-test.\", \"created\": \"2016-12-28T18:12:09Z\", \"adminGroupId\": \"6baa85ad-267f-44ff-b535-818b7d7a2467\", \"email\": \"test@example.com\", \"connection\": { \"primaryServer\": \"127.0.0.1:5301\", \"keyName\": \"vinyl.\", \"name\": \"system-test.\", \"key\": \"OBF:1:B2cetOaRf1YAABAAek/w22XyKAleCRjA/hZO9fkNtNufPIRWTYHXviAk9GjrfcFOG9nNuB==\" }, \"transferConnection\": { \"primaryServer\": \"127.0.0.1:5301\", \"keyName\": \"vinyl.\", \"name\": \"system-test.\", \"key\": \"OBF:1:PNt2k1nYkC0AABAAePpNMrDp+4C4GDbicWWlAqB5c4mKoKhvfpiWY1PfuRCVzSAeXydztB==\" }, \"shared\": true, \"acl\": { \"rules\": [] }, \"id\": \"0f2fcece-b4ee-4982-b671-e5946f7db81d\", \"latestSync\": \"2016-12-16T15:27:26Z\" } }" - } , - { - "title": "Getting Help", - "url": "/getting-help.html", - "content": "Getting Help VinylDNS Discussions: https://github.com/vinyldns/vinyldns/discussions" - } , - { - "title": "Groups", - "url": "/portal/groups.html", - "content": "Groups Groups are the primary way users are granted access to zones. Users can create groups for two purposes in VinylDNS: to be the zone admin group for a zone or to be assigned more limited access via ACL rules. Every zone in VinylDNS must have a zone admin group assigned. VinylDNS does not currently integrate with any services to generate pre-defined zone admin groups. Create a group Manage membership" - } , - { - "title": "Operator Guide", - "url": "/operator/", - "content": "Operator Guide This operator guide will help administrators install and operate VinylDNS API and Portal. Setup the pre-requisite systems - VinylDNS has several external dependencies that are required in order to operate. Setup the VinylDNS API server Setup the VinylDNS Portal server" - } , - { - "title": "API documentation", - "url": "/api/", - "content": "API documentation Authentication Zone RecordSet Batch Change Membership" - } , - { - "title": "Portal Guide", - "url": "/portal/", - "content": "Portal Guide The VinylDNS portal is the primary user interface for interacting with VinylDNS. Users can retrieve their credentials and manage zones, records, and user groups. This guide covers the functionality of the portal. Navigating the Portal User Menu The User Menu is located in the top right corner of the portal and accessed by selecting your username. It contains a Logout link to sign out of the portal and the Download Credentials link. Credentials In order to use tooling to access VinylDNS, all users must download their credentials from the VinylDNS portal. Learn more Zones The Zones section of the portal is for managing DNS zones and records. This area also includes more granular management of user abilities. To access Zones in the portal select the Zones link in the left column navigation. Access to individual zones in this part of the portal is limited to zone administrators and users with explicit permissions. Learn More Groups The Groups section of the portal is for managing high level user access and abilities. To access Groups in the portal select the Groups link in the left column navigation. Learn More DNS Changes The DNS Changes section of the portal allows users to implement multiple record changes simultaneously and across different zones. To access DNS Changes in the portal select the DNS Changes link in the left column navigation. Learn More" - } , - { - "title": "Home", - "url": "/", - "content": "Welcome VinylDNS is a vendor agnostic front-end for enabling self-service DNS and streamlining DNS operations. It is designed to integrate with your existing DNS infrastructure, and provides extensibility to fit your installation. VinylDNS manages millions of DNS records supporting thousands of engineers in production at Comcast. The platform provides fine-grained access controls, auditing of changes, a self-service user interface, secure RESTful API, and integration with infrastructure automation tools like Ansible and Terraform. VinylDNS helps secure DNS management via: AWS Sig4 signing of all messages to ensure that the message that was sent was not altered in transit Throttling of DNS updates to rate limit concurrent updates against your DNS systems Encrypting user secrets and TSIG keys at rest and in-transit Recording every change made to DNS records and zones Integration is simple with first-class language support including: Java JavaScript Python Go" - } , - { - "title": "List Batch Changes", - "url": "/api/list-batchchanges.html", - "content": "List Batch Changes Retrieves the most recent 100 batch changes created by the user. This call will return a subset of the full information in each change, as detailed in the attributes section. The max number of batch changes that are returned from a single request has been set to 100. HTTP REQUEST GET zones/batchrecordchanges?startFrom={response.nextId}&maxItems={1-100}&ignoreAccess={true | false}&approval_status={BatchChangeApprovalStatus} HTTP REQUEST PARAMS name type required? description startFrom int no In order to advance through pages of results, the startFrom is set to the nextId that is returned on the previous response. It is up to the client to maintain previous pages if the client wishes to advance forward and backward. If not specified, will return the first page of results. maxItems int no The number of items to return in the page. Valid values are 1 - 100. Defaults to 100 if not provided. ignoreAccess boolean no Flag determining whether to retrieve only batch changes made by calling user or to retrieve all changes. Only affects system administrators (ie. support and super users). Defaults to false if not provided. approvalStatus BatchChangeApprovalStatus no Filter batch changes based on approval status. Can be one of AutoApproved, PendingReview, ManuallyApproved, Rejected, or Cancelled. HTTP RESPONSE TYPES Code description 200 OK - the batch change is returned in response body. 403 Forbidden - the user does not have the access required to perform the action. If there are no batch changes created by the user, a successful empty response body is returned. HTTP RESPONSE ATTRIBUTES name type description batchChanges Array of BatchChangeSummary Summary information for the most recent 100 batch changes created by the user. startFrom int startFrom sent in request, will not be returned if not provided. nextId int startFrom parameter of next page request, will not be returned if record sets are exhausted. maxItems integer maxItems sent in request, default is 100. ignoreAccess boolean ignoreAccess sent in request, default is false. approvalStatus BatchChangeApprovalStatus approvalStatus sent in request, will not be returned if not provided. BatchChangeSummary name type description userId string The unique identifier of the user that created the batch change. userName string The username of the user that created the batch change. comments string Conditional: comments about the batch change, if provided. createdTimestamp date-time The timestamp (UTC) when the batch change was created. totalChanges int The total number of single changes within the batch change. status BatchChangeStatus Status of the batch change. id string The unique identifier for this batch change. ownerGroupName string Conditional: Record ownership assignment, if provided. approvalStatus BatchChangeApprovalStatus Whether the batch change is currently awaiting manual review. Can be one of AutoApproved, PendingReview, ManuallyApproved, Rejected, or Cancelled. EXAMPLE RESPONSE { \"batchChanges\": [ { \"userId\": \"vinyl\", \"userName\": \"vinyl201\", \"comments\": \"this is optional\", \"createdTimestamp\": \"2018-05-11T18:12:13Z\", \"totalChanges\": 5, \"status\": \"Complete\", \"id\": \"bd03175c-6fd7-419e-991c-3d5d1441d995\", \"ownerGroupId\": \"f42385e4-5675-38c0-b42f-64105e743bfe\", \"ownerGroupName\": \"some owner group name\", \"approvalStatus\": \"AutoApproved\" }, { \"userId\": \"vinyl\", \"userName\": \"vinyl201\", \"comments\": \"this is optional\", \"createdTimestamp\": \"2018-05-11T18:12:12Z\", \"totalChanges\": 10, \"status\": \"Complete\", \"id\": \"743cbd16-5440-4cf7-bca9-20319df9b651\", \"ownerGroupId\": \"f42385e4-5675-38c0-b42f-64105e743bfe\", \"ownerGroupName\": \"some owner group name\", \"approvalStatus\": \"ManuallyApproved\" }, { \"userId\": \"vinyl\", \"userName\": \"vinyl201\", \"comments\": \"this is optional\", \"createdTimestamp\": \"2018-05-11T18:12:12Z\", \"totalChanges\": 7, \"status\": \"Complete\", \"id\": \"2b827a33-7c4f-4623-8dd9-277c6fba0e54\", \"approvalStatus\": \"Rejected\", \"reviewerId\": \"270ba4b3-f5eb-4043-a283-1a6cec0993f3\", \"reviewerName\": \"some reviewer\", \"reviewTimestamp\": \"2018-05-13T13:12:10Z\" } ], \"maxItems\": 100, \"ignoreAccess\": false }" - } , - { - "title": "List Group Activity", - "url": "/api/list-group-activity.html", - "content": "List Group Activity Retrieves a list of group activity HTTP REQUEST GET /groups/{groupId}/activity?startFrom={response.nextId}&maxItems={1 - 100} HTTP REQUEST PARAMS name type required? description startFrom any no In order to advance through pages of results, the startFrom is set to the nextId that is returned on the previous response. It is up to the client to maintain previous pages if the client wishes to advance forward and backward. If not specified, will return the first page of results maxItems integer no The number of items to return in the page. Valid values are 1 to 100. Defaults to 100 if not provided. HTTP RESPONSE TYPES Code description 200 OK - The changes have been returned in the response body 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 404 Not Found - The group was not found HTTP RESPONSE ATTRIBUTES name type description changes Array of Group Changes refer to Group Change startFrom any startFrom sent in request, will not be returned if not provided nextId any nextId, used as startFrom parameter of next page request, will not be returned if activity is exhausted maxItems integer maxItems sent in request, default is 100 GROUP CHANGE ATTRIBUTES name type description newGroup map The new group as a result of the change, refer to Membership Model oldGroup map The old group before the change, refer to Membership Model created string Millisecond timestamp that change was created userId string User Id of user who made the change changeType string The type change, either Create, Update, or Delete EXAMPLE RESPONSE { \"maxItems\": 100, \"changes\": [ { \"newGroup\": { \"status\": \"Active\", \"name\": \"test-list-group-activity-max-item-success\", \"created\": \"2017-03-02T18:49:58Z\", \"id\": \"1555bac7-0343-4d11-800f-955afb481818\", \"admins\": [ { \"id\": \"ok\" } ], \"members\": [ { \"id\": \"dummy199\" }, { \"id\": \"ok\" } ], \"email\": \"test@test.com\" }, \"created\": \"1488480605378\", \"userId\": \"some-user\", \"changeType\": \"Update\", \"oldGroup\": { \"status\": \"Active\", \"name\": \"test-list-group-activity-max-item-success\", \"created\": \"2017-03-02T18:49:58Z\", \"id\": \"1555bac7-0343-4d11-800f-955afb481818\", \"admins\": [ { \"id\": \"ok\" } ], \"members\": [ { \"id\": \"dummy198\" }, { \"id\": \"ok\" } ], \"email\": \"test@test.com\" }, \"id\": \"11abb88b-c47d-469b-bc2d-6656e00711cf\" } ] }" - } , - { - "title": "List Group Admins", - "url": "/api/list-group-admins.html", - "content": "List Group Admins Retrieves a group’s admins HTTP REQUEST GET /groups/{groupId}/admins HTTP RESPONSE TYPES Code description 200 OK - The admins have been returned in the response body 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 404 Not Found - The group was not found HTTP RESPONSE ATTRIBUTES name type description admins Array of Users refer to membership model EXAMPLE RESPONSE { \"admins\": [ { \"userName\": \"jdoe201\", \"firstName\": \"john\", \"created\": \"2017-03-02T16:39:02Z\", \"lastName\": \"doe\", \"email\": \"john_doe@example.com\", \"id\": \"2764183c-5e75-4ae6-8833-503cd5f4dcb0\" }, { \"userName\": \"jdoe202\", \"firstName\": \"jane\", \"created\": \"2017-03-02T16:50:02Z\", \"lastName\": \"doe\", \"email\": \"jane_doe@example.com\", \"id\": \"1764183c-5e75-4ae6-8833-503cd5f4dcb4\" } ] }" - } , - { - "title": "List Group Members", - "url": "/api/list-group-members.html", - "content": "List Group Members Retrieves a list of group members HTTP REQUEST GET /groups/{groupId}/members?startFrom={response.nextId}&maxItems={1 - 100} HTTP REQUEST PARAMS name type required? description startFrom any no In order to advance through pages of results, the startFrom is set to the nextId that is returned on the previous response. It is up to the client to maintain previous pages if the client wishes to advance forward and backward. If not specified, will return the first page of results maxItems integer no The number of items to return in the page. Valid values are 1 to 100. Defaults to 100 if not provided. HTTP RESPONSE TYPES Code description 200 OK - The members have been returned in the response body 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 404 Not Found - The group was not found HTTP RESPONSE ATTRIBUTES name type description members Array of Users refer to membership model, these Users will also include an isAdmin attribute startFrom any startFrom sent in request, will not be returned if not provided nextId any nextId, used as startFrom parameter of next page request, will not be returned if members are exhausted maxItems integer maxItems sent in request, default is 100 EXAMPLE RESPONSE { \"members\": [ { \"id\": \"0b1acc37-7d97-4da7-8a28-f1770bb99643\", \"userName\": \"jdoe201\", \"firstName\": \"John\", \"lastName\": \"Doe\", \"email\": \"John_Doe@example.com\", \"created\": \"2017-03-02T18:42:31Z\", \"isAdmin\": true }, { \"id\": \"0cb85121-671a-4920-ab02-0c17a7b40874\", \"userName\": \"bwayne300\", \"firstName\": \"Bruce\", \"lastName\": \"Wayne\", \"email\": \"Bruce_Wayne@cable.example.com\", \"created\": \"2017-03-02T18:42:54Z\", \"isAdmin\": false } ], \"maxItems\": 100 }" - } , - { - "title": "List Groups", - "url": "/api/list-groups.html", - "content": "List Groups Retrieves a list of groups that you are a part of HTTP REQUEST GET /groups?startFrom={response.nextId}&maxItems={1 - 100}&groupNameFilter={filter}&ignoreAccess={true | false} HTTP REQUEST PARAMS name type required? description groupNameFilter string no One or more characters contained in the name of the group set to search for. For example TP. This is a contains search only, no wildcards or regular expressions are supported startFrom any no In order to advance through pages of results, the startFrom is set to the nextId that is returned on the previous response. It is up to the client to maintain previous pages if the client wishes to advance forward and backward. If not specified, will return the first page of results maxItems integer no The number of items to return in the page. Valid values are 1 to 100. Defaults to 100 if not provided. ignoreAccess boolean no If false, returns only groups the requesting user is a member of. If true, returns groups in the system, regardless of membership. Defaults to false if not provided. Super and support admin see all groups regardless of this value. HTTP RESPONSE TYPES Code description 200 OK - The groups have been returned in the response body 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect HTTP RESPONSE ATTRIBUTES name type description groups Array of Groups refer to membership model groupNameFilter string name filter sent in request startFrom any startFrom sent in request, will not be returned if not provided nextId any nextId, used as startFrom parameter of next page request, will not be returned if groups are exhausted maxItems integer maxItems sent in request, default is 100 ignoreAccess boolean The ignoreAccess parameter that was sent in the HTTP request. This will be false if not sent. EXAMPLE RESPONSE { \"maxItems\": 100, \"groups\": [ { \"id\": \"93887728-2b26-4749-ba69-98871dda9cc0\", \"name\": \"some-other-group\", \"email\": \"test@example.com\", \"created\": \"2017-03-02T16:23:07Z\", \"status\": \"Active\", \"members\": [ { \"id\": \"2764183c-5e75-4ae6-8833-503cd5f4dcb0\" } ], \"admins\": [ { \"id\": \"2764183c-5e75-4ae6-8833-503cd5f4dcb0\" } ] }, { \"id\": \"aa1ea217-70a7-4350-b22b-c7e2f2158fb9\", \"name\": \"some-group\", \"email\": \"test@example.com\", \"created\": \"2017-03-02T16:22:57Z\", \"status\": \"Active\", \"members\": [ { \"id\": \"2764183c-5e75-4ae6-8833-503cd5f4dcb0\" } ], \"admins\": [ { \"id\": \"2764183c-5e75-4ae6-8833-503cd5f4dcb0\" } ] } ], \"ignoreAccess\": false }" - } , - { - "title": "List RecordSet Changes", - "url": "/api/list-recordset-changes.html", - "content": "List RecordSet Changes RecordSet changes (Create, Update, Delete) are not immediately applied to the DNS backend; they are queued up for processing. Most changes are applied within a few seconds. When you submit a change for processing, the response is a Change model. You can use the information in that change model in order to poll for the status of the change until it completes (status = Complete) or fails (status = Failed) Retrieves a list of RecordSet changes in a zone. All RecordSet changes are stored, including those coming from zone syncs. RecordSet changes come in max page sizes of 100 changes, paging must be done independently using startFrom and nextId parameters HTTP REQUEST GET /zones/{zoneId}/recordsetchanges?startFrom={response.nextId}&maxItems={1 - 100} HTTP REQUEST PARAMS name type required? description startFrom any no In order to advance through pages of results, the startFrom is set to the nextId that is returned on the previous response. It is up to the client to maintain previous pages if the client wishes to advance forward and backward. If not specified, will return the first page of results maxItems int no The number of items to return in the page. Valid values are 1 - 100. Defaults to 100 if not provided. HTTP RESPONSE TYPES Code description 200 OK - the recordset changes are returned in response body 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 403 Forbidden - The user does not have the access required to perform the action 404 Not Found - Zone not found HTTP RESPONSE ATTRIBUTES name type description zoneId string Id of zone used for request recordSetChanges array of recordset changes array of recordset changes sorted by created time in descending order startFrom any (optional) The startFrom parameter that was sent in on the HTTP request. Will not be present if the startFrom parameter was not sent nextId any (optional) The identifier to be passed in as the startFrom parameter to retrieve the next page of results. If there are no results left, this field will not be present maxItems int The maxItems parameter that was sent in on the HTTP request. This will be 100 if not sent status string The status of the change (Pending, Complete, Failed) EXAMPLE RESPONSE { \"recordSetChanges\": [ { \"status\": \"Complete\", \"zone\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:57Z\", \"name\": \"system-test-history.\", \"adminGroupId\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"created\": \"2016-12-30T15:37:56Z\", \"account\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"email\": \"i.changed.this.10.times@history-test.com\", \"shared\": true, \"acl\": { \"rules\": [] }, \"id\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\" }, \"created\": \"2016-12-30T15:37:58Z\", \"recordSet\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:58Z\", \"name\": \"test-create-cname-ok\", \"created\": \"2016-12-30T15:37:57Z\", \"account\": \"history-id\", \"zoneId\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\", \"records\": [ { \"cname\": \"changed-cname.\" } ], \"ttl\": 200, \"type\": \"CNAME\", \"id\": \"f62235df-5372-443c-9ba4-bdd3fca452f4\" }, \"changeType\": \"Delete\", \"userId\": \"history-id\", \"updates\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:58Z\", \"name\": \"test-create-cname-ok\", \"created\": \"2016-12-30T15:37:57Z\", \"account\": \"history-id\", \"zoneId\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\", \"records\": [ { \"cname\": \"changed-cname.\" } ], \"ttl\": 200, \"type\": \"CNAME\", \"id\": \"f62235df-5372-443c-9ba4-bdd3fca452f4\" }, \"id\": \"68fd6dbe-0da8-4280-bcf3-37f54528dc41\" }, { \"status\": \"Complete\", \"zone\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:57Z\", \"name\": \"system-test-history.\", \"adminGroupId\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"created\": \"2016-12-30T15:37:56Z\", \"account\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"email\": \"i.changed.this.10.times@history-test.com\", \"shared\": true, \"acl\": { \"rules\": [] }, \"id\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\" }, \"created\": \"2016-12-30T15:37:58Z\", \"recordSet\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:58Z\", \"name\": \"test-create-aaaa-ok\", \"created\": \"2016-12-30T15:37:57Z\", \"account\": \"history-id\", \"zoneId\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\", \"records\": [ { \"address\": \"2003:db8:0:0:0:0:0:4\" }, { \"address\": \"2002:db8:0:0:0:0:0:3\" } ], \"ttl\": 200, \"type\": \"AAAA\", \"id\": \"9559103d-4cb4-4d34-9d3f-eab3fe2e8aed\" }, \"changeType\": \"Delete\", \"userId\": \"history-id\", \"updates\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:57Z\", \"name\": \"test-create-aaaa-ok\", \"created\": \"2016-12-30T15:37:57Z\", \"account\": \"history-id\", \"zoneId\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\", \"records\": [ { \"address\": \"2003:db8:0:0:0:0:0:4\" }, { \"address\": \"2002:db8:0:0:0:0:0:3\" } ], \"ttl\": 200, \"type\": \"AAAA\", \"id\": \"9559103d-4cb4-4d34-9d3f-eab3fe2e8aed\" }, \"id\": \"dabf1e57-49e7-4d2d-8a00-814d88546b0c\" }, { \"status\": \"Complete\", \"zone\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:57Z\", \"name\": \"system-test-history.\", \"adminGroupId\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"created\": \"2016-12-30T15:37:56Z\", \"account\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"email\": \"i.changed.this.10.times@history-test.com\", \"shared\": true, \"acl\": { \"rules\": [] }, \"id\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\" }, \"created\": \"2016-12-30T15:37:58Z\", \"recordSet\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:58Z\", \"name\": \"test-create-a-ok\", \"created\": \"2016-12-30T15:37:57Z\", \"account\": \"history-id\", \"zoneId\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\", \"records\": [ { \"address\": \"9.9.9.9\" }, { \"address\": \"10.2.2.2\" } ], \"ttl\": 200, \"type\": \"A\", \"id\": \"f1fd620e-5ff3-4ee9-839f-bc747a9867d9\" }, \"changeType\": \"Delete\", \"userId\": \"history-id\", \"updates\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:57Z\", \"name\": \"test-create-a-ok\", \"created\": \"2016-12-30T15:37:57Z\", \"account\": \"history-id\", \"zoneId\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\", \"records\": [ { \"address\": \"9.9.9.9\" }, { \"address\": \"10.2.2.2\" } ], \"ttl\": 200, \"type\": \"A\", \"id\": \"f1fd620e-5ff3-4ee9-839f-bc747a9867d9\" }, \"id\": \"23ae1487-bc7f-481b-a544-10ceb7a87540\" }, { \"status\": \"Complete\", \"zone\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:57Z\", \"name\": \"system-test-history.\", \"adminGroupId\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"created\": \"2016-12-30T15:37:56Z\", \"account\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"email\": \"i.changed.this.10.times@history-test.com\", \"shared\": true, \"acl\": { \"rules\": [] }, \"id\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\" }, \"created\": \"2016-12-30T15:37:57Z\", \"recordSet\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:58Z\", \"name\": \"test-create-cname-ok\", \"created\": \"2016-12-30T15:37:57Z\", \"account\": \"history-id\", \"zoneId\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\", \"records\": [ { \"cname\": \"changed-cname.\" } ], \"ttl\": 200, \"type\": \"CNAME\", \"id\": \"f62235df-5372-443c-9ba4-bdd3fca452f4\" }, \"changeType\": \"Update\", \"userId\": \"history-id\", \"updates\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:57Z\", \"name\": \"test-create-cname-ok\", \"created\": \"2016-12-30T15:37:57Z\", \"account\": \"history-id\", \"zoneId\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\", \"records\": [ { \"cname\": \"cname.\" } ], \"ttl\": 100, \"type\": \"CNAME\", \"id\": \"f62235df-5372-443c-9ba4-bdd3fca452f4\" }, \"id\": \"5c722555-c7be-4620-a1fd-8ca53a5b8683\" }, { \"status\": \"Complete\", \"zone\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:57Z\", \"name\": \"system-test-history.\", \"adminGroupId\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"created\": \"2016-12-30T15:37:56Z\", \"account\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"email\": \"i.changed.this.10.times@history-test.com\", \"shared\": true, \"acl\": { \"rules\": [] }, \"id\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\" }, \"created\": \"2016-12-30T15:37:57Z\", \"recordSet\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:57Z\", \"name\": \"test-create-aaaa-ok\", \"created\": \"2016-12-30T15:37:57Z\", \"account\": \"history-id\", \"zoneId\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\", \"records\": [ { \"address\": \"2003:db8:0:0:0:0:0:4\" }, { \"address\": \"2002:db8:0:0:0:0:0:3\" } ], \"ttl\": 200, \"type\": \"AAAA\", \"id\": \"9559103d-4cb4-4d34-9d3f-eab3fe2e8aed\" }, \"changeType\": \"Update\", \"userId\": \"history-id\", \"updates\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:57Z\", \"name\": \"test-create-aaaa-ok\", \"created\": \"2016-12-30T15:37:57Z\", \"account\": \"history-id\", \"zoneId\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\", \"records\": [ { \"address\": \"2001:db8:0:0:0:0:0:3\" }, { \"address\": \"2002:db8:0:0:0:0:0:3\" } ], \"ttl\": 100, \"type\": \"AAAA\", \"id\": \"9559103d-4cb4-4d34-9d3f-eab3fe2e8aed\" }, \"id\": \"480fff34-61d3-4a1d-9696-f5007842b38a\" }, { \"status\": \"Complete\", \"zone\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:57Z\", \"name\": \"system-test-history.\", \"adminGroupId\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"created\": \"2016-12-30T15:37:56Z\", \"account\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"email\": \"i.changed.this.10.times@history-test.com\", \"shared\": true, \"acl\": { \"rules\": [] }, \"id\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\" }, \"created\": \"2016-12-30T15:37:57Z\", \"recordSet\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:57Z\", \"name\": \"test-create-a-ok\", \"created\": \"2016-12-30T15:37:57Z\", \"account\": \"history-id\", \"zoneId\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\", \"records\": [ { \"address\": \"9.9.9.9\" }, { \"address\": \"10.2.2.2\" } ], \"ttl\": 200, \"type\": \"A\", \"id\": \"f1fd620e-5ff3-4ee9-839f-bc747a9867d9\" }, \"changeType\": \"Update\", \"userId\": \"history-id\", \"updates\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:57Z\", \"name\": \"test-create-a-ok\", \"created\": \"2016-12-30T15:37:57Z\", \"account\": \"history-id\", \"zoneId\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\", \"records\": [ { \"address\": \"10.1.1.1\" }, { \"address\": \"10.2.2.2\" } ], \"ttl\": 100, \"type\": \"A\", \"id\": \"f1fd620e-5ff3-4ee9-839f-bc747a9867d9\" }, \"id\": \"999d8674-e59b-478e-95c0-9d4eb964f2be\" }, { \"status\": \"Complete\", \"zone\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:57Z\", \"name\": \"system-test-history.\", \"adminGroupId\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"created\": \"2016-12-30T15:37:56Z\", \"account\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"email\": \"i.changed.this.10.times@history-test.com\", \"connection\": { \"primaryServer\": \"127.0.0.1:5301\", \"keyName\": \"vinyl.\", \"name\": \"system-test-history.\", \"key\": \"OBF:1:YVgGogd/Y+oAABAAIp4s3z7FAn92uvfOci9v0jMjihQ+uV3bOCyNwpMPh78tL4q/A8dR7A==\" }, \"transferConnection\": { \"primaryServer\": \"127.0.0.1:5301\", \"keyName\": \"vinyl.\", \"name\": \"system-test-history.\", \"key\": \"OBF:1:Pq3UqxiceV4AABAAdu90et1pkNn2ZO3MuYstki5BkQVm3T50RQLarpVhIgaoOKLi2CdL6Q==\" }, \"shared\": true, \"acl\": { \"rules\": [] }, \"id\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\" }, \"created\": \"2016-12-30T15:37:57Z\", \"recordSet\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:57Z\", \"name\": \"test-create-cname-ok\", \"created\": \"2016-12-30T15:37:57Z\", \"account\": \"history-id\", \"zoneId\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\", \"records\": [ { \"cname\": \"cname.\" } ], \"ttl\": 100, \"type\": \"CNAME\", \"id\": \"f62235df-5372-443c-9ba4-bdd3fca452f4\" }, \"changeType\": \"Create\", \"userId\": \"history-id\", \"id\": \"b05f0837-84bd-47aa-8a95-7bde91046268\" }, { \"status\": \"Complete\", \"zone\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:57Z\", \"name\": \"system-test-history.\", \"adminGroupId\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"created\": \"2016-12-30T15:37:56Z\", \"account\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"email\": \"i.changed.this.10.times@history-test.com\", \"shared\": true, \"acl\": { \"rules\": [] }, \"id\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\" }, \"created\": \"2016-12-30T15:37:57Z\", \"recordSet\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:57Z\", \"name\": \"test-create-aaaa-ok\", \"created\": \"2016-12-30T15:37:57Z\", \"account\": \"history-id\", \"zoneId\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\", \"records\": [ { \"address\": \"2001:db8:0:0:0:0:0:3\" }, { \"address\": \"2002:db8:0:0:0:0:0:3\" } ], \"ttl\": 100, \"type\": \"AAAA\", \"id\": \"9559103d-4cb4-4d34-9d3f-eab3fe2e8aed\" }, \"changeType\": \"Create\", \"userId\": \"history-id\", \"id\": \"e7e6b7f9-5253-4947-9580-3f0b81a48717\" }, { \"status\": \"Complete\", \"zone\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:57Z\", \"name\": \"system-test-history.\", \"adminGroupId\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"created\": \"2016-12-30T15:37:56Z\", \"account\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"email\": \"i.changed.this.10.times@history-test.com\", \"shared\": true, \"acl\": { \"rules\": [] }, \"id\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\" }, \"created\": \"2016-12-30T15:37:57Z\", \"recordSet\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:57Z\", \"name\": \"test-create-a-ok\", \"created\": \"2016-12-30T15:37:57Z\", \"account\": \"history-id\", \"zoneId\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\", \"records\": [ { \"address\": \"10.1.1.1\" }, { \"address\": \"10.2.2.2\" } ], \"ttl\": 100, \"type\": \"A\", \"id\": \"f1fd620e-5ff3-4ee9-839f-bc747a9867d9\" }, \"changeType\": \"Create\", \"userId\": \"history-id\", \"id\": \"6743d428-7748-4348-a6c9-ae59e9eeaf97\" } ], \"maxItems\": 100 }" - } , - { - "title": "List / Search RecordSets", - "url": "/api/list-recordsets-by-zone.html", - "content": "List / Search RecordSets by Zone Retrieves a list of RecordSets from the zone HTTP REQUEST GET /zones/{zoneId}/recordsets?startFrom={response.nextId}&maxItems={1 - 100}&recordNameFilter={filter} HTTP REQUEST PARAMS name type required? description recordNameFilter string no Characters that are part of the record name to search for. The wildcard character * is supported, for example www*. Omit the wildcard when searching for an exact record name. recordTypeFilter Array of RecordType no An array of record types to filter for listing record sets. Refer to recordset mode for supported types. Invalid record types will be ignored. If left empty or no valid record types are provided, then all record types will be returned. nameSort string no Name sort order for record sets returned by list record set response. Valid values are ASC (ascending; default) and DESC (descending). startFrom any no In order to advance through pages of results, the startFrom is set to the nextId that is returned on the previous response. It is up to the client to maintain previous pages if the client wishes to advance forward and backward. If not specified, will return the first page of results maxItems integer no The number of items to return in the page. Valid values are 1 to 100. Defaults to 100 if not provided. HTTP RESPONSE TYPES Code description 200 OK - The record sets are returned in the response body 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 403 Forbidden - The user does not have the access required to perform the action 404 Not Found - Zone or RecordSet not found HTTP RESPONSE ATTRIBUTES name type description recordSets Array of RecordSets refer to recordset model, the RecordSet data will also include the accessLevel the requesting user has based off acl rules and membership in Zone Admin Group startFrom any startFrom sent in request, will not be returned if not provided nextId any nextId, used as startFrom parameter of next page request, will not be returned if record sets are exhausted maxItems integer maxItems sent in request, default is 100 recordNameFilter string name filter sent in request recordTypeFilter Array of RecordType record type filter sent in request nameSort string name sort order sent in request EXAMPLE RESPONSE { \"recordSets\": [ { \"type\": \"A\", \"zoneId\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"name\": \"already-exists\", \"ttl\": 38400, \"status\": \"Active\", \"created\": \"2017-02-23T15:12:41Z\", \"updated\": \"2017-02-23T15:12:41Z\", \"records\": [ { \"address\": \"6.6.6.1\" } ], \"id\": \"dd9c1120-0594-4e61-982e-8ddcbc8b2d21\", \"account\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\", \"accessLevel\": \"Delete\" }, { \"type\": \"NS\", \"zoneId\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"name\": \"vinyl\", \"ttl\": 38400, \"status\": \"Active\", \"created\": \"2017-02-23T15:12:33Z\", \"records\": [ { \"nsdname\": \"172.17.42.2.\" } ], \"id\": \"daf5ea7b-c28c-422a-ba47-2c37ca567a77\", \"account\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\", \"accessLevel\": \"Delete\" }, { \"type\": \"SOA\", \"zoneId\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"name\": \"vinyl\", \"ttl\": 38400, \"status\": \"Active\", \"created\": \"2017-02-23T15:12:33Z\", \"records\": [ { \"mname\": \"172.17.42.2.\", \"rname\": \"admin.test.com.\", \"serial\": 1439234395, \"refresh\": 10800, \"retry\": 3600, \"expire\": 604800, \"minimum\": 38400 } ], \"id\": \"9da83158-05ab-4f14-8bd0-0a4d85cdeb30\", \"account\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\", \"accessLevel\": \"Delete\" }, { \"type\": \"A\", \"zoneId\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"name\": \"vinyl\", \"ttl\": 38400, \"status\": \"Active\", \"created\": \"2017-02-23T15:12:33Z\", \"records\": [ { \"address\": \"5.5.5.5\" } ], \"id\": \"d73275ff-e71e-4024-aef1-1236741443b5\", \"account\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\", \"accessLevel\": \"Delete\" }, { \"type\": \"A\", \"zoneId\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"name\": \"jenkins\", \"ttl\": 38400, \"status\": \"Active\", \"created\": \"2017-02-23T15:12:33Z\", \"records\": [ { \"address\": \"10.1.1.1\" } ], \"id\": \"0432f63b-3947-4262-9ade-a3311d07a099\", \"account\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\", \"accessLevel\": \"Delete\" }, { \"type\": \"A\", \"zoneId\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"name\": \"test\", \"ttl\": 38400, \"status\": \"Active\", \"created\": \"2017-02-23T15:12:33Z\", \"records\": [ { \"address\": \"4.4.4.4\" }, { \"address\": \"3.3.3.3\" } ], \"id\": \"dc0e3ce9-ec01-47f1-9418-461dc1754f48\", \"account\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\", \"accessLevel\": \"Delete\" } ], \"maxItems\": 100, \"nameSort\": \"ASC\" }" - } , - { - "title": "Global List / Search RecordSets", - "url": "/api/list-recordsets-global.html", - "content": "Global List / Search RecordSets Retrieves a list of RecordSets globally in the VinylDNS database based on search criteria. A minimum of two alpha-numeric characters is required. HTTP REQUEST GET /recordsets?startFrom={response.nextId}&maxItems={1 - 100}&recordNameFilter={recordNameFilter}&recordTypeFilter={recordTypeFilter}&recordOwnerGroupFilter={recordOwnerGroupFilter}&nameSort={nameSort} HTTP REQUEST PARAMS name type required? description recordNameFilter string yes Characters that are part of the record name to search for. The wildcard character * is supported, for example www*. Omit the wildcard when searching for an exact record name. At least two alphanumeric characters are required for searching. recordTypeFilter Array of RecordType no An array of record types to filter for listing record sets. Refer to recordset mode for supported types. Invalid record types will be ignored. If left empty or no valid record types are provided, then all record types will be returned. recordOwnerGroupFilter string no Owner group ID for record set. nameSort string no Name sort order for record sets returned by list record set response. Valid values are ASC (ascending; default) and DESC (descending). startFrom any no In order to advance through pages of results, the startFrom is set to the nextId that is returned on the previous response. It is up to the client to maintain previous pages if the client wishes to advance forward and backward. If not specified, will return the first page of results maxItems integer no The number of items to return in the page. Valid values are 1 to 100. Defaults to 100 if not provided. HTTP RESPONSE TYPES Code description 200 OK - The record sets are returned in the response body 422 Unprocessable Entity - recordNameFilter was either omitted or provided but does not contain at least two alphanumeric characters HTTP RESPONSE ATTRIBUTES name type description recordSets Array of RecordSets refer to recordset model startFrom any startFrom sent in request, will not be returned if not provided nextId any nextId, used as startFrom parameter of next page request, will not be returned if record sets are exhausted maxItems integer maxItems sent in request, default is 100 recordNameFilter string name filter sent in request recordTypeFilter Array of RecordType record type filter sent in request recordOwnerGroupFilter string record owner group sent in request nameSort string name sort order sent in request EXAMPLE RESPONSE { \"recordSets\": [ { \"type\": \"A\", \"zoneId\": \"5f5304ba-c81f-456c-9d33-bb6179c8b1f1\", \"name\": \"foo\", \"ttl\": 7200, \"status\": \"Active\", \"created\": \"2019-04-26T17:15:35Z\", \"records\": [ { \"address\": \"1.1.1.1\" } ], \"id\": \"f802596f-4f0e-4e65-bb43-c7ca439d2608\", \"account\": \"system\", \"fqdn\": \"foo.example.com.\", \"zoneName\": \"example.com.\", \"zoneShared\": true } ], \"maxItems\": 100, \"recordNameFilter\": \"foo*\", \"recordTypeFilter\": [ \"A\" ], \"nameSort\": \"ASC\" }" - } , - { - "title": "List Zone Changes", - "url": "/api/list-zone-changes.html", - "content": "List Zone Changes Retrieves a list of zone changes to a zone. All zone changes are stored, including those coming from zone syncs. Zone changes come in max page sizes of 100 changes, paging must be done independently using startFrom and nextId parameters HTTP REQUEST GET /zones/{zoneId}/changes?startFrom={response.nextId}&maxItems={1 - 100} HTTP REQUEST PARAMS name type required? description startFrom any no In order to advance through pages of results, the startFrom is set to the nextId that is returned on the previous response. It is up to the client to maintain previous pages if the client wishes to advance forward and backward. If not specified, will return the first page of results maxItems int no The number of items to return in the page. Valid values are 1 - 100. Defaults to 100 if not provided. HTTP RESPONSE TYPES Code description 200 Accepted - The zone changes will be returned in the response body 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 403 Forbidden - The user does not have the access required to perform the action 404 Not Found - Zone not found HTTP RESPONSE ATTRIBUTES name type description zoneId string Id of zone used for request zoneChanges array of zone changes array of zone changes sorted by created time in descending order startFrom any (optional) The startFrom parameter that was sent in on the HTTP request. Will not be present if the startFrom parameter was not sent nextId any (optional) The identifier to be passed in as the startFrom parameter to retrieve the next page of results. If there are no results left, this field will not be present maxItems int The maxItems parameter that was sent in on the HTTP request. This will be 100 if not sent EXAMPLE RESPONSE { \"zoneId\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"zoneChanges\": [ { \"status\": \"Synced\", \"zone\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:57Z\", \"name\": \"system-test-history.\", \"adminGroupId\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"created\": \"2016-12-30T15:37:56Z\", \"account\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"email\": \"i.changed.this.10.times@history-test.com\", \"shared\": true, \"acl\": { \"rules\": [] }, \"id\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\" }, \"created\": \"2016-12-30T15:37:57Z\", \"changeType\": \"Update\", \"userId\": \"history-id\", \"id\": \"6d4deccb-4632-475e-9ebc-3f6bace5fe68\" }, { \"status\": \"Synced\", \"zone\": { \"status\": \"Active\", \"updated\": \"2016-12-30T15:37:57Z\", \"name\": \"system-test-history.\", \"adminGroupId\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"created\": \"2016-12-30T15:37:56Z\", \"account\": \"67b4da23-6832-4600-8450-9fa0664caeeb\", \"email\": \"i.changed.this.9.times@history-test.com\", \"shared\": true, \"acl\": { \"rules\": [] }, \"id\": \"9f353bc7-cb8d-491c-b074-34afafc97c5f\" }, \"created\": \"2016-12-30T15:37:57Z\", \"changeType\": \"Update\", \"userId\": \"history-id\", \"id\": \"59c2db90-41aa-49ae-8c56-e13a2ada918d\" } ], \"startFrom\": \"2910234\", \"nextId\": \"1034932\", \"maxItems\": 2 }" - } , - { - "title": "List / Search Zones", - "url": "/api/list-zones.html", - "content": "List / Search Zone Retrieves the list of zones a user has access to. The zone name is only sorted alphabetically. HTTP REQUEST GET /zones?nameFilter={yoursearchhere}&startFrom={response.nextId}&maxItems={1 - 100}&ignoreAccess={true false} HTTP REQUEST PARAMS name type required? description nameFilter string no Characters that are part of the zone name to search for. The wildcard character * is supported, for example www*. Omit the wildcard character when searching for an exact zone name. startFrom any no In order to advance through pages of results, the startFrom is set to the nextId that is returned on the previous response. It is up to the client to maintain previous pages if the client wishes to advance forward and backward. If not specified, will return the first page of results maxItems int no The number of items to return in the page. Valid values are 1 - 100. Defaults to 100 if not provided. ignoreAccess boolean no If false, returns only zones the requesting user owns or has ACL access to. If true, returns zones in the system, regardless of ownership. Defaults to false if not provided. HTTP RESPONSE TYPES Code description 200 OK - The zones and search info are returned in response body 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 403 Forbidden - The user does not have the access required to perform the action HTTP RESPONSE ATTRIBUTES name type description zones Array of Zones An array of the zones found. The zones are sorted alphabetically by zone name. startFrom any (optional) The startFrom parameter that was sent in on the HTTP request. Will not be present if the startFrom parameter was not sent nextId any (optional) The identifier to be passed in as the startFrom parameter to retrieve the next page of results. If there are no results left, this field will not be present. maxItems int The maxItems parameter that was sent in the HTTP request. This will be 100 if not sent. ignoreAccess boolean The ignoreAccess parameter that was sent in the HTTP request. This will be false if not sent. EXAMPLE RESPONSE { \"zones\": [ { \"status\": \"Active\", \"account\": \"a0b5ea74-cc05-4932-a294-9bf935d52744\", \"name\": \"list-zones-test-searched-1.\", \"created\": \"2016-12-16T15:21:47Z\", \"adminGroupId\": \"a0b5ea74-cc05-4932-a294-9bf935d52744\", \"email\": \"test@test.com\", \"shared\": false, \"acl\": { \"rules\": [] }, \"id\": \"31a3d8a9-bea0-458f-9c24-3d39d4b929d6\", \"latestSync\": \"2016-12-16T15:27:26Z\", \"accessLevel\": \"NoAccess\" }, { \"status\": \"Active\", \"account\": \"a0b5ea74-cc05-4932-a294-9bf935d52744\", \"name\": \"list-zones-test-searched-2.\", \"created\": \"2016-12-16T15:21:47Z\", \"adminGroupId\": \"a0b5ea74-cc05-4932-a294-9bf935d52744\", \"email\": \"test@test.com\", \"shared\": false, \"acl\": { \"rules\": [] }, \"id\": \"f1a376b2-2d8f-41f3-b8c8-9c9fba308f5d\", \"latestSync\": \"2016-12-16T15:27:26Z\", \"accessLevel\": \"Delete\" }, { \"status\": \"Active\", \"account\": \"a0b5ea74-cc05-4932-a294-9bf935d52744\", \"name\": \"list-zones-test-searched-3.\", \"created\": \"2016-12-16T15:21:47Z\", \"adminGroupId\": \"a0b5ea74-cc05-4932-a294-9bf935d52744\", \"email\": \"test@test.com\", \"shared\": false, \"acl\": { \"rules\": [] }, \"id\": \"568de57d-cb34-4f05-a9b5-35f9187490af\", \"latestSync\": \"2016-12-16T15:27:26Z\", \"accessLevel\": \"Read\" }, { \"status\": \"Active\", \"account\": \"a0b5ea74-cc05-4932-a294-9bf935d52744\", \"name\": \"list-zones-test-unfiltered-1.\", \"created\": \"2016-12-16T15:21:47Z\", \"adminGroupId\": \"a0b5ea74-cc05-4932-a294-9bf935d52744\", \"email\": \"test@test.com\", \"shared\": false, \"acl\": { \"rules\": [] }, \"id\": \"98dac90c-236e-4171-8729-c977ad38717e\", \"latestSync\": \"2016-12-16T15:27:26Z\", \"accessLevel\": \"NoAccess\" }, { \"status\": \"Active\", \"account\": \"a0b5ea74-cc05-4932-a294-9bf935d52744\", \"name\": \"list-zones-test-unfiltered-2.\", \"created\": \"2016-12-16T15:21:47Z\", \"adminGroupId\": \"a0b5ea74-cc05-4932-a294-9bf935d52744\", \"email\": \"test@test.com\", \"shared\": false, \"acl\": { \"rules\": [] }, \"id\": \"e4942020-b85a-421f-a8e2-124d8ba79422\", \"latestSync\": \"2016-12-16T15:27:26Z\", \"accessLevel\": \"Read\" } ], \"maxItems\": 100, \"ignoreAccess\": true }" - } , - { - "title": "Manage Access", - "url": "/portal/manage-access.html", - "content": "Manage Access to Zones and Records Full Access Members of a zone admin group have full access to all records and permissions in the zone. Each zone is limited to one admin group. Typically, this should be a limited set of users. If you wish to add other users to a group you can do so in the Groups section of the portal. Limited Access If you don’t want a user to have full access to a zone you can use ACL rules to give them more granular access. With ACL rules, the zone admins can grant individual users or groups read, write or delete access to all records in the zone, or a subset of record names and/or types. Go to the desired zone Select the Manage Zone tab Select the Create ACL rule button Fill in the form Submit the form Shared Zones The shared zone feature is designed to allow more granular record ownership and management in a flexible way. Super users can mark zones as ‘shared’ which then allow any users to create new records or claim existing unowned records in zones. Zone administrators can assign records in a shared zone to specific groups by designating a group when creating the record set or when updating existing records in the portal. Users who are not zone administrators can create new records in shared zones, or claim and modify unowned records in shared zones, through the DNS Changes interface." - } , - { - "title": "Manage Membership", - "url": "/portal/manage-membership.html", - "content": "Manage membership If you create a group in VinylDNS you are automatically made a member and group manager of the group. To manage the members of the group select the View button next to the desired group to view the Membership page. Add members: In the text box over the table enter the username of the person you want to add to the group. If you want to make them a group manager check the Is Group Manager? checkbox. Select the Add Group Member button. Delete members: Select the Delete button in the row of the user you wish to remove. Change managerial rights: Toggle the switch under the Group Manager column in the row of the user. The switch to the right and green means the user is a group manager. If the switch is to the left and red it means the user is not an group manager. Relinquish managerial rights: You can relinquish your managerial rights if there is at least one other group manager in the group. If that condition is met you can toggle the Group Manager switch for yourself. Remove yourself from a group: If you wish to remove yourself entirely from a group there must be at least one other manager of the group. If that condition is met you can select the Delete button that corresponds with your username and you will be removed from the group entirely." - } , - { - "title": "Manage Records", - "url": "/portal/manage-records.html", - "content": "Manage Records There are currently two ways to manage records in the VinylDNS portal. This covers managing individual records through their associated zone. To manage multiple records at once, possibly across zones, and records in shared zones you can use the DNS Changes area of the portal. Access Only zone administrators and users with ACL rules can manage records this way. Supported record types A, AAAA, CNAME, DS, MX, NAPTR, NS, PTR, SRV, SSHFP, and TXT To manage records in a zone go to the Zones section of the portal and select the View button that corresponds with the zone you want to manage. The Manage Records tab will be the active tab by default. Once you are in the Manage Records tab of the zone, you can create new records sets or update or delete existing record sets. The Records pane, below the Recent Record Changes pane, lists record sets. Record sets are records that have the same name but different record data. Not all record types support record sets. When you make any change, it will be immediately queued for processing. Typically processing happens in a second or two. You may need to select the Refresh button if you don’t see the change reflected in the portal. If for any reason the change failed, you can view the change in the Recent Record Changes pane at the top of the screen, or look at the Change History tab to see what went wrong. The Additional Info column will contain details of the change failure. Record sorting and filtering It is now possible to sort records in VinylDNS by record name ascending/descending order in addition to filtering the record types that will be displayed, providing more ease and control when navigating your DNS records. To change the sort order for record name, click on the Name header in the Records table to toggle between ascending and descending order. To filter record types, click on the Filter By Record Type link to reveal the record type options and adjust your selection. When searching for a record name using the search bar, exact matches are returned; however it is possible to use * to fuzzy match on desired patterns (e.g. foo* will match foo and foobar). Sync Zones If you make changes to the records in a zone outside of VinylDNS you must manually sync the zone so VinylDNS is aware of those records. Use the Sync Zone button in the Records pane." - } , - { - "title": "Manual Review & Scheduling", - "url": "/portal/manual-review-scheduling.html", - "content": "DNS Changes: Manual Review & Scheduling Configuration Note: DNS Change manual review and scheduling are configured features in VinylDNS. Check with your VinylDNS administrators to determine if they are enabled in your instance.** Manual Review Scheduling Filter by Open Requests Cancelling DNS Changes Reviewing Pending DNS Changes (administrators only) Manual Review If a DNS Change is submitted with only non-fatal errors you will be notified to either correct those errors or submit your DNS Change for manual review. If you submit the DNS Change for manual review a VinylDNS administrator will determine if your request can be approved or if it needs to be rejected. After the review your DNS Change will include the review details, including the review status, reviewer name, review time and review comment, if provided. Scheduling VinylDNS processes DNS Changes immediately, unless they have a Request Date and Time. The day and time must be in the future. The portal accepts and returns the Request Date and Time as your local time. A VinylDNS administrator will review the DNS Change after the requested time and either approve or reject it for processing. Filter by Open Requests If you have many DNS Changes you may find it helpful to filter your list of requests by those that are currently open. In the top right corner of the DNS Changes table is a checkbox labeled “View Open Requests Only”. If the checkbox is selected the DNS Changes list will be limited to only Pending Review and Scheduled DNS Changes. Cancelling DNS Changes Users can cancel any DNS Change they create if it has a review status of “Pending Review”. Either select the “Cancel” button in the main DNS Changes list or the “Cancel” button in the DNS Change Detail page. A modal will appear for the user to confirm the cancellation. Reviewing Pending DNS Changes VinylDNS administrators can use the portal to review DNS Changes. In the DNS Changes view there are two tabs, “My Requests” and “All Requests”. “My Requests” are only your own DNS Changes. “All Requests” are requests by everyone in the VinylDNS instance. Both tabs can be filtered by open requests. On the detail page for a DNS change that is pending review, administrators will see a review section beneath the list of single changes. The administrator can provide a comment, then choose Approve or Reject and finally confirm their choice. If the DNS Change is approved and there are no new errors or it’s rejected then the review is completed and the DNS Change status and review information is updated. If the DNS Change still has errors after the approval attempt, the page will display the new errors and the administrator needs to address those or reject the DNS change." - } , - { - "title": "Membership Model", - "url": "/api/membership-model.html", - "content": "Membership Model Table of Contents Group Attributes Group Example User Attributes User Example MEMBERSHIP BREAKDOWN Every zone can be connected to by only one group in VinylDNS. That initial group will be the admin group for that zone, which can be changed later on in a Zone Update. Every member of the admin group will be an admin of that zone, and can preform zone syncs, zone updates, zone deletes, and record set changes regardless of any Access Control Rules set on them. While users in the admin group will have complete zone access, further users can be given limited membership through Zone ACL Rules GROUP ATTRIBUTES field type description name string This should be a single word name used for the groups. Use hyphens if needed, no spaces email string The email distribution list for the group description string A short description of the group, if more info is needed other than the name. The group will not have this attribute if it was not included in the create request id string Unique UUID of the group created date-time The timestamp (UTC) when the group was created status string Active or Deleted members Array of User id objects Set of User ids in the group admins Array of User id objects Set of User ids that are admins of the group. All admin user ids should also be in the members array Being in the admin set of a group has no impact on zone privileges when the group is the zone’s admin group. Being a group admin allows adding users to the group, deleting users from the group, toggling other users’ admin statuses (including your own), and deleting the group GROUP EXAMPLE { \"id\": \"dc4c7c79-5bbc-41bf-992e-8d6c4ec574c6\", \"name\": \"some-group\", \"email\": \"test@example.com\", \"created\": \"2017-01-30T20:05:24Z\", \"status\": \"Active\", \"members\": [ { \"id\": \"2764183c-5e75-4ae6-8833-503cd5f4dcb0\" }, { \"id\": \"a6d35b1a-57d7-4a65-bec2-d7ed30a7c430\" } ], \"admins\": [ { \"id\": \"a6d35b1a-57d7-4a65-bec2-d7ed30a7c430\" } ] } USER ATTRIBUTES field type description userName string This should be the AD username of the user firstName string First name of the user lastName string Last name of the user email string Email address of the user created date-time The timestamp (UTC) when the user was created id string Unique UUID of the user isTest boolean Defaults to false. Used for restricted access during VinylDNS testing, can be ignored by clients To get your access and secret keys, log into the VinylDNS portal and then with the top right drop-down select Download Credentials USER EXAMPLE { \"userName\": \"jdoe201\", \"firstName\": \"John\", \"lastName\": \"Doe\", \"email\": \"john_doe@example.com\", \"id\": \"1764183c-5e75-4ae6-8833-503cd5f4dcb3\", \"isTest\": false }" - } , - { - "title": "Permissions Guide", - "url": "/permissions.html", - "content": "VinylDNS Permissions Guide Vinyldns is about making DNS self-service safe. There are a number of ways that you can govern access to your DNS infrastructure, from extremely restrictive, to extremely lax, and anywhere in between. This guide attempts to explain the various options available for governing access to your VinylDNS installation. A few notes on VinylDNS Groups Most of the access controls available in VinylDNS are managed by the way of Groups. You can see the groups to which you belong to in the Groups tab in in the portal. Groups are completely separate from LDAP, OIDC, or other Authorization mechanisms. They are tied deeply into the permissions capability in VinylDNS. Users can belong to many different groups, but typically they will belong to one “Primary” group. Groups are completely self-service, so users can create new groups, add / remove users from their groups, and even delete groups. We strongly recommend creating a VinylDNS Admin group for DNS administrators. Permission Precedence We work on the most restrictive access wins. In general: High Value Domain - Can’t get past this step in VinylDNS Zone Ownership - If the user owns a zone, the user can make any changes in that zone Zone ACL - If the user was granted access to the zone via an ACL they can make the change Shared Zone - If the zone is shared, and the record does not yet exist or has not yet been claimed Record Owner - If the zone is shared, and the record is owned, the user has to be a member of the group that owns the record to make the change Global ACL - If all the above fail, if the user has access to the record by way of a Global ACL, the user can make the change Permission Management High Value Domains - config file Zone Ownership - web portal / Manage Zone Zone ACL - web portal / Manage Zone Shared Zone web portal / Manage Zone Record Owner - (implicitly via DNS Requests) Global ACL - config file Manual Review - config file Zone Ownership The original way to govern access is via Zone Ownership and Zone ACLs. When connecting to a zone in VinylDNS, you must designate a VinylDNS group that will effectively “own” the Zone. We refer to “Zone Owners” as any VinylDNS user that is a member of the VinylDNS Group on the Zone. This can be changed subsequent to connecting at any time via the Manage Zone tab. Zone Owners have full rights on a zone. They can manage the zone, abandon it, change connection information, and assign ACLs. A Zone ACL Rule is a record level control that allows VinylDNS users who are not Zone Owners privileges to perform certain actions in the zone. For example, you can grant access to A, AAAA, CNAME records in Zone foo.baz.com to user Josh ACL rules provide an extremely flexible way to grant access to DNS records. Each ACL Rule consists of the following: recordMask - this is a regular expression that is used to match on the record name (without the zone name). For example, a record mask www.* would match any record that started with www For reverse zones, this is a CIDR expression. This allows you to grant access based on individual or contiguous IP address space. For example, you could have a record mask of 100.100.100.100/16 recordTypes - types of DNS records that an ACL rule applies to. Often times, special records like NS records you do not want to grant access to. Add one or more record types to restrict the types of records you are granting access to. accessLevel - what kinds of permissions to give. Create allows a user to create new records, but not change or delete them. Write allows a user to create AND change records, but not delete them Delete allows a user full permissions to create, change, and delete any records that match the rule NoAccess explicitly negates other rules as an override. user - the user that the rule grants access to. You can specify this OR a Group group - the group the rule grants access to. description - an optional description for the rule for personal audit purposes Depending on your organization, you may choose to exclusively use Zone Ownership for managing self-service. This does come at a higher cost of administrative overhead than other options; however, it is the most restrictive and still very flexible. Shared Zone Ownership Shared Zones were introduced in order to alleviate the administrative burden of Zone Ownership for large organizations. If you mark a zone as Shared (via the Manage Zone tab or API), you effectively grant anyone who can login to VinylDNS permissions to manage records in that DNS Zone. Read this section closely, as it can be a little confusing. Shared Zones still have a Zone Owner group that has full access. This will typically be the VinylDNS Admin group / DNS administrators. However, they open up access to everyone. This is very useful for universally “shared” DNS zones, in particular IP space. Often times, IP space is not allocated to groups, but blocks (i.e. Reverse Zones) are shared across the enterprise. It is common to use Shared Zones as a way to allow rather unfettered access to IP space. Shared Zones still have restrictions. It wouldn’t be safe to allow anyone the ability to manage anyone else’s DNS records. Therefore, we use a Record Ownership model that works in concert with Shared Zones to ensure that the user/group that created a DNS record, is the only group that can update or delete it. You can think of Record Ownership like a land grab. If I create it, I own it. All changes to Shared zones are made via the DNS Changes tab. Here is where users create one or more DNS record changes. When users submit changes here, they assign a “Record Owner Group” to the DNS change. As you have just learned, this Record Owner Group will be the group that owns any new records created as part of the batch change. In addition to shared zones, you can configure which record types you allow broad access to. Certain record types like NS maybe sensitive to be “world writable”. You can configure the allowable record types via config as shown below: shared-approved-types = [\"A\", \"AAAA\", \"CNAME\", \"PTR\", \"TXT\"] Global ACL Rules Global ACL Rules provide an override mechanism that applies for specific groups and FQDNs across ALL of VinylDNS. These were created as a means of overriding Record Ownership. The use case that fits here is when You want to use Shared Zones You have group(s) that must override the record ownership model. For example, one group may create or provision a DNS record, and another group may update or decommission that record. Global ACL rules are configured in VinylDNS (i.e. they are config file entries not available in the UI yet). The configuration entry is global-acl-rules. An example entry follows global-acl-rules = [ { group-ids: ['global-acl-group-id'], fqdn-regex-list: ['.*shared.'] } ] The group-ids are one or more VinylDNS group id (UUID) for the groups that you want to grant access to. The fqdn-regex-list is a list of regular expressions matched against the FQDN (i.e. record name and zone name). High Value Domains High value domains are currently configured in VinylDNS. Sometimes, certain domain names are just too valuable that you do not want them to be even touched by VinylDNS. See the operator guide for more information on configuring high value domains. High Value IP Addresses Similarly to forward FQDN records, you can also set certain IP addresses as “off limits, do not touch in VinylDNS”. Also done via the configuration file. Manual Review VinylDNS provides the ability for have DNS changes made via the DNS Change screen to be manually reviewed before being applied. This is another tool in the permissions toolkit to help you govern self-service. Note: if you enable manual review, then someone will need to login to VinylDNS and Approve or Reject the changes that are submitted. This can also be accomplished via scripting against the API if desired. In addition, Manual Review allows you to override certain error conditions. For example, if you create a DNS change for a Zone that does not yet exist in VinylDNS, it will fail before the user can submit. But if you have manual-batch-review-enabled = true, then those DNS changes can be sent to manual review, where a DNS administrator can create the DNS zone, add it to VinylDNS (marking it as shared or otherwise creating ACL access), and then re submit the change to complete processing. To turn on manual review, set the manual-batch-review-enabled = true in your application configuration file. In addition, you can specify certain zones that are ALWAYS manually reviewed. Even with Shared Zones turned on, you can require manual inspection to certain FQDNs. This is also done via configuration. The following snippet shows the configuration for zones that are ALWAYS manually reviewed: manual-review-domains = { domain-list = [\".*imporant.biz.com\"] ip-list = [\"1.2.3.4\"] zone-name-list = [ \"zone.requires.review.\", \"foo.com.\", \"baz.com.\", \"curl.bz.\" ] }" - } , - { - "title": "Pre-requisites", - "url": "/operator/pre.html", - "content": "VinylDNS Pre-requisites VinylDNS has the following external requirements that need to be setup so that VinylDNS can operate. Those include: DNS - your DNS servers VinylDNS will interact with Database - the database houses all of VinylDNS information including history, records, zones, and users Message Queue - the message queue supports high-availability and throttling of commands to DNS backend servers LDAP - ldap supports both authentication as well as the source of truth for users that are managed inside the VinylDNS database DNS VinylDNS is not a DNS, rather it integrates with your existing DNS installations to enable DNS self-service and streamline DNS operations. VinylDNS communicates to your DNS via: DDNS - DDNS is used for all record updates AXFR - Zone Transfers are used to load DNS records into the VinylDNS database. VinylDNS communicates to your DNS using “connections”. A connection allows you to specify: The TSIG key name The TSIG key secret The server (and optionally port) to communicate to DNS with There are 2 connections, one for DDNS and another for zone transfers. This allows you to use a different DNS server / key for zone transfers. Connections (DDNS and Transfer) can be setup per zone - every zone can override the global default by specifying its own connections. global default - assuming you are managing a primary system, you can configure default zone connections. When no zone connection is specified on a zone, the global defaults will be used. Message Queues Most operations that take place in VinylDNS use a message queue. These operations require high-availability, fault-tolerance with retry, and throttling. The message queue supports these characteristics in VinylDNS. Some operations do not use the message queue, these include user and group changes as they do not carry the same fault-tolerance and throttling requirements. Message Queue Types AWS SQS Our VinylDNS instance uses AWS SQS to fulfill its message queue service needs. SQS has the following characteristics: High-Availability Retry - in the event that a message cannot be processed, or if a node fails midstream processing, it will be automatically made available for another node to process Back-pressure - SQS is a pull based system, meaning that if VinylDNS is currently busy, new messages will not be pulled for processing. As soon as a node becomes available, the message will be pulled. This is much preferable to a push based system, where bottlenecks in processing could cause an increase in heap pressure in the API nodes themselves. Price - SQS is very reasonably priced. Comcast operates multiple message queues for different environments (dev, staging, prod, etc). The price to use SQS is in the single digit dollars per month. VinylDNS can be tuned to run exclusively in the free tier. Review the Setup AWS SQS Guide for more information. MySQL VinylDNS has also implemented a message queue using MySQL, which incorporates the features that we currently utilize through AWS SQS such as changing visibility timeout and re-queuing operations. Review the Setup MySQL Guide for more information. LDAP VinylDNS uses LDAP in order to authenticate users in the Portal. LDAP is not used in the API, instead the API uses its own user and group database for authentication. When a user first logs into VinylDNS, their user information (first name, last name, user name, email) will be pulled from LDAP, and stored in the UserRepository. Credentials will also be generated for the user and stored encrypted in the UserRepository. Review the Setup LDAP Guide for more information" - } , - { - "title": "RecordSet Model", - "url": "/api/recordset-model.html", - "content": "RecordSet Model Table of Contents RecordSet Attributes Record Data Information Record Data Example RecordSet ATTRIBUTES field type description zoneId string the id of the zone to which this recordset belongs name string The name of the RecordSet type string Type of DNS record, supported records are currently: A, AAAA, CNAME, DS, MX, NAPTR, NS, PTR, SOA, SRV, TXT, SSHFP, and SPF. Unsupported types will be given the type UNKNOWN ttl long the TTL in seconds for the recordset status string Active - RecordSet is added is created and ready for use, Inactive - RecordSet effects are not applied, Pending - RecordSet is queued for creation, PendingUpdate - RecordSet is queued for update, PendingDelete - RecordSet is queued for delete created date-time The timestamp (UTC) when the recordset was created updated date-time The timestamp (UTC) when the recordset was last updated records Array of RecordData Array of record data, a single RecordSet can have multiple DNS records as long as they are all the same type id string the id of the recordset. This is important as you will use it for other recordset operations account string DEPRECATED The account that created the RecordSet RecordSet EXAMPLE { \"type\": \"A\", \"zoneId\": \"8f8f649f-998e-4428-a029-b4ba5f5bd4ca\", \"name\": \"foo\", \"ttl\": 38400, \"status\": \"Active\", \"created\": \"2017-02-22T21:34:35Z\", \"records\": [ { \"address\": \"1.1.1.1\" }, { \"address\": \"2.2.2.2\" }, { \"address\": \"3.3.3.3\" } ], \"id\": \"8306cce4-e16a-4579-9b19-4af46dc75853\", \"account\": \"b34f8d18-646f-4843-a80a-7c0d58a22bf5\" } RECORD DATA INFORMATION Current supported record types are: A, AAAA, CNAME, DS, MX, NAPTR, NS, PTR, SOA, SRV, TXT, SSHFP, and SPF. Each individual record encodes its data in a record data object, in which each record type has different required attributes SOA records and NS origin records (record with the same name as the zone) are currently read-only and cannot be created, updated or deleted. Non-origin NS records can be created or updated for approved name servers only. Any non-origin NS record can be deleted. record type attribute type A address string     AAAA address string     CNAME cname string     DS keytag integer DS algorithm integer DS digesttype integer DS digest string     MX preference integer MX exchange string     NAPTR order integer NAPTR preference integer NAPTR flags string NAPTR service string NAPTR regexp string NAPTR replacement string     NS nsdname string     PTR ptrdname string     SOA mname string SOA rname string SOA serial long SOA refresh long SOA retry long SOA expire long SOA minimum long     SPF text string     SRV priority integer SRV weight integer SRV port integer SRV target string     SSHFP algorithm integer SSHFP type integer SSHFP fingerprint string     TXT text string RECORD DATA EXAMPLE Each record is a map that must include all attributes for the data type, the records are stored in the records field of the RecordSet. The records must be an array of at least one record map. All records in the records array must be of the type stored in the typ field of the RecordSet Use the @ symbol to point to the zone origin CNAME records cannot point to the zone origin, thus the RecordSet name cannot be @ nor the zone origin Individual SSHFP record: { \"type\": \"SSHFP\", \"zoneId\": \"8f8f649f-998e-4428-a029-b4ba5f5bd4ca\", \"name\": \"foo\", \"ttl\": 38400, \"status\": \"Active\", \"created\": \"2017-02-22T21:34:35Z\", \"records\": [ { \"algorithm\": 1, \"type\": 3, \"fingerprint\": \"560c7d19d5da9a3a5c7c19992d1fbde15d8dad31\" } ], \"id\": \"8306cce4-e16a-4579-9b19-4af46dc75853\", \"account\": \"b34f8d18-646f-4843-a80a-7c0d58a22bf5\" } Multiple SSHFP records: { \"type\": \"SSHFP\", \"zoneId\": \"8f8f649f-998e-4428-a029-b4ba5f5bd4ca\", \"name\": \"foo\", \"ttl\": 38400, \"status\": \"Active\", \"created\": \"2017-02-22T21:34:35Z\", \"records\": [ { \"algorithm\": 1, \"type\": 2, \"fingerprint\": \"560c7d19d5da9a3a5c7c19992d1fbde15d8dad31\" }, { \"algorithm\": 3, \"type\": 1, \"fingerprint\": \"160c7d19d5da9a3a5c7c19992d1fbde15d8dad31\" }, { \"algorithm\": 4, \"type\": 1, \"fingerprint\": \"260c7d19d5da9a3a5c7c19992d1fbde15d8dad31\" } ], \"id\": \"8306cce4-e16a-4579-9b19-4af46dc75853\", \"account\": \"b34f8d18-646f-4843-a80a-7c0d58a22bf5\" }" - } , - { - "title": "RecordSet Search", - "url": "/portal/recordset-search.html", - "content": "RecordSet Search RecordSet Search provides a view to lookup the state of DNS records within VinylDNS without requiring access to the specific zone. To use the search, a search term containing at least two alphanumeric characters must be entered. Record type and/or record owner group to further filter the search results. There is also a collapsible help section that provides further information regarding search querying tips." - } , - { - "title": "Reject Batch Change", - "url": "/api/reject-batchchange.html", - "content": "Reject Batch Change Manually rejects a batch change in pending review status given the batch change ID, resulting in immediate failure. Only system administrators (i.e., support or super user) can manually review a batch change. Note: If manual review is disabled in the VinylDNS instance, users trying to access this endpoint will encounter a 404 Not Found response since it will not exist. HTTP REQUEST POST /zones/batchrecordchanges/{id}/reject HTTP REQUEST PARAMS name type required? description id string yes Unique identifier assigned to each created batch change. reviewComment string no Optional rejection explanation. EXAMPLE HTTP REQUEST { \"reviewComment\": \"Comments are optional.\" } HTTP RESPONSE TYPES Code description 200 OK Batch change is rejected and is returned in response body. 400 BadRequest Batch change is not in pending approval status. 403 Forbidden User is not a system administrator (ie. support or super user). 404 NotFound Batch change does not exist. HTTP RESPONSE ATTRIBUTES name type description userId string The unique identifier of the user that created the batch change. userName string The username of the user that created the batch change. comments string Conditional: comments about the batch change, if provided. createdTimestamp date-time The timestamp (UTC) when the batch change was created. changes Array of SingleChange Array of single changes within a batch change. A SingleChange can either be a SingleAddChange or a SingleDeleteRRSetChange. status BatchChangeStatus Status of the batch change. id string The unique identifier for this batch change. ownerGroupId string Conditional: Record ownership assignment, if provided. approvalStatus BatchChangeApprovalStatus Whether the batch change is currently awaiting manual review. Will be Rejected status when rejecting. reviewerId string Unique identifier for the reviewer of the batch change. reviewerUserName string User name for the reviewer of the batch change. reviewComment string Conditional: Comment from the reviewer of the batch change, if provided. reviewTimestamp date-time The timestamp (UTC) of when the batch change was manually reviewed. EXAMPLE RESPONSE { \"userId\": \"vinyl\", \"userName\": \"vinyl201\", \"comments\": \"this is optional\", \"createdTimestamp\": \"2019-07-25T20:22:53Z\", \"changes\": [ { \"changeType\": \"Add\", \"inputName\": \"reject.parent.com.\", \"type\": \"A\", \"ttl\": 7200, \"record\": { \"address\": \"1.2.3.4\" }, \"status\": \"Rejected\", \"recordName\": \"\", \"zoneName\": \"\", \"zoneId\": \"\", \"validationErrors\": [ { \"errorType\": \"ZoneDiscoveryError\", \"message\": \"Zone Discovery Failed: zone for \\\"reject.parent.com.\\\" does not exist in VinylDNS. If zone exists, then it must be connected to in VinylDNS.\" } ], \"id\": \"db811a02-5b0f-44ad-8ad9-8ecac7ba6bb4\" } ], \"status\": \"Failed\", \"id\": \"50e1b48b-80fa-41e0-96ef-72438abc31ec\", \"ownerGroupId\": \"159a41c5-e67e-4951-b539-05f5ac788139\", \"reviewerId\": \"90c11ffc-5a71-4794-97c6-74d19c81af7d \", \"reviewComment\": \"We can't make *this* change - are you out of your mind?!\", \"reviewTimestamp\": \"2019-07-25T20:33:41Z\", \"approvalStatus\": \"Rejected\" }" - } , - { - "title": "Search Zones", - "url": "/portal/search-zones.html", - "content": "Search Zones The search box on the Zones page is designed to search on the zone name. It will search the “My Zones” and “All Zones” tabs simultaneously. For partial name matching use * in the search term. Without * the search will be run for exact zone names. The trailing . is accounted for whether it’s in the search term or not. Examples: Given a list of zone names: another.example.com., example.com., test.com., test.net., xyz.efg. Search test returns: No Zones Search test.com returns: test.com. Search test* returns: test.com., test.net. Search *example returns: example.com., another.example.com. Search *e* returns: another.example.com., example.com., test.com., test.net., xyz.efg." - } , - { - "title": "Setup API Server", - "url": "/operator/setup-api.html", - "content": "Setup API Server The API Server is the main run-time for VinylDNS. To setup the API server, follow these steps: Pre-requisites Setup MySQL Setup AWS SQS Configure API Server Using the API Docker Image Using the API Docker Image The API server is provided via the VinylDNS API Image. The docker image allows you to mount your own config, as well as your own external dependency jars. The API server is stateless, allowing you to run multiple instances in multiple data centers for high-availability purposes. Note: If using VinylDNS Java Crypto and the pre-requisites defined here, no additional jars need to be loaded. Environment variables MYSQL_ADDRESS - the IP address of the mysql server; defaults to vinyldns-mysql assuming a docker compose setup MYSQL_PORT - the port of the mysql server; defaults to 3306 Volume Mounts The API exposes volumes that allow the user to customize the runtime. Those mounts include: /opt/vinyldns/lib_extra - place here additional jar files that need to be loaded into the classpath when the application starts up. This is used for “plugins” that are proprietary or not part of the standard build. All jar files here will be placed on the class path. /opt/vinyldns/conf - place an application.conf file here with your own custom settings. Once you have your config created, place here. Ports The API only exposes port 9000 for HTTP access to all endpoints" - } , - { - "title": "Setup LDAP", - "url": "/operator/setup-ldap.html", - "content": "Setup LDAP VinylDNS uses LDAP for authenticating users in the portal as well as the source of user information loaded into VinylDNS. VinylDNS does support service accounts, which are useful for automation. Important Note: VinylDNS presently maintains its own user, group, and membership repository. The only way for a user to be created is to login to the portal. Implementers can choose to out-of-band manage the VinylDNS repositories. There are no steps necessary for setup than having a Directory that can communicate via LDAP, and a user (account) that can read data from the Directory. Once you have that information, proceed to the Portal Configuration. Considerations You should communicate to your Directory over LDAP using TLS. To do so, the SSL certs should be installed on the portal servers, or provided via a java trust store (key store). The portal provides an option to specific a java key store when it starts up. Configuring LDAP Before you can configure LDAP, make note of the host, username, and password that you will be using. Follow the Portal Configuration to complete the setup. Syncing users against LDAP VinylDNS has implemented an optional feature to perform a recurring LDAP lookup against all non-test users in the database and perform a user lock for users that no longer exist in the directory. Automated user locking of deprecated accounts both streamlines the user management process and enforces an extra layer of security around VinylDNS." - } , - { - "title": "Setup MySQL", - "url": "/operator/setup-mysql.html", - "content": "Setup MySQL Our instance of VinylDNS currently stores data in MySQL. zone - holds zones zone_access - holds user or group identifiers that have access to zones batch_change - holds batch changes (multiple changes across zones in a single batch) single_change - holds individual changes within a batch_change user - holds user information, including access keys and secrets record-set - holds record data Setting up the database VinylDNS uses Flyway to manage SQL migrations. This means that any database changes, including creating the database, adding tables, etc. are all automatically applied when VinylDNS starts up. You do not need to do anything other than giving access to VinylDNS API from your MySQL server instance. You can view the database schema and migrations in the mysql module db/migration folder VinylDNS uses HikariCP for a high-speed connection pool. Configuring MySQL Before you can configure MySQL, make note of the host, username, and password that you will be using. Follow the API Database Configuration to complete the setup." - } , - { - "title": "Setup the Portal Server", - "url": "/operator/setup-portal.html", - "content": "Setup the Portal Server The Portal Server is the web UI for VinylDNS. To setup the Portal server, follow these steps: Setup API Server Setup LDAP Configure Portal Server Using the Portal Docker Image Once you have you pre-requisites ready, review the Portal Configuration Guide for how to build out your configuration file. Using the Portal Docker Image The Portal server is provided as a VinylDNS Portal Image. The API server is stateless, allowing you to run multiple instances in multiple data centers for high-availability purposes. Volume mounts /opt/vinyldns/lib_extra - place here additional jar files that need to be loaded into the classpath when the application starts up. This is used for “plugins” that are proprietary or not part of the standard build. All jar files here will be placed on the class path. /opt/vinyldns/conf/application.conf - to override default configuration settings. Follow the Portal Configuration Guide Configuring a custom Java trustStore To add a custom Java trustStore for LDAP certs, add the trustStore to /opt/vinyldns/conf/trustStore.jks. Then add -Djavax.net.ssl.trustStore=/opt/vinyldns/conf/trustStore.jks to the JVM_OPTS environment variable for the container. Example: docker run -e JVM_OPTS=\"-Djavax.net.ssl.trustStore=/opt/vinyldns/conf/trustStore.jks\" ... Additional JVM parameters Additional JVM parameters can be added to the JVM_OPTS environment variable" - } , - { - "title": "Setup AWS SQS", - "url": "/operator/setup-sqs.html", - "content": "Setup AWS SQS SQS is used to provide high-availability and failover in the event that a node crashes mid-stream while processing a message. The backend processing for VinylDNS is built to be idempotent so changes can be fully re-applied. The SQS queue also provides a mechanism to throttle updates, in the event that an out-of-control client submits thousands or millions of concurrent requests, they will all be throttled through SQS. You must setup an SQS queue before you can start working with VinylDNS. An AWS SQS Getting Started Guide provides the information you need to setup your queue. Setting up AWS SQS As opposed to MySQL where everything is created when the application starts up, the SQS queue needs to be setup by hand. This section goes through those settings that are required. The traffic with AWS SQS is rather low. Presently, Comcast operates multiple SQS queues across multiple environments (dev, staging, prod), and incur a cost of less than $10 USD per month. SQS allows up to 1MM requests per month in the free tier. It is possible to operate VinylDNS entirely in the “free” tier. You can “tune down” your usage by increasing your polling interval. The following SQS Queue Attributes are recommended (these are in AWS when you create an SQS Queue): Queue Type - Standard Delivery Delay - 0 seconds Default Visibility Timeout - 1 minute (how long it takes a record change to complete, usually a second) Message Retention Period - 4 days Maximum Message Size - 256KB Receive Message Wait Time - 0 seconds Maximum Receives - 100 (how many times a message will be retried before failing. Note: if any messages retry more than 100 times, there is likely a problem requiring immediate attention) Dead Letter Queue - use a dead letter queue for all queues Configuring SQS Before you can configure SQS, make note of the AWS account (access key and secret access key) as well as the SQS Queue Url that you will be using. Follow the SQS Configuration to complete the setup." - } , - { - "title": "Sync Zone", - "url": "/api/sync-zone.html", - "content": "Sync Zone Used to sync VinylDNS zone info with existing zone info. When a sync is performed, a zone transfer is initiated with the backend DNS server. The backend data is compared to the existing data in VinylDNS. If there are any differences, the backend DNS Server is considered the source of truth and will overwrite the data in VinylDNS. All changes will be recorded in VinylDNS so they can be seen in the zone history. While the zone is syncing, the zone will be unavailable for updates (read-only). We have done some testing on how long syncs take. These will vary with usage: 1000 records ~ 1 second 10,000 records ~ 10 seconds 100,000 records ~ 6 minutes Please keep these numbers in mind when you perform syncs. HTTP REQUEST POST /zones/{zoneId}/sync HTTP RESPONSE TYPES Code description 200 OK - Successful lookup, the zone is returned in the response body 400 Bad Request - invalid sync state, a sync has been performed recently, or zone is inactive 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 403 Forbidden - the user does not have the access required to perform the action 404 Not Found - Zone not found 409 Conflict - Zone has a pending update HTTP RESPONSE ATTRIBUTES name type description status string Sync status zone map Refer to zone model created string The timestamp (UTC) the sync was initiated changeType string Type of change requested (Create, Update, Sync, Delete); in this case Sync userId string The user ID that initiated the change id string The ID of the change. This is not the id of the zone EXAMPLE RESPONSE { \"status\": \"Pending\", \"zone\": { \"status\": \"Syncing\", \"updated\": \"2016-12-28T19:22:02Z\", \"name\": \"sync-test.\", \"adminGroupId\": \"cf00d1e4-46f1-493a-a3be-0ae79dd306a5\", \"created\": \"2016-12-28T19:22:01Z\", \"account\": \"cf00d1e4-46f1-493a-a3be-0ae79dd306a5\", \"email\": \"test@test.com\", \"shared\": false, \"acl\": { \"rules\": [] }, \"id\": \"621a13df-a2e3-4394-84c0-3eb3a664dff4\" }, \"created\": \"2016-12-28T19:22:02Z\", \"changeType\": \"Sync\", \"userId\": \"ok\", \"id\": \"03f1ee91-9053-4346-8b53-e0f6042600f2\" }" - } , - { - "title": "Tools", - "url": "/tools.html", - "content": "VinylDNS Tools There are a few existing tools for working with the VinylDNS API. vinyldns-cli - a VinylDNS API command line client go-vinyldns - Go client package for VinylDNS vinyldns-java - Java client for VinylDNS vinyldns-python - Python client library for VinylDNS vinyldns-js - JavaScript client for use in Node.js terraform-provider-vinyldns - a Terraform provider for VinylDNS Integrations external-dns - DNS provider-agnostic synchronization of Cloud Foundry and Kubernetes resources, including VinylDNS" - } , - { - "title": "Update Group", - "url": "/api/update-group.html", - "content": "Update Group Updates a Group in VinylDNS HTTP REQUEST PUT /groups/{groupId} HTTP REQUEST PARAMS name type required? description id string yes The ID of the group name string yes The name of the group. Should be one word, use hyphens if needed but no spaces email string yes The email distribution list for the group description string no A short description of the group, if more info is needed other than the name created date-time yes The timestamp (UTC) when the group was created status string yes Active or Deleted, should not be changed in an update, a delete request will handle deleting a group members Array of User ID objects yes Set of User IDs in the group admins Array of User ID objects yes Set of User IDs that are admins of the group. All admin user ids should also be in the members array EXAMPLE HTTP REQUEST { \"id\": \"6f8afcda-7529-4cad-9f2d-76903f4b1aca\", \"name\": \"some-group\", \"email\": \"test@example.com\", \"created\": \"Thu Mar 02 2017 10:29:21\", \"status\": \"Active\", \"members\": [ { \"id\": \"4764183c-5e75-4ae6-8833-503cd5f4dcb0\" }, { \"id\": \"k8630ebc-0af2-4c9a-a0a0-d18c590ed03e\" } ], \"admins\": [ { \"id\": \"4764183c-5e75-4ae6-8833-503cd5f4dcb0\" } ] } HTTP RESPONSE TYPES Code description 200 OK - The group has been updated and the group info is returned in the response body 400 Bad Request - The group was invalid or a user id was not found 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 403 Forbidden - The user does not have the access required to perform the action 404 Not Found - The group was not found 409 Conflict - The group already exists HTTP RESPONSE ATTRIBUTES name type description id string Unique UUID of the group name map The name of the group email string The email distribution list of the group description string The group description, the group will not have this attribute if it was not included in the update request and already did not exist created string The timestamp (UTC) the group was created status string Active or Deleted, in this case Active members Array of User Id objects Ids of members of the group including admins admins Array of User Id objects Ids of admins of the group EXAMPLE RESPONSE { \"id\": \"6f8afcda-7529-4cad-9f2d-76903f4b1aca\", \"name\": \"some-group\", \"email\": \"test@example.com\", \"created\": \"2017-03-02T15:29:21Z\", \"status\": \"Active\", \"members\": [ { \"id\": \"2764183c-5e75-4ae6-8833-503cd5f4dcb0\" }, { \"id\": \"c8630ebc-0af2-4c9a-a0a0-d18c590ed03e\" } ], \"admins\": [ { \"id\": \"2764183c-5e75-4ae6-8833-503cd5f4dcb0\" } ] }" - } , - { - "title": "Update RecordSet", - "url": "/api/update-recordset.html", - "content": "Update RecordSet Updates a RecordSet. This performs a delete of the old record, and inserts the new record. HTTP REQUEST PUT /zones/{zoneId}/recordsets/{recordSetId} HTTP REQUEST PARAMS name type required? description zoneId string yes id of the zone where the recordset belongs, this value must match the zoneId of the existing recordSet id string yes the id of the recordset being updated name string yes the name of the recordset being updated type string yes the type of recordset ttl integer yes the TTL in seconds records array of record data yes record data for recordset, see RecordSet Model ownerGroupId string sometimes* Record ownership assignment, applicable if the recordset is in a shared zone *Note: If a recordset has an ownerGroupId you must include that value in the update request, otherwise the update will remove the ownerGroupId value EXAMPLE HTTP REQUEST { \"id\": \"dd9c1120-0594-4e61-982e-8ddcbc8b2d21\", \"name\": \"already-exists\", \"type\": \"A\", \"ttl\": 38400, \"records\": [ { \"address\": \"6.5.4.3\" } ], \"zoneId\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"ownerGroupId\": \"f42385e4-5675-38c0-b42f-64105e743bfe\" } HTTP RESPONSE TYPES Code description 202 Accepted - the update is valid and has been accepted for processing; the record set change resource is returned in the response body 400 Bad Request - the zone being updated is not active; typically because the connection information does not exist for the zone 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 403 Forbidden - The user does not have the access required to perform the action 404 Not Found - Zone or RecordSet not found 409 Conflict - There is an existing pending change against this record set 422 Unprocessable Entity HTTP RESPONSE ATTRIBUTES name type description zone map Contains information about the zone when the change was created recordSet map Contains the recordset model updates map New data to overwrite current record set userId string The user id that initiated the change changeType string Type of change requested (Create, Update, Delete); in this case Update created string The timestamp (UTC) the change was initiated id string The ID of the change. This is not the ID of the recordset status RecordSetChangeStatus The status of the change (Pending, Complete, or Failed) singleBatchChangeIds array of SingleBatchChange ID objects If the recordset change was part of a batch change, the IDs of the single changes that comprise the recordset change EXAMPLE RESPONSE { \"zone\": { \"name\": \"vinyl.\", \"email\": \"test@test.com\", \"status\": \"Active\", \"created\": \"2017-02-23T14:52:44Z\", \"updated\": \"2017-02-23T15:12:33Z\", \"id\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"account\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\", \"shared\": false, \"acl\": { \"rules\": [ ] }, \"adminGroupId\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\", \"latestSync\": \"2017-02-23T15:12:33Z\" }, \"recordSet\": { \"type\": \"A\", \"zoneId\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"name\": \"already-exists\", \"ttl\": 38400, \"status\": \"PendingUpdate\", \"created\": \"2017-02-23T15:12:41Z\", \"updated\": \"2017-02-23T15:12:41Z\", \"records\": [ { \"address\": \"6.6.6.1\" } ], \"id\": \"dd9c1120-0594-4e61-982e-8ddcbc8b2d21\", \"account\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\" }, \"userId\": \"0215d410-9b7e-4636-89fd-b6b948a06347\", \"changeType\": \"Update\", \"status\": \"Pending\", \"created\": \"2017-02-23T15:12:41Z\", \"updates\": { \"type\": \"A\", \"zoneId\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"name\": \"already-exists\", \"ttl\": 38400, \"status\": \"Active\", \"created\": \"2017-02-23T15:12:33Z\", \"records\": [ { \"address\": \"6.6.6.6\" } ], \"id\": \"dd9c1120-0594-4e61-982e-8ddcbc8b2d21\", \"account\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\", \"ownerGroupId\": \"f42385e4-5675-38c0-b42f-64105e743bfe\" }, \"id\": \"df69bc45-2942-4fb7-813c-4dd21cfad7fa\", \"singleBatchChangeIds\": [] }" - } , - { - "title": "Update Zone", - "url": "/api/update-zone.html", - "content": "Update Zone Updates an existing zone that has already been connected to. Used to update the ACL rules or zone level meta data like the zone connection or email. HTTP REQUEST PUT /zones/{zoneId} HTTP REQUEST PARAMS zone fields, refer to zone model EXAMPLE HTTP REQUEST { \"name\": \"vinyl.\", \"email\": \"update@update.com\", \"status\": \"Active\", \"created\": \"2017-02-23T14:52:44Z\", \"updated\": \"2017-02-23T19:05:33Z\", \"id\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"account\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\", \"shared\": false, \"acl\": { \"rules\": [] }, \"adminGroupId\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\", \"latestSync\": \"2017-02-23T19:05:33Z\", \"adminGroupName\": \"test\", \"hiddenKey\": \"\", \"hiddenTransferKey\": \"\" } HTTP RESPONSE TYPES Code description 200 Accepted - The zone change is returned in the response body 400 Bad Request - connection failed 401 Unauthorized - The authentication information provided is invalid. Typically the request was not signed properly, or the access key and secret used to sign the request are incorrect 403 Forbidden - the user does not have the access required to perform the action 404 Not Found - Zone not found 409 Conflict - Zone has a pending update HTTP RESPONSE ATTRIBUTES name type description zone map Zone sent with update request, refer to zone model userId string The user id that initiated the change changeType string Type of change requested (Create, Update, Sync, Delete); in this case Update created string The timestamp (UTC) the change was initiated id string The ID of the change. This is not the ID of the zone status string The status of the zone change EXAMPLE RESPONSE { \"zone\": { \"name\": \"vinyl.\", \"email\": \"update@update.com\", \"status\": \"Active\", \"created\": \"2017-02-23T14:52:44Z\", \"updated\": \"2017-02-23T19:23:26Z\", \"id\": \"2467dc05-68eb-4498-a9d5-78d24bb0893c\", \"account\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\", \"shared\": false, \"acl\": { \"rules\": [] }, \"adminGroupId\": \"9b22b686-54bc-47fb-a8f8-cdc48e6d04ae\", \"latestSync\": \"2017-02-23T19:05:33Z\" }, \"userId\": \"0215d410-9b7e-4636-89fd-b6b948a06347\", \"changeType\": \"Update\", \"status\": \"Pending\", \"created\": \"2017-02-23T19:23:26Z\", \"id\": \"d1fcd28d-61fe-4c24-ac0b-4377d66d50db\" }" - } , - { - "title": "Zone Model", - "url": "/api/zone-model.html", - "content": "Zone Model Table of Contents Zone Attributes Zone JSON Example Zone Connection Attributes Zone Connection JSON Example Zone ACL Rule Attributes Zone ACL Rule Examples PTR ACL Rule PTR ACL Rule Examples Shared Zones ZONE ATTRIBUTES field type description status string Active - the zone is connected and ready for use; Syncing - the zone is currently syncing with the DNS backend and is not available until syncing is complete. updated date-time The last time the zone was changed. Note: this does not include changes to record sets, only the zone entity itself name string The name of the zone adminGroupId string The id of the administrators group for the zone created date-time The time when the zone was first created account string DEPRECATED The account that created the zone email string The distribution email for the zone backendId string Optional. Recommended over connection and transferConnection. The configuration ID of the DNS backend server for the zone. If not provided, default keys will be used unless connection and transfer connection are provided. connection ZoneConnection Optional. The connection used to issue DDNS updates to the backend zone. If not provided, default keys will be used unless backendId is provided. See the Zone Connection Attributes for more information transferConnection ZoneConnection Optional. The connection that is used to sync the zone with the DNS backend. This can be different than the update connection. If not provided, default keys will be used unless backendId is provided. shared boolean An indicator that the zone is shared with anyone. At this time only VinylDNS administrators can set this to true. acl ZoneACL The access control rules governing the zone. See the Zone ACL Rule Attributes for more information id string The unique identifier for this zone latestSync date-time The last date and time the zone was synced isTest boolean Defaults to false. Used for restricted access during VinylDNS testing, can be ignored by clients accessLevel string Access level of the user requesting the zone. Current levels are Delete (full access), Read and NoAccess. ZONE EXAMPLE { \"status\": \"Active\", \"updated\": \"2016-12-16T15:27:28Z\", \"name\": \"ok.\", \"adminGroupId\": \"92b298e8-97db-4f1b-881b-fd08ca0dd311\", \"created\": \"2016-12-16T15:27:26Z\", \"account\": \"92b298e8-97db-4f1b-881b-fd08ca0dd311\", \"email\": \"test@test.com\", \"connection\": { \"primaryServer\": \"127.0.0.1:5301\", \"keyName\": \"vinyl.\", \"name\": \"ok.\", \"key\": \"OBF:1:W1FXgpOjjrQAABAARrZmyLjFSOuFYTAw81mhvNEmNAc4RnYzPjJQMEjVQWWLRohu7gRAVw==\" }, \"transferConnection\": { \"primaryServer\": \"127.0.0.1:5301\", \"keyName\": \"vinyl.\", \"name\": \"ok.\", \"key\": \"OBF:1:W1FXgpOjjrQAABAARrZmyLjFSOuFYTAw81mhvNEmNAc4RnYzPjJQMEjVQWWLRohu7gRAVw==\" }, \"shared\": false, \"acl\": { \"rules\": [ { \"accessLevel\": \"Write\", \"userId\": \"<uuid>\", \"description\": \"some_test_rule\", \"recordTypes\": [] }, { \"recordMask\": \".*\", \"accessLevel\": \"Write\", \"userId\": \"<uuid>\", \"description\": \"some_test_rule\", \"recordTypes\": [] }, { \"recordMask\": \"test.*\", \"accessLevel\": \"Read\", \"groupId\": \"<uuid>\", \"description\": \"some_test_rule\", \"recordTypes\": [] } ] }, \"id\": \"9cbdd3ac-9752-4d56-9ca0-6a1a14fc5562\", \"latestSync\": \"2016-12-16T15:27:26Z\", \"backendId\":\"func-test-backend\", \"accessLevel\": \"Delete\" } ZONE ACL RULE ATTRIBUTES ACL Rules are used to govern user and group access to record operations on a zone. ACL Rules can be associated with a specific user, or all users in a specified group. If neither a user or a group is attached to an ACL rule, then the rule applies to all users in the system. Use the Zone Update endpoint to update the acl attribute of the zone Important! If a user is mentioned on an ACL Rule directly, or is a member of a group that is mentioned on an ACL Rule, that user will be able to see the zone. Rules made without selecting a group or user will apply to all users in VinylDNS. field type description recordMask string (optional) A regular expression that is used to match against record names. If left empty, then all records will be matched for the rule. All records matching the match will be governed by this rule. recordTypes Array[String] An array of all record types that this rule applies to. If left empty, then all record types will be governed by this rule. accessLevel string NoAccess - cannot see the data for the record; Read - can read only the record; Write - the user can create and edit records, but cannot delete them; Delete - the user can read, create, update, and delete records userId string (optional) The unique identifier for the user the rule applies to. Note: this is not the name of the user, but their uuid in VinylDNS groupId string (optional) The unique identifier for the group the rule applies to. Note: you cannot set both the userId and groupId, only one description string (optional) A user entered description for the rule The priority of ACL Rules in descending precedence: Individual rules placed on a user Rules placed on groups that a user is in Rules placed on all users in VinylDNS Note: Being in the admin group of a zone will grant users full access regardless of ACL Rules For conflicting rules, the rule that is more specific will take precedence. For example, if the account jdoe201 was given Read access to all records in a zone through the rule: { \"userId\": \"<uuid>\", \"accessLevel\": \"Read\", } and then Write access to only A records through the rule: { \"userId\": \"<uuid>\", \"accessLevel\": \"Write\", \"recordTypes\": [\"A\"] } and then Delete access to only A records that matched the expression *dev* through the rule: { \"userId\": \"<uuid>\", \"accessLevel\": \"Delete\", \"recordTypes\": [\"A\"], \"recordMask\": \"*dev*\" } then the rule with the recordMask will take precedence and give Delete access to matched A RecordSets, the rule with recordTypes will take precedence and give Write access to all other A records, and the more broad rule will give Read access to all other record types in the zone ZONE ACL RULE EXAMPLES Grant read/write/delete access to www.* records of type A, AAAA, CNAME to one user Under this rule, the user specified will be able to view, create, edit, and delete records in the zone that match the expression www.* and are of type A, AAAA, or CNAME. { \"recordMask\": \"www.*\", \"accessLevel\": \"Delete\", \"userId\": \"<uuid>\", \"recordTypes\": [\"A\", \"AAAA\", \"CNAME\"] } Grant read only access to all VinylDNS users to A, AAAA, CNAME records { \"accessLevel\": \"Read\", \"recordTypes\": [\"A\", \"AAAA\", \"CNAME\"] } Grant read/write/delete access to records of type A, AAAA, CNAME to one group* { \"accessLevel\": \"Delete\", \"groupId\": \"<uuid>\", \"recordTypes\": [\"A\", \"AAAA\", \"CNAME\"] } PTR ACL RULES WITH CIDR MASKS ACL rules can be applied to specific record types and can include record masks to further narrow down which records they apply to. These record masks apply to record names, but because PTR record names are part their reverse zone ip, the use of regular expressions for record masks are not supported. Instead PTR record masks must be CIDR rules, which will denote a range of IP addresses that the rule will apply to. While more information and useful CIDR rule utility tools can be found online, CIDR rules describe how many bits of an ip address’ binary representation must be the same for a match. PTR ACL RULES WITH CIDR MASKS EXAMPLE The ACL Rule { \"recordTypes\": [\"PTR\"], \"accessLevel\": \"Read\" } Will give Read permissions to PTR Record Sets to all users in VinylDNS The IPv4 ACL Rule { \"recordTypes\": [\"PTR\"], \"accessLevel\": \"Read\", \"recordMask\": \"100.100.100.100/16\" } Will give Read permissions to PTR Record Sets 100.100.000.000 to 100.100.255.255, as 16 bits is half of an IPv4 address The IPv6 ACL Rule { \"recordTypes\": [\"PTR\"], \"accessLevel\": \"Read\", \"recordMask\": \"1000:1000:1000:1000:1000:1000:1000:1000/64\" } Will give Read permissions to PTR Record Sets 1000:1000:1000:1000:0000:0000:0000:0000 to 1000:1000:1000:1000:FFFF:FFFF:FFFF:FFFF, as 64 bits is half of an IPv6 address. ZONE CONNECTION ATTRIBUTES In order for VinylDNS to make updates in DNS, it needs key information for every zone. There are 3 ways to specify that key information; ask your VinylDNS admin which is appropriate for your zone based on the configuration of the service: Leave connection, transfer connection, and backend ID blank: In this case, the default VinylDNS keys will be used Specify a backend ID on the zone: if multiple backends are configured for your instance of VinylDNS, you can specify a backend ID on the zone and the keys associated with that backend will be used. Specify zone connection and transfer connection on the zone itself: see below for details Note that if both a backend ID and specific connection keys are included on a zone, the specific connection keys will be used. Zone Connection specifies the connection information to the backend DNS server. field type description primaryServer string The IP address or host that is connected to. This can take a port as well 127.0.0.1:5300. If no port is specified, 53 will be assumed. keyName string The name of the DNS key that has access to the DNS server and zone. Note: For the transfer connection, the key must be given allow-transfer access to the zone. For the primary connection, the key must be given allow-update access to the zone. name string A user identifier for the connection. key string The TSIG secret key used to sign requests when communicating with the primary server. Note: After creating the zone, the key value itself is hashed and obfuscated, so it will be unusable from a client perspective. ZONE CONNECTION EXAMPLE { \"primaryServer\": \"127.0.0.1:5301\", \"keyName\": \"vinyl.\", \"name\": \"ok.\", \"key\": \"OBF:1:W1FXgpOjjrQAABAARrZmyLjFSOuFYTAw81mhvNEmNAc4RnYzPjJQMEjVQWWLRohu7gRAVw==\" } SHARED ZONES Shared zones allow for a more open management of records in VinylDNS. Zone administrators can assign ownership of records to groups. Any user in VinylDNS can claim existing unowned records in shared zones, as well as create records in those zones. Once a record is owned, only users in the record owner group, the zone administrators and those with relevant ACL rules can modify or delete the record. The batch change API endpoint and DNS change area of the portal are where users can create new records in shared zones, modify records they own, or claim unowned records. If a zone’s shared state changes to false the record ownership access is no longer applicable." - } , - { - "title": "Zones", - "url": "/portal/zones.html", - "content": "Zones The My Zones tab lists zones you have access to (through ownership or ACL rules). The list contains links to the individual zone pages where you can manage the zone, it’s records and ACL access. The All Zones tab is intended as a reference, it includes zones you have access to as well as all other private and shared zones in VinylDNS. If needed, you can use the contact information in the list to reach out to the owners of the zones you don’t have access to. Note you may have access to specific records in shared zones, but you are not permitted to access those zones in this area. Those records are accessible via the DNS Changes area of the portal. Search Zones Connect to your zone Manage records Manage access Understand connections" - } - ]; - - idx = lunr(function () { - this.ref("title"); - this.field("content"); - - docs.forEach(function (doc) { - this.add(doc); - }, this); - }); - - docs.forEach(function (doc) { - docMap.set(doc.title, doc.url); - }); -} - -// The onkeypress handler for search functionality -function searchOnKeyDown(e) { - const keyCode = e.keyCode; - const parent = e.target.parentElement; - const isSearchBar = e.target.id === "search-bar"; - const isSearchResult = parent ? parent.id.startsWith("result-") : false; - const isSearchBarOrResult = isSearchBar || isSearchResult; - - if (keyCode === 40 && isSearchBarOrResult) { - // On 'down', try to navigate down the search results - e.preventDefault(); - e.stopPropagation(); - selectDown(e); - } else if (keyCode === 38 && isSearchBarOrResult) { - // On 'up', try to navigate up the search results - e.preventDefault(); - e.stopPropagation(); - selectUp(e); - } else if (keyCode === 27 && isSearchBarOrResult) { - // On 'ESC', close the search dropdown - e.preventDefault(); - e.stopPropagation(); - closeDropdownSearch(e); - } -} - -// Search is only done on key-up so that the search terms are properly propagated -function searchOnKeyUp(e) { - // Filter out up, down, esc keys - const keyCode = e.keyCode; - const cannotBe = [40, 38, 27]; - const isSearchBar = e.target.id === "search-bar"; - const keyIsNotWrong = !cannotBe.includes(keyCode); - if (isSearchBar && keyIsNotWrong) { - // Try to run a search - runSearch(e); - } -} - -// Move the cursor up the search list -function selectUp(e) { - if (e.target.parentElement.id.startsWith("result-")) { - const index = parseInt(e.target.parentElement.id.substring(7)); - if (!isNaN(index) && (index > 0)) { - const nextIndexStr = "result-" + (index - 1); - const querySel = "li[id$='" + nextIndexStr + "'"; - const nextResult = document.querySelector(querySel); - if (nextResult) { - nextResult.firstChild.focus(); - } - } - } -} - -// Move the cursor down the search list -function selectDown(e) { - if (e.target.id === "search-bar") { - const firstResult = document.querySelector("li[id$='result-0']"); - if (firstResult) { - firstResult.firstChild.focus(); - } - } else if (e.target.parentElement.id.startsWith("result-")) { - const index = parseInt(e.target.parentElement.id.substring(7)); - if (!isNaN(index)) { - const nextIndexStr = "result-" + (index + 1); - const querySel = "li[id$='" + nextIndexStr + "'"; - const nextResult = document.querySelector(querySel); - if (nextResult) { - nextResult.firstChild.focus(); - } - } - } -} - -// Search for whatever the user has typed so far -function runSearch(e) { - if (e.target.value === "") { - // On empty string, remove all search results - // Otherwise this may show all results as everything is a "match" - applySearchResults([]); - } else { - const tokens = e.target.value.split(" "); - const moddedTokens = tokens.map(function (token) { - // "*" + token + "*" - return token; - }) - const searchTerm = moddedTokens.join(" "); - const searchResults = idx.search(searchTerm); - const mapResults = searchResults.map(function (result) { - const resultUrl = docMap.get(result.ref); - return { name: result.ref, url: resultUrl }; - }) - - applySearchResults(mapResults); - } - -} - -// After a search, modify the search dropdown to contain the search results -function applySearchResults(results) { - const dropdown = document.querySelector("div[id$='search-dropdown'] > .dropdown-content.show"); - if (dropdown) { - //Remove each child - while (dropdown.firstChild) { - dropdown.removeChild(dropdown.firstChild); - } - - //Add each result as an element in the list - results.forEach(function (result, i) { - const elem = document.createElement("li"); - elem.setAttribute("class", "dropdown-item"); - elem.setAttribute("id", "result-" + i); - - const elemLink = document.createElement("a"); - elemLink.setAttribute("title", result.name); - elemLink.setAttribute("href", result.url); - elemLink.setAttribute("class", "dropdown-item-link"); - - const elemLinkText = document.createElement("span"); - elemLinkText.setAttribute("class", "dropdown-item-link-text"); - elemLinkText.innerHTML = result.name; - - elemLink.appendChild(elemLinkText); - elem.appendChild(elemLink); - dropdown.appendChild(elem); - }); - } -} - -// Close the dropdown if the user clicks (only) outside of it -function closeDropdownSearch(e) { - // Check if where we're clicking is the search dropdown - if (e.target.id !== "search-bar") { - const dropdown = document.querySelector("div[id$='search-dropdown'] > .dropdown-content.show"); - if (dropdown) { - dropdown.classList.remove("show"); - document.documentElement.removeEventListener("click", closeDropdownSearch); - } - } -} diff --git a/js/version-selector.js b/js/version-selector.js deleted file mode 100644 index 0c3e58550..000000000 --- a/js/version-selector.js +++ /dev/null @@ -1,36 +0,0 @@ -/* When the user clicks on the navigation Documentation button, - * toggle between hiding and showing the dropdown content. - */ -function displayToggleVersion(e) { - e.preventDefault(); - e.stopPropagation(); - // Calling close func. in case we're clicking another dropdown with one opened - closeDropdownVersion(e); - const parent = e.target.closest("div[id$='version-dropdown']"); - if (parent) { - const dropdown = parent.querySelector("#version-dropdown-content"); - if (dropdown) { - dropdown.classList.toggle("show"); - if (dropdown.classList.contains("show")) { - document.documentElement.addEventListener("click", closeDropdownVersion); - } - else { - document.documentElement.removeEventListener("click", closeDropdownVersion); - } - } - } -} - -// Close the dropdown if the user clicks (only) outside of it -function closeDropdownVersion(e) { - const dropdown = document.querySelector("div[id$='version-dropdown'] > .dropdown-content.show"); - if (dropdown) { - const currentTarget = e.currentTarget || {}; - const currentTargetParent = currentTarget.closest("div[id$='version-dropdown']"); - const dropdownParent = dropdown.closest("div[id$='version-dropdown']"); - if (currentTargetParent !== dropdownParent) { - dropdown.classList.remove("show"); - } - document.documentElement.removeEventListener("click", closeDropdownVersion); - } -} diff --git a/lunr/LICENSE b/lunr/LICENSE deleted file mode 100644 index 8a12a69b4..000000000 --- a/lunr/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ - -Copyright (C) 2013 by Oliver Nightingale - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file diff --git a/lunr/lunr.js b/lunr/lunr.js deleted file mode 100644 index fc329593b..000000000 --- a/lunr/lunr.js +++ /dev/null @@ -1,3475 +0,0 @@ -/** - * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9 - * Copyright (C) 2020 Oliver Nightingale - * @license MIT - */ - -; (function () { - - /** - * A convenience function for configuring and constructing - * a new lunr Index. - * - * A lunr.Builder instance is created and the pipeline setup - * with a trimmer, stop word filter and stemmer. - * - * This builder object is yielded to the configuration function - * that is passed as a parameter, allowing the list of fields - * and other builder parameters to be customised. - * - * All documents _must_ be added within the passed config function. - * - * @example - * var idx = lunr(function () { - * this.field('title') - * this.field('body') - * this.ref('id') - * - * documents.forEach(function (doc) { - * this.add(doc) - * }, this) - * }) - * - * @see {@link lunr.Builder} - * @see {@link lunr.Pipeline} - * @see {@link lunr.trimmer} - * @see {@link lunr.stopWordFilter} - * @see {@link lunr.stemmer} - * @namespace {function} lunr - */ - var lunr = function (config) { - var builder = new lunr.Builder - - builder.pipeline.add( - lunr.trimmer, - lunr.stopWordFilter, - lunr.stemmer - ) - - builder.searchPipeline.add( - lunr.stemmer - ) - - config.call(builder, builder) - return builder.build() - } - - lunr.version = "2.3.9" - /*! - * lunr.utils - * Copyright (C) 2020 Oliver Nightingale - */ - - /** - * A namespace containing utils for the rest of the lunr library - * @namespace lunr.utils - */ - lunr.utils = {} - - /** - * Print a warning message to the console. - * - * @param {String} message The message to be printed. - * @memberOf lunr.utils - * @function - */ - lunr.utils.warn = (function (global) { - /* eslint-disable no-console */ - return function (message) { - if (global.console && console.warn) { - console.warn(message) - } - } - /* eslint-enable no-console */ - })(this) - - /** - * Convert an object to a string. - * - * In the case of `null` and `undefined` the function returns - * the empty string, in all other cases the result of calling - * `toString` on the passed object is returned. - * - * @param {Any} obj The object to convert to a string. - * @return {String} string representation of the passed object. - * @memberOf lunr.utils - */ - lunr.utils.asString = function (obj) { - if (obj === void 0 || obj === null) { - return "" - } else { - return obj.toString() - } - } - - /** - * Clones an object. - * - * Will create a copy of an existing object such that any mutations - * on the copy cannot affect the original. - * - * Only shallow objects are supported, passing a nested object to this - * function will cause a TypeError. - * - * Objects with primitives, and arrays of primitives are supported. - * - * @param {Object} obj The object to clone. - * @return {Object} a clone of the passed object. - * @throws {TypeError} when a nested object is passed. - * @memberOf Utils - */ - lunr.utils.clone = function (obj) { - if (obj === null || obj === undefined) { - return obj - } - - var clone = Object.create(null), - keys = Object.keys(obj) - - for (var i = 0; i < keys.length; i++) { - var key = keys[i], - val = obj[key] - - if (Array.isArray(val)) { - clone[key] = val.slice() - continue - } - - if (typeof val === 'string' || - typeof val === 'number' || - typeof val === 'boolean') { - clone[key] = val - continue - } - - throw new TypeError("clone is not deep and does not support nested objects") - } - - return clone - } - lunr.FieldRef = function (docRef, fieldName, stringValue) { - this.docRef = docRef - this.fieldName = fieldName - this._stringValue = stringValue - } - - lunr.FieldRef.joiner = "/" - - lunr.FieldRef.fromString = function (s) { - var n = s.indexOf(lunr.FieldRef.joiner) - - if (n === -1) { - throw "malformed field ref string" - } - - var fieldRef = s.slice(0, n), - docRef = s.slice(n + 1) - - return new lunr.FieldRef(docRef, fieldRef, s) - } - - lunr.FieldRef.prototype.toString = function () { - if (this._stringValue == undefined) { - this._stringValue = this.fieldName + lunr.FieldRef.joiner + this.docRef - } - - return this._stringValue - } - /*! - * lunr.Set - * Copyright (C) 2020 Oliver Nightingale - */ - - /** - * A lunr set. - * - * @constructor - */ - lunr.Set = function (elements) { - this.elements = Object.create(null) - - if (elements) { - this.length = elements.length - - for (var i = 0; i < this.length; i++) { - this.elements[elements[i]] = true - } - } else { - this.length = 0 - } - } - - /** - * A complete set that contains all elements. - * - * @static - * @readonly - * @type {lunr.Set} - */ - lunr.Set.complete = { - intersect: function (other) { - return other - }, - - union: function () { - return this - }, - - contains: function () { - return true - } - } - - /** - * An empty set that contains no elements. - * - * @static - * @readonly - * @type {lunr.Set} - */ - lunr.Set.empty = { - intersect: function () { - return this - }, - - union: function (other) { - return other - }, - - contains: function () { - return false - } - } - - /** - * Returns true if this set contains the specified object. - * - * @param {object} object - Object whose presence in this set is to be tested. - * @returns {boolean} - True if this set contains the specified object. - */ - lunr.Set.prototype.contains = function (object) { - return !!this.elements[object] - } - - /** - * Returns a new set containing only the elements that are present in both - * this set and the specified set. - * - * @param {lunr.Set} other - set to intersect with this set. - * @returns {lunr.Set} a new set that is the intersection of this and the specified set. - */ - - lunr.Set.prototype.intersect = function (other) { - var a, b, elements, intersection = [] - - if (other === lunr.Set.complete) { - return this - } - - if (other === lunr.Set.empty) { - return other - } - - if (this.length < other.length) { - a = this - b = other - } else { - a = other - b = this - } - - elements = Object.keys(a.elements) - - for (var i = 0; i < elements.length; i++) { - var element = elements[i] - if (element in b.elements) { - intersection.push(element) - } - } - - return new lunr.Set(intersection) - } - - /** - * Returns a new set combining the elements of this and the specified set. - * - * @param {lunr.Set} other - set to union with this set. - * @return {lunr.Set} a new set that is the union of this and the specified set. - */ - - lunr.Set.prototype.union = function (other) { - if (other === lunr.Set.complete) { - return lunr.Set.complete - } - - if (other === lunr.Set.empty) { - return this - } - - return new lunr.Set(Object.keys(this.elements).concat(Object.keys(other.elements))) - } - /** - * A function to calculate the inverse document frequency for - * a posting. This is shared between the builder and the index - * - * @private - * @param {object} posting - The posting for a given term - * @param {number} documentCount - The total number of documents. - */ - lunr.idf = function (posting, documentCount) { - var documentsWithTerm = 0 - - for (var fieldName in posting) { - if (fieldName == '_index') continue // Ignore the term index, its not a field - documentsWithTerm += Object.keys(posting[fieldName]).length - } - - var x = (documentCount - documentsWithTerm + 0.5) / (documentsWithTerm + 0.5) - - return Math.log(1 + Math.abs(x)) - } - - /** - * A token wraps a string representation of a token - * as it is passed through the text processing pipeline. - * - * @constructor - * @param {string} [str=''] - The string token being wrapped. - * @param {object} [metadata={}] - Metadata associated with this token. - */ - lunr.Token = function (str, metadata) { - this.str = str || "" - this.metadata = metadata || {} - } - - /** - * Returns the token string that is being wrapped by this object. - * - * @returns {string} - */ - lunr.Token.prototype.toString = function () { - return this.str - } - - /** - * A token update function is used when updating or optionally - * when cloning a token. - * - * @callback lunr.Token~updateFunction - * @param {string} str - The string representation of the token. - * @param {Object} metadata - All metadata associated with this token. - */ - - /** - * Applies the given function to the wrapped string token. - * - * @example - * token.update(function (str, metadata) { - * return str.toUpperCase() - * }) - * - * @param {lunr.Token~updateFunction} fn - A function to apply to the token string. - * @returns {lunr.Token} - */ - lunr.Token.prototype.update = function (fn) { - this.str = fn(this.str, this.metadata) - return this - } - - /** - * Creates a clone of this token. Optionally a function can be - * applied to the cloned token. - * - * @param {lunr.Token~updateFunction} [fn] - An optional function to apply to the cloned token. - * @returns {lunr.Token} - */ - lunr.Token.prototype.clone = function (fn) { - fn = fn || function (s) { return s } - return new lunr.Token(fn(this.str, this.metadata), this.metadata) - } - /*! - * lunr.tokenizer - * Copyright (C) 2020 Oliver Nightingale - */ - - /** - * A function for splitting a string into tokens ready to be inserted into - * the search index. Uses `lunr.tokenizer.separator` to split strings, change - * the value of this property to change how strings are split into tokens. - * - * This tokenizer will convert its parameter to a string by calling `toString` and - * then will split this string on the character in `lunr.tokenizer.separator`. - * Arrays will have their elements converted to strings and wrapped in a lunr.Token. - * - * Optional metadata can be passed to the tokenizer, this metadata will be cloned and - * added as metadata to every token that is created from the object to be tokenized. - * - * @static - * @param {?(string|object|object[])} obj - The object to convert into tokens - * @param {?object} metadata - Optional metadata to associate with every token - * @returns {lunr.Token[]} - * @see {@link lunr.Pipeline} - */ - lunr.tokenizer = function (obj, metadata) { - if (obj == null || obj == undefined) { - return [] - } - - if (Array.isArray(obj)) { - return obj.map(function (t) { - return new lunr.Token( - lunr.utils.asString(t).toLowerCase(), - lunr.utils.clone(metadata) - ) - }) - } - - var str = obj.toString().toLowerCase(), - len = str.length, - tokens = [] - - for (var sliceEnd = 0, sliceStart = 0; sliceEnd <= len; sliceEnd++) { - var char = str.charAt(sliceEnd), - sliceLength = sliceEnd - sliceStart - - if ((char.match(lunr.tokenizer.separator) || sliceEnd == len)) { - - if (sliceLength > 0) { - var tokenMetadata = lunr.utils.clone(metadata) || {} - tokenMetadata["position"] = [sliceStart, sliceLength] - tokenMetadata["index"] = tokens.length - - tokens.push( - new lunr.Token( - str.slice(sliceStart, sliceEnd), - tokenMetadata - ) - ) - } - - sliceStart = sliceEnd + 1 - } - - } - - return tokens - } - - /** - * The separator used to split a string into tokens. Override this property to change the behaviour of - * `lunr.tokenizer` behaviour when tokenizing strings. By default this splits on whitespace and hyphens. - * - * @static - * @see lunr.tokenizer - */ - lunr.tokenizer.separator = /[\s\-]+/ - /*! - * lunr.Pipeline - * Copyright (C) 2020 Oliver Nightingale - */ - - /** - * lunr.Pipelines maintain an ordered list of functions to be applied to all - * tokens in documents entering the search index and queries being ran against - * the index. - * - * An instance of lunr.Index created with the lunr shortcut will contain a - * pipeline with a stop word filter and an English language stemmer. Extra - * functions can be added before or after either of these functions or these - * default functions can be removed. - * - * When run the pipeline will call each function in turn, passing a token, the - * index of that token in the original list of all tokens and finally a list of - * all the original tokens. - * - * The output of functions in the pipeline will be passed to the next function - * in the pipeline. To exclude a token from entering the index the function - * should return undefined, the rest of the pipeline will not be called with - * this token. - * - * For serialisation of pipelines to work, all functions used in an instance of - * a pipeline should be registered with lunr.Pipeline. Registered functions can - * then be loaded. If trying to load a serialised pipeline that uses functions - * that are not registered an error will be thrown. - * - * If not planning on serialising the pipeline then registering pipeline functions - * is not necessary. - * - * @constructor - */ - lunr.Pipeline = function () { - this._stack = [] - } - - lunr.Pipeline.registeredFunctions = Object.create(null) - - /** - * A pipeline function maps lunr.Token to lunr.Token. A lunr.Token contains the token - * string as well as all known metadata. A pipeline function can mutate the token string - * or mutate (or add) metadata for a given token. - * - * A pipeline function can indicate that the passed token should be discarded by returning - * null, undefined or an empty string. This token will not be passed to any downstream pipeline - * functions and will not be added to the index. - * - * Multiple tokens can be returned by returning an array of tokens. Each token will be passed - * to any downstream pipeline functions and all will returned tokens will be added to the index. - * - * Any number of pipeline functions may be chained together using a lunr.Pipeline. - * - * @interface lunr.PipelineFunction - * @param {lunr.Token} token - A token from the document being processed. - * @param {number} i - The index of this token in the complete list of tokens for this document/field. - * @param {lunr.Token[]} tokens - All tokens for this document/field. - * @returns {(?lunr.Token|lunr.Token[])} - */ - - /** - * Register a function with the pipeline. - * - * Functions that are used in the pipeline should be registered if the pipeline - * needs to be serialised, or a serialised pipeline needs to be loaded. - * - * Registering a function does not add it to a pipeline, functions must still be - * added to instances of the pipeline for them to be used when running a pipeline. - * - * @param {lunr.PipelineFunction} fn - The function to check for. - * @param {String} label - The label to register this function with - */ - lunr.Pipeline.registerFunction = function (fn, label) { - if (label in this.registeredFunctions) { - lunr.utils.warn('Overwriting existing registered function: ' + label) - } - - fn.label = label - lunr.Pipeline.registeredFunctions[fn.label] = fn - } - - /** - * Warns if the function is not registered as a Pipeline function. - * - * @param {lunr.PipelineFunction} fn - The function to check for. - * @private - */ - lunr.Pipeline.warnIfFunctionNotRegistered = function (fn) { - var isRegistered = fn.label && (fn.label in this.registeredFunctions) - - if (!isRegistered) { - lunr.utils.warn('Function is not registered with pipeline. This may cause problems when serialising the index.\n', fn) - } - } - - /** - * Loads a previously serialised pipeline. - * - * All functions to be loaded must already be registered with lunr.Pipeline. - * If any function from the serialised data has not been registered then an - * error will be thrown. - * - * @param {Object} serialised - The serialised pipeline to load. - * @returns {lunr.Pipeline} - */ - lunr.Pipeline.load = function (serialised) { - var pipeline = new lunr.Pipeline - - serialised.forEach(function (fnName) { - var fn = lunr.Pipeline.registeredFunctions[fnName] - - if (fn) { - pipeline.add(fn) - } else { - throw new Error('Cannot load unregistered function: ' + fnName) - } - }) - - return pipeline - } - - /** - * Adds new functions to the end of the pipeline. - * - * Logs a warning if the function has not been registered. - * - * @param {lunr.PipelineFunction[]} functions - Any number of functions to add to the pipeline. - */ - lunr.Pipeline.prototype.add = function () { - var fns = Array.prototype.slice.call(arguments) - - fns.forEach(function (fn) { - lunr.Pipeline.warnIfFunctionNotRegistered(fn) - this._stack.push(fn) - }, this) - } - - /** - * Adds a single function after a function that already exists in the - * pipeline. - * - * Logs a warning if the function has not been registered. - * - * @param {lunr.PipelineFunction} existingFn - A function that already exists in the pipeline. - * @param {lunr.PipelineFunction} newFn - The new function to add to the pipeline. - */ - lunr.Pipeline.prototype.after = function (existingFn, newFn) { - lunr.Pipeline.warnIfFunctionNotRegistered(newFn) - - var pos = this._stack.indexOf(existingFn) - if (pos == -1) { - throw new Error('Cannot find existingFn') - } - - pos = pos + 1 - this._stack.splice(pos, 0, newFn) - } - - /** - * Adds a single function before a function that already exists in the - * pipeline. - * - * Logs a warning if the function has not been registered. - * - * @param {lunr.PipelineFunction} existingFn - A function that already exists in the pipeline. - * @param {lunr.PipelineFunction} newFn - The new function to add to the pipeline. - */ - lunr.Pipeline.prototype.before = function (existingFn, newFn) { - lunr.Pipeline.warnIfFunctionNotRegistered(newFn) - - var pos = this._stack.indexOf(existingFn) - if (pos == -1) { - throw new Error('Cannot find existingFn') - } - - this._stack.splice(pos, 0, newFn) - } - - /** - * Removes a function from the pipeline. - * - * @param {lunr.PipelineFunction} fn The function to remove from the pipeline. - */ - lunr.Pipeline.prototype.remove = function (fn) { - var pos = this._stack.indexOf(fn) - if (pos == -1) { - return - } - - this._stack.splice(pos, 1) - } - - /** - * Runs the current list of functions that make up the pipeline against the - * passed tokens. - * - * @param {Array} tokens The tokens to run through the pipeline. - * @returns {Array} - */ - lunr.Pipeline.prototype.run = function (tokens) { - var stackLength = this._stack.length - - for (var i = 0; i < stackLength; i++) { - var fn = this._stack[i] - var memo = [] - - for (var j = 0; j < tokens.length; j++) { - var result = fn(tokens[j], j, tokens) - - if (result === null || result === void 0 || result === '') continue - - if (Array.isArray(result)) { - for (var k = 0; k < result.length; k++) { - memo.push(result[k]) - } - } else { - memo.push(result) - } - } - - tokens = memo - } - - return tokens - } - - /** - * Convenience method for passing a string through a pipeline and getting - * strings out. This method takes care of wrapping the passed string in a - * token and mapping the resulting tokens back to strings. - * - * @param {string} str - The string to pass through the pipeline. - * @param {?object} metadata - Optional metadata to associate with the token - * passed to the pipeline. - * @returns {string[]} - */ - lunr.Pipeline.prototype.runString = function (str, metadata) { - var token = new lunr.Token(str, metadata) - - return this.run([token]).map(function (t) { - return t.toString() - }) - } - - /** - * Resets the pipeline by removing any existing processors. - * - */ - lunr.Pipeline.prototype.reset = function () { - this._stack = [] - } - - /** - * Returns a representation of the pipeline ready for serialisation. - * - * Logs a warning if the function has not been registered. - * - * @returns {Array} - */ - lunr.Pipeline.prototype.toJSON = function () { - return this._stack.map(function (fn) { - lunr.Pipeline.warnIfFunctionNotRegistered(fn) - - return fn.label - }) - } - /*! - * lunr.Vector - * Copyright (C) 2020 Oliver Nightingale - */ - - /** - * A vector is used to construct the vector space of documents and queries. These - * vectors support operations to determine the similarity between two documents or - * a document and a query. - * - * Normally no parameters are required for initializing a vector, but in the case of - * loading a previously dumped vector the raw elements can be provided to the constructor. - * - * For performance reasons vectors are implemented with a flat array, where an elements - * index is immediately followed by its value. E.g. [index, value, index, value]. This - * allows the underlying array to be as sparse as possible and still offer decent - * performance when being used for vector calculations. - * - * @constructor - * @param {Number[]} [elements] - The flat list of element index and element value pairs. - */ - lunr.Vector = function (elements) { - this._magnitude = 0 - this.elements = elements || [] - } - - - /** - * Calculates the position within the vector to insert a given index. - * - * This is used internally by insert and upsert. If there are duplicate indexes then - * the position is returned as if the value for that index were to be updated, but it - * is the callers responsibility to check whether there is a duplicate at that index - * - * @param {Number} insertIdx - The index at which the element should be inserted. - * @returns {Number} - */ - lunr.Vector.prototype.positionForIndex = function (index) { - // For an empty vector the tuple can be inserted at the beginning - if (this.elements.length == 0) { - return 0 - } - - var start = 0, - end = this.elements.length / 2, - sliceLength = end - start, - pivotPoint = Math.floor(sliceLength / 2), - pivotIndex = this.elements[pivotPoint * 2] - - while (sliceLength > 1) { - if (pivotIndex < index) { - start = pivotPoint - } - - if (pivotIndex > index) { - end = pivotPoint - } - - if (pivotIndex == index) { - break - } - - sliceLength = end - start - pivotPoint = start + Math.floor(sliceLength / 2) - pivotIndex = this.elements[pivotPoint * 2] - } - - if (pivotIndex == index) { - return pivotPoint * 2 - } - - if (pivotIndex > index) { - return pivotPoint * 2 - } - - if (pivotIndex < index) { - return (pivotPoint + 1) * 2 - } - } - - /** - * Inserts an element at an index within the vector. - * - * Does not allow duplicates, will throw an error if there is already an entry - * for this index. - * - * @param {Number} insertIdx - The index at which the element should be inserted. - * @param {Number} val - The value to be inserted into the vector. - */ - lunr.Vector.prototype.insert = function (insertIdx, val) { - this.upsert(insertIdx, val, function () { - throw "duplicate index" - }) - } - - /** - * Inserts or updates an existing index within the vector. - * - * @param {Number} insertIdx - The index at which the element should be inserted. - * @param {Number} val - The value to be inserted into the vector. - * @param {function} fn - A function that is called for updates, the existing value and the - * requested value are passed as arguments - */ - lunr.Vector.prototype.upsert = function (insertIdx, val, fn) { - this._magnitude = 0 - var position = this.positionForIndex(insertIdx) - - if (this.elements[position] == insertIdx) { - this.elements[position + 1] = fn(this.elements[position + 1], val) - } else { - this.elements.splice(position, 0, insertIdx, val) - } - } - - /** - * Calculates the magnitude of this vector. - * - * @returns {Number} - */ - lunr.Vector.prototype.magnitude = function () { - if (this._magnitude) return this._magnitude - - var sumOfSquares = 0, - elementsLength = this.elements.length - - for (var i = 1; i < elementsLength; i += 2) { - var val = this.elements[i] - sumOfSquares += val * val - } - - return this._magnitude = Math.sqrt(sumOfSquares) - } - - /** - * Calculates the dot product of this vector and another vector. - * - * @param {lunr.Vector} otherVector - The vector to compute the dot product with. - * @returns {Number} - */ - lunr.Vector.prototype.dot = function (otherVector) { - var dotProduct = 0, - a = this.elements, b = otherVector.elements, - aLen = a.length, bLen = b.length, - aVal = 0, bVal = 0, - i = 0, j = 0 - - while (i < aLen && j < bLen) { - aVal = a[i], bVal = b[j] - if (aVal < bVal) { - i += 2 - } else if (aVal > bVal) { - j += 2 - } else if (aVal == bVal) { - dotProduct += a[i + 1] * b[j + 1] - i += 2 - j += 2 - } - } - - return dotProduct - } - - /** - * Calculates the similarity between this vector and another vector. - * - * @param {lunr.Vector} otherVector - The other vector to calculate the - * similarity with. - * @returns {Number} - */ - lunr.Vector.prototype.similarity = function (otherVector) { - return this.dot(otherVector) / this.magnitude() || 0 - } - - /** - * Converts the vector to an array of the elements within the vector. - * - * @returns {Number[]} - */ - lunr.Vector.prototype.toArray = function () { - var output = new Array(this.elements.length / 2) - - for (var i = 1, j = 0; i < this.elements.length; i += 2, j++) { - output[j] = this.elements[i] - } - - return output - } - - /** - * A JSON serializable representation of the vector. - * - * @returns {Number[]} - */ - lunr.Vector.prototype.toJSON = function () { - return this.elements - } - /* eslint-disable */ - /*! - * lunr.stemmer - * Copyright (C) 2020 Oliver Nightingale - * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt - */ - - /** - * lunr.stemmer is an english language stemmer, this is a JavaScript - * implementation of the PorterStemmer taken from http://tartarus.org/~martin - * - * @static - * @implements {lunr.PipelineFunction} - * @param {lunr.Token} token - The string to stem - * @returns {lunr.Token} - * @see {@link lunr.Pipeline} - * @function - */ - lunr.stemmer = (function () { - var step2list = { - "ational": "ate", - "tional": "tion", - "enci": "ence", - "anci": "ance", - "izer": "ize", - "bli": "ble", - "alli": "al", - "entli": "ent", - "eli": "e", - "ousli": "ous", - "ization": "ize", - "ation": "ate", - "ator": "ate", - "alism": "al", - "iveness": "ive", - "fulness": "ful", - "ousness": "ous", - "aliti": "al", - "iviti": "ive", - "biliti": "ble", - "logi": "log" - }, - - step3list = { - "icate": "ic", - "ative": "", - "alize": "al", - "iciti": "ic", - "ical": "ic", - "ful": "", - "ness": "" - }, - - c = "[^aeiou]", // consonant - v = "[aeiouy]", // vowel - C = c + "[^aeiouy]*", // consonant sequence - V = v + "[aeiou]*", // vowel sequence - - mgr0 = "^(" + C + ")?" + V + C, // [C]VC... is m>0 - meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$", // [C]VC[V] is m=1 - mgr1 = "^(" + C + ")?" + V + C + V + C, // [C]VCVC... is m>1 - s_v = "^(" + C + ")?" + v; // vowel in stem - - var re_mgr0 = new RegExp(mgr0); - var re_mgr1 = new RegExp(mgr1); - var re_meq1 = new RegExp(meq1); - var re_s_v = new RegExp(s_v); - - var re_1a = /^(.+?)(ss|i)es$/; - var re2_1a = /^(.+?)([^s])s$/; - var re_1b = /^(.+?)eed$/; - var re2_1b = /^(.+?)(ed|ing)$/; - var re_1b_2 = /.$/; - var re2_1b_2 = /(at|bl|iz)$/; - var re3_1b_2 = new RegExp("([^aeiouylsz])\\1$"); - var re4_1b_2 = new RegExp("^" + C + v + "[^aeiouwxy]$"); - - var re_1c = /^(.+?[^aeiou])y$/; - var re_2 = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; - - var re_3 = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; - - var re_4 = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; - var re2_4 = /^(.+?)(s|t)(ion)$/; - - var re_5 = /^(.+?)e$/; - var re_5_1 = /ll$/; - var re3_5 = new RegExp("^" + C + v + "[^aeiouwxy]$"); - - var porterStemmer = function porterStemmer(w) { - var stem, - suffix, - firstch, - re, - re2, - re3, - re4; - - if (w.length < 3) { return w; } - - firstch = w.substr(0, 1); - if (firstch == "y") { - w = firstch.toUpperCase() + w.substr(1); - } - - // Step 1a - re = re_1a - re2 = re2_1a; - - if (re.test(w)) { w = w.replace(re, "$1$2"); } - else if (re2.test(w)) { w = w.replace(re2, "$1$2"); } - - // Step 1b - re = re_1b; - re2 = re2_1b; - if (re.test(w)) { - var fp = re.exec(w); - re = re_mgr0; - if (re.test(fp[1])) { - re = re_1b_2; - w = w.replace(re, ""); - } - } else if (re2.test(w)) { - var fp = re2.exec(w); - stem = fp[1]; - re2 = re_s_v; - if (re2.test(stem)) { - w = stem; - re2 = re2_1b_2; - re3 = re3_1b_2; - re4 = re4_1b_2; - if (re2.test(w)) { w = w + "e"; } - else if (re3.test(w)) { re = re_1b_2; w = w.replace(re, ""); } - else if (re4.test(w)) { w = w + "e"; } - } - } - - // Step 1c - replace suffix y or Y by i if preceded by a non-vowel which is not the first letter of the word (so cry -> cri, by -> by, say -> say) - re = re_1c; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - w = stem + "i"; - } - - // Step 2 - re = re_2; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - suffix = fp[2]; - re = re_mgr0; - if (re.test(stem)) { - w = stem + step2list[suffix]; - } - } - - // Step 3 - re = re_3; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - suffix = fp[2]; - re = re_mgr0; - if (re.test(stem)) { - w = stem + step3list[suffix]; - } - } - - // Step 4 - re = re_4; - re2 = re2_4; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - re = re_mgr1; - if (re.test(stem)) { - w = stem; - } - } else if (re2.test(w)) { - var fp = re2.exec(w); - stem = fp[1] + fp[2]; - re2 = re_mgr1; - if (re2.test(stem)) { - w = stem; - } - } - - // Step 5 - re = re_5; - if (re.test(w)) { - var fp = re.exec(w); - stem = fp[1]; - re = re_mgr1; - re2 = re_meq1; - re3 = re3_5; - if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) { - w = stem; - } - } - - re = re_5_1; - re2 = re_mgr1; - if (re.test(w) && re2.test(w)) { - re = re_1b_2; - w = w.replace(re, ""); - } - - // and turn initial Y back to y - - if (firstch == "y") { - w = firstch.toLowerCase() + w.substr(1); - } - - return w; - }; - - return function (token) { - return token.update(porterStemmer); - } - })(); - - lunr.Pipeline.registerFunction(lunr.stemmer, 'stemmer') - /*! - * lunr.stopWordFilter - * Copyright (C) 2020 Oliver Nightingale - */ - - /** - * lunr.generateStopWordFilter builds a stopWordFilter function from the provided - * list of stop words. - * - * The built in lunr.stopWordFilter is built using this generator and can be used - * to generate custom stopWordFilters for applications or non English languages. - * - * @function - * @param {Array} token The token to pass through the filter - * @returns {lunr.PipelineFunction} - * @see lunr.Pipeline - * @see lunr.stopWordFilter - */ - lunr.generateStopWordFilter = function (stopWords) { - var words = stopWords.reduce(function (memo, stopWord) { - memo[stopWord] = stopWord - return memo - }, {}) - - return function (token) { - if (token && words[token.toString()] !== token.toString()) return token - } - } - - /** - * lunr.stopWordFilter is an English language stop word list filter, any words - * contained in the list will not be passed through the filter. - * - * This is intended to be used in the Pipeline. If the token does not pass the - * filter then undefined will be returned. - * - * @function - * @implements {lunr.PipelineFunction} - * @params {lunr.Token} token - A token to check for being a stop word. - * @returns {lunr.Token} - * @see {@link lunr.Pipeline} - */ - lunr.stopWordFilter = lunr.generateStopWordFilter([ - 'a', - 'able', - 'about', - 'across', - 'after', - 'all', - 'almost', - 'also', - 'am', - 'among', - 'an', - 'and', - 'any', - 'are', - 'as', - 'at', - 'be', - 'because', - 'been', - 'but', - 'by', - 'can', - 'cannot', - 'could', - 'dear', - 'did', - 'do', - 'does', - 'either', - 'else', - 'ever', - 'every', - 'for', - 'from', - 'get', - 'got', - 'had', - 'has', - 'have', - 'he', - 'her', - 'hers', - 'him', - 'his', - 'how', - 'however', - 'i', - 'if', - 'in', - 'into', - 'is', - 'it', - 'its', - 'just', - 'least', - 'let', - 'like', - 'likely', - 'may', - 'me', - 'might', - 'most', - 'must', - 'my', - 'neither', - 'no', - 'nor', - 'not', - 'of', - 'off', - 'often', - 'on', - 'only', - 'or', - 'other', - 'our', - 'own', - 'rather', - 'said', - 'say', - 'says', - 'she', - 'should', - 'since', - 'so', - 'some', - 'than', - 'that', - 'the', - 'their', - 'them', - 'then', - 'there', - 'these', - 'they', - 'this', - 'tis', - 'to', - 'too', - 'twas', - 'us', - 'wants', - 'was', - 'we', - 'were', - 'what', - 'when', - 'where', - 'which', - 'while', - 'who', - 'whom', - 'why', - 'will', - 'with', - 'would', - 'yet', - 'you', - 'your' - ]) - - lunr.Pipeline.registerFunction(lunr.stopWordFilter, 'stopWordFilter') - /*! - * lunr.trimmer - * Copyright (C) 2020 Oliver Nightingale - */ - - /** - * lunr.trimmer is a pipeline function for trimming non word - * characters from the beginning and end of tokens before they - * enter the index. - * - * This implementation may not work correctly for non latin - * characters and should either be removed or adapted for use - * with languages with non-latin characters. - * - * @static - * @implements {lunr.PipelineFunction} - * @param {lunr.Token} token The token to pass through the filter - * @returns {lunr.Token} - * @see lunr.Pipeline - */ - lunr.trimmer = function (token) { - return token.update(function (s) { - return s.replace(/^\W+/, '').replace(/\W+$/, '') - }) - } - - lunr.Pipeline.registerFunction(lunr.trimmer, 'trimmer') - /*! - * lunr.TokenSet - * Copyright (C) 2020 Oliver Nightingale - */ - - /** - * A token set is used to store the unique list of all tokens - * within an index. Token sets are also used to represent an - * incoming query to the index, this query token set and index - * token set are then intersected to find which tokens to look - * up in the inverted index. - * - * A token set can hold multiple tokens, as in the case of the - * index token set, or it can hold a single token as in the - * case of a simple query token set. - * - * Additionally token sets are used to perform wildcard matching. - * Leading, contained and trailing wildcards are supported, and - * from this edit distance matching can also be provided. - * - * Token sets are implemented as a minimal finite state automata, - * where both common prefixes and suffixes are shared between tokens. - * This helps to reduce the space used for storing the token set. - * - * @constructor - */ - lunr.TokenSet = function () { - this.final = false - this.edges = {} - this.id = lunr.TokenSet._nextId - lunr.TokenSet._nextId += 1 - } - - /** - * Keeps track of the next, auto increment, identifier to assign - * to a new tokenSet. - * - * TokenSets require a unique identifier to be correctly minimised. - * - * @private - */ - lunr.TokenSet._nextId = 1 - - /** - * Creates a TokenSet instance from the given sorted array of words. - * - * @param {String[]} arr - A sorted array of strings to create the set from. - * @returns {lunr.TokenSet} - * @throws Will throw an error if the input array is not sorted. - */ - lunr.TokenSet.fromArray = function (arr) { - var builder = new lunr.TokenSet.Builder - - for (var i = 0, len = arr.length; i < len; i++) { - builder.insert(arr[i]) - } - - builder.finish() - return builder.root - } - - /** - * Creates a token set from a query clause. - * - * @private - * @param {Object} clause - A single clause from lunr.Query. - * @param {string} clause.term - The query clause term. - * @param {number} [clause.editDistance] - The optional edit distance for the term. - * @returns {lunr.TokenSet} - */ - lunr.TokenSet.fromClause = function (clause) { - if ('editDistance' in clause) { - return lunr.TokenSet.fromFuzzyString(clause.term, clause.editDistance) - } else { - return lunr.TokenSet.fromString(clause.term) - } - } - - /** - * Creates a token set representing a single string with a specified - * edit distance. - * - * Insertions, deletions, substitutions and transpositions are each - * treated as an edit distance of 1. - * - * Increasing the allowed edit distance will have a dramatic impact - * on the performance of both creating and intersecting these TokenSets. - * It is advised to keep the edit distance less than 3. - * - * @param {string} str - The string to create the token set from. - * @param {number} editDistance - The allowed edit distance to match. - * @returns {lunr.Vector} - */ - lunr.TokenSet.fromFuzzyString = function (str, editDistance) { - var root = new lunr.TokenSet - - var stack = [{ - node: root, - editsRemaining: editDistance, - str: str - }] - - while (stack.length) { - var frame = stack.pop() - - // no edit - if (frame.str.length > 0) { - var char = frame.str.charAt(0), - noEditNode - - if (char in frame.node.edges) { - noEditNode = frame.node.edges[char] - } else { - noEditNode = new lunr.TokenSet - frame.node.edges[char] = noEditNode - } - - if (frame.str.length == 1) { - noEditNode.final = true - } - - stack.push({ - node: noEditNode, - editsRemaining: frame.editsRemaining, - str: frame.str.slice(1) - }) - } - - if (frame.editsRemaining == 0) { - continue - } - - // insertion - if ("*" in frame.node.edges) { - var insertionNode = frame.node.edges["*"] - } else { - var insertionNode = new lunr.TokenSet - frame.node.edges["*"] = insertionNode - } - - if (frame.str.length == 0) { - insertionNode.final = true - } - - stack.push({ - node: insertionNode, - editsRemaining: frame.editsRemaining - 1, - str: frame.str - }) - - // deletion - // can only do a deletion if we have enough edits remaining - // and if there are characters left to delete in the string - if (frame.str.length > 1) { - stack.push({ - node: frame.node, - editsRemaining: frame.editsRemaining - 1, - str: frame.str.slice(1) - }) - } - - // deletion - // just removing the last character from the str - if (frame.str.length == 1) { - frame.node.final = true - } - - // substitution - // can only do a substitution if we have enough edits remaining - // and if there are characters left to substitute - if (frame.str.length >= 1) { - if ("*" in frame.node.edges) { - var substitutionNode = frame.node.edges["*"] - } else { - var substitutionNode = new lunr.TokenSet - frame.node.edges["*"] = substitutionNode - } - - if (frame.str.length == 1) { - substitutionNode.final = true - } - - stack.push({ - node: substitutionNode, - editsRemaining: frame.editsRemaining - 1, - str: frame.str.slice(1) - }) - } - - // transposition - // can only do a transposition if there are edits remaining - // and there are enough characters to transpose - if (frame.str.length > 1) { - var charA = frame.str.charAt(0), - charB = frame.str.charAt(1), - transposeNode - - if (charB in frame.node.edges) { - transposeNode = frame.node.edges[charB] - } else { - transposeNode = new lunr.TokenSet - frame.node.edges[charB] = transposeNode - } - - if (frame.str.length == 1) { - transposeNode.final = true - } - - stack.push({ - node: transposeNode, - editsRemaining: frame.editsRemaining - 1, - str: charA + frame.str.slice(2) - }) - } - } - - return root - } - - /** - * Creates a TokenSet from a string. - * - * The string may contain one or more wildcard characters (*) - * that will allow wildcard matching when intersecting with - * another TokenSet. - * - * @param {string} str - The string to create a TokenSet from. - * @returns {lunr.TokenSet} - */ - lunr.TokenSet.fromString = function (str) { - var node = new lunr.TokenSet, - root = node - - /* - * Iterates through all characters within the passed string - * appending a node for each character. - * - * When a wildcard character is found then a self - * referencing edge is introduced to continually match - * any number of any characters. - */ - for (var i = 0, len = str.length; i < len; i++) { - var char = str[i], - final = (i == len - 1) - - if (char == "*") { - node.edges[char] = node - node.final = final - - } else { - var next = new lunr.TokenSet - next.final = final - - node.edges[char] = next - node = next - } - } - - return root - } - - /** - * Converts this TokenSet into an array of strings - * contained within the TokenSet. - * - * This is not intended to be used on a TokenSet that - * contains wildcards, in these cases the results are - * undefined and are likely to cause an infinite loop. - * - * @returns {string[]} - */ - lunr.TokenSet.prototype.toArray = function () { - var words = [] - - var stack = [{ - prefix: "", - node: this - }] - - while (stack.length) { - var frame = stack.pop(), - edges = Object.keys(frame.node.edges), - len = edges.length - - if (frame.node.final) { - /* In Safari, at this point the prefix is sometimes corrupted, see: - * https://github.com/olivernn/lunr.js/issues/279 Calling any - * String.prototype method forces Safari to "cast" this string to what - * it's supposed to be, fixing the bug. */ - frame.prefix.charAt(0) - words.push(frame.prefix) - } - - for (var i = 0; i < len; i++) { - var edge = edges[i] - - stack.push({ - prefix: frame.prefix.concat(edge), - node: frame.node.edges[edge] - }) - } - } - - return words - } - - /** - * Generates a string representation of a TokenSet. - * - * This is intended to allow TokenSets to be used as keys - * in objects, largely to aid the construction and minimisation - * of a TokenSet. As such it is not designed to be a human - * friendly representation of the TokenSet. - * - * @returns {string} - */ - lunr.TokenSet.prototype.toString = function () { - // NOTE: Using Object.keys here as this.edges is very likely - // to enter 'hash-mode' with many keys being added - // - // avoiding a for-in loop here as it leads to the function - // being de-optimised (at least in V8). From some simple - // benchmarks the performance is comparable, but allowing - // V8 to optimize may mean easy performance wins in the future. - - if (this._str) { - return this._str - } - - var str = this.final ? '1' : '0', - labels = Object.keys(this.edges).sort(), - len = labels.length - - for (var i = 0; i < len; i++) { - var label = labels[i], - node = this.edges[label] - - str = str + label + node.id - } - - return str - } - - /** - * Returns a new TokenSet that is the intersection of - * this TokenSet and the passed TokenSet. - * - * This intersection will take into account any wildcards - * contained within the TokenSet. - * - * @param {lunr.TokenSet} b - An other TokenSet to intersect with. - * @returns {lunr.TokenSet} - */ - lunr.TokenSet.prototype.intersect = function (b) { - var output = new lunr.TokenSet, - frame = undefined - - var stack = [{ - qNode: b, - output: output, - node: this - }] - - while (stack.length) { - frame = stack.pop() - - // NOTE: As with the #toString method, we are using - // Object.keys and a for loop instead of a for-in loop - // as both of these objects enter 'hash' mode, causing - // the function to be de-optimised in V8 - var qEdges = Object.keys(frame.qNode.edges), - qLen = qEdges.length, - nEdges = Object.keys(frame.node.edges), - nLen = nEdges.length - - for (var q = 0; q < qLen; q++) { - var qEdge = qEdges[q] - - for (var n = 0; n < nLen; n++) { - var nEdge = nEdges[n] - - if (nEdge == qEdge || qEdge == '*') { - var node = frame.node.edges[nEdge], - qNode = frame.qNode.edges[qEdge], - final = node.final && qNode.final, - next = undefined - - if (nEdge in frame.output.edges) { - // an edge already exists for this character - // no need to create a new node, just set the finality - // bit unless this node is already final - next = frame.output.edges[nEdge] - next.final = next.final || final - - } else { - // no edge exists yet, must create one - // set the finality bit and insert it - // into the output - next = new lunr.TokenSet - next.final = final - frame.output.edges[nEdge] = next - } - - stack.push({ - qNode: qNode, - output: next, - node: node - }) - } - } - } - } - - return output - } - lunr.TokenSet.Builder = function () { - this.previousWord = "" - this.root = new lunr.TokenSet - this.uncheckedNodes = [] - this.minimizedNodes = {} - } - - lunr.TokenSet.Builder.prototype.insert = function (word) { - var node, - commonPrefix = 0 - - if (word < this.previousWord) { - throw new Error("Out of order word insertion") - } - - for (var i = 0; i < word.length && i < this.previousWord.length; i++) { - if (word[i] != this.previousWord[i]) break - commonPrefix++ - } - - this.minimize(commonPrefix) - - if (this.uncheckedNodes.length == 0) { - node = this.root - } else { - node = this.uncheckedNodes[this.uncheckedNodes.length - 1].child - } - - for (var i = commonPrefix; i < word.length; i++) { - var nextNode = new lunr.TokenSet, - char = word[i] - - node.edges[char] = nextNode - - this.uncheckedNodes.push({ - parent: node, - char: char, - child: nextNode - }) - - node = nextNode - } - - node.final = true - this.previousWord = word - } - - lunr.TokenSet.Builder.prototype.finish = function () { - this.minimize(0) - } - - lunr.TokenSet.Builder.prototype.minimize = function (downTo) { - for (var i = this.uncheckedNodes.length - 1; i >= downTo; i--) { - var node = this.uncheckedNodes[i], - childKey = node.child.toString() - - if (childKey in this.minimizedNodes) { - node.parent.edges[node.char] = this.minimizedNodes[childKey] - } else { - // Cache the key for this node since - // we know it can't change anymore - node.child._str = childKey - - this.minimizedNodes[childKey] = node.child - } - - this.uncheckedNodes.pop() - } - } - /*! - * lunr.Index - * Copyright (C) 2020 Oliver Nightingale - */ - - /** - * An index contains the built index of all documents and provides a query interface - * to the index. - * - * Usually instances of lunr.Index will not be created using this constructor, instead - * lunr.Builder should be used to construct new indexes, or lunr.Index.load should be - * used to load previously built and serialized indexes. - * - * @constructor - * @param {Object} attrs - The attributes of the built search index. - * @param {Object} attrs.invertedIndex - An index of term/field to document reference. - * @param {Object} attrs.fieldVectors - Field vectors - * @param {lunr.TokenSet} attrs.tokenSet - An set of all corpus tokens. - * @param {string[]} attrs.fields - The names of indexed document fields. - * @param {lunr.Pipeline} attrs.pipeline - The pipeline to use for search terms. - */ - lunr.Index = function (attrs) { - this.invertedIndex = attrs.invertedIndex - this.fieldVectors = attrs.fieldVectors - this.tokenSet = attrs.tokenSet - this.fields = attrs.fields - this.pipeline = attrs.pipeline - } - - /** - * A result contains details of a document matching a search query. - * @typedef {Object} lunr.Index~Result - * @property {string} ref - The reference of the document this result represents. - * @property {number} score - A number between 0 and 1 representing how similar this document is to the query. - * @property {lunr.MatchData} matchData - Contains metadata about this match including which term(s) caused the match. - */ - - /** - * Although lunr provides the ability to create queries using lunr.Query, it also provides a simple - * query language which itself is parsed into an instance of lunr.Query. - * - * For programmatically building queries it is advised to directly use lunr.Query, the query language - * is best used for human entered text rather than program generated text. - * - * At its simplest queries can just be a single term, e.g. `hello`, multiple terms are also supported - * and will be combined with OR, e.g `hello world` will match documents that contain either 'hello' - * or 'world', though those that contain both will rank higher in the results. - * - * Wildcards can be included in terms to match one or more unspecified characters, these wildcards can - * be inserted anywhere within the term, and more than one wildcard can exist in a single term. Adding - * wildcards will increase the number of documents that will be found but can also have a negative - * impact on query performance, especially with wildcards at the beginning of a term. - * - * Terms can be restricted to specific fields, e.g. `title:hello`, only documents with the term - * hello in the title field will match this query. Using a field not present in the index will lead - * to an error being thrown. - * - * Modifiers can also be added to terms, lunr supports edit distance and boost modifiers on terms. A term - * boost will make documents matching that term score higher, e.g. `foo^5`. Edit distance is also supported - * to provide fuzzy matching, e.g. 'hello~2' will match documents with hello with an edit distance of 2. - * Avoid large values for edit distance to improve query performance. - * - * Each term also supports a presence modifier. By default a term's presence in document is optional, however - * this can be changed to either required or prohibited. For a term's presence to be required in a document the - * term should be prefixed with a '+', e.g. `+foo bar` is a search for documents that must contain 'foo' and - * optionally contain 'bar'. Conversely a leading '-' sets the terms presence to prohibited, i.e. it must not - * appear in a document, e.g. `-foo bar` is a search for documents that do not contain 'foo' but may contain 'bar'. - * - * To escape special characters the backslash character '\' can be used, this allows searches to include - * characters that would normally be considered modifiers, e.g. `foo\~2` will search for a term "foo~2" instead - * of attempting to apply a boost of 2 to the search term "foo". - * - * @typedef {string} lunr.Index~QueryString - * @example Simple single term query - * hello - * @example Multiple term query - * hello world - * @example term scoped to a field - * title:hello - * @example term with a boost of 10 - * hello^10 - * @example term with an edit distance of 2 - * hello~2 - * @example terms with presence modifiers - * -foo +bar baz - */ - - /** - * Performs a search against the index using lunr query syntax. - * - * Results will be returned sorted by their score, the most relevant results - * will be returned first. For details on how the score is calculated, please see - * the {@link https://lunrjs.com/guides/searching.html#scoring|guide}. - * - * For more programmatic querying use lunr.Index#query. - * - * @param {lunr.Index~QueryString} queryString - A string containing a lunr query. - * @throws {lunr.QueryParseError} If the passed query string cannot be parsed. - * @returns {lunr.Index~Result[]} - */ - lunr.Index.prototype.search = function (queryString) { - return this.query(function (query) { - var parser = new lunr.QueryParser(queryString, query) - parser.parse() - }) - } - - /** - * A query builder callback provides a query object to be used to express - * the query to perform on the index. - * - * @callback lunr.Index~queryBuilder - * @param {lunr.Query} query - The query object to build up. - * @this lunr.Query - */ - - /** - * Performs a query against the index using the yielded lunr.Query object. - * - * If performing programmatic queries against the index, this method is preferred - * over lunr.Index#search so as to avoid the additional query parsing overhead. - * - * A query object is yielded to the supplied function which should be used to - * express the query to be run against the index. - * - * Note that although this function takes a callback parameter it is _not_ an - * asynchronous operation, the callback is just yielded a query object to be - * customized. - * - * @param {lunr.Index~queryBuilder} fn - A function that is used to build the query. - * @returns {lunr.Index~Result[]} - */ - lunr.Index.prototype.query = function (fn) { - // for each query clause - // * process terms - // * expand terms from token set - // * find matching documents and metadata - // * get document vectors - // * score documents - - var query = new lunr.Query(this.fields), - matchingFields = Object.create(null), - queryVectors = Object.create(null), - termFieldCache = Object.create(null), - requiredMatches = Object.create(null), - prohibitedMatches = Object.create(null) - - /* - * To support field level boosts a query vector is created per - * field. An empty vector is eagerly created to support negated - * queries. - */ - for (var i = 0; i < this.fields.length; i++) { - queryVectors[this.fields[i]] = new lunr.Vector - } - - fn.call(query, query) - - for (var i = 0; i < query.clauses.length; i++) { - /* - * Unless the pipeline has been disabled for this term, which is - * the case for terms with wildcards, we need to pass the clause - * term through the search pipeline. A pipeline returns an array - * of processed terms. Pipeline functions may expand the passed - * term, which means we may end up performing multiple index lookups - * for a single query term. - */ - var clause = query.clauses[i], - terms = null, - clauseMatches = lunr.Set.empty - - if (clause.usePipeline) { - terms = this.pipeline.runString(clause.term, { - fields: clause.fields - }) - } else { - terms = [clause.term] - } - - for (var m = 0; m < terms.length; m++) { - var term = terms[m] - - /* - * Each term returned from the pipeline needs to use the same query - * clause object, e.g. the same boost and or edit distance. The - * simplest way to do this is to re-use the clause object but mutate - * its term property. - */ - clause.term = term - - /* - * From the term in the clause we create a token set which will then - * be used to intersect the indexes token set to get a list of terms - * to lookup in the inverted index - */ - var termTokenSet = lunr.TokenSet.fromClause(clause), - expandedTerms = this.tokenSet.intersect(termTokenSet).toArray() - - /* - * If a term marked as required does not exist in the tokenSet it is - * impossible for the search to return any matches. We set all the field - * scoped required matches set to empty and stop examining any further - * clauses. - */ - if (expandedTerms.length === 0 && clause.presence === lunr.Query.presence.REQUIRED) { - for (var k = 0; k < clause.fields.length; k++) { - var field = clause.fields[k] - requiredMatches[field] = lunr.Set.empty - } - - break - } - - for (var j = 0; j < expandedTerms.length; j++) { - /* - * For each term get the posting and termIndex, this is required for - * building the query vector. - */ - var expandedTerm = expandedTerms[j], - posting = this.invertedIndex[expandedTerm], - termIndex = posting._index - - for (var k = 0; k < clause.fields.length; k++) { - /* - * For each field that this query term is scoped by (by default - * all fields are in scope) we need to get all the document refs - * that have this term in that field. - * - * The posting is the entry in the invertedIndex for the matching - * term from above. - */ - var field = clause.fields[k], - fieldPosting = posting[field], - matchingDocumentRefs = Object.keys(fieldPosting), - termField = expandedTerm + "/" + field, - matchingDocumentsSet = new lunr.Set(matchingDocumentRefs) - - /* - * if the presence of this term is required ensure that the matching - * documents are added to the set of required matches for this clause. - * - */ - if (clause.presence == lunr.Query.presence.REQUIRED) { - clauseMatches = clauseMatches.union(matchingDocumentsSet) - - if (requiredMatches[field] === undefined) { - requiredMatches[field] = lunr.Set.complete - } - } - - /* - * if the presence of this term is prohibited ensure that the matching - * documents are added to the set of prohibited matches for this field, - * creating that set if it does not yet exist. - */ - if (clause.presence == lunr.Query.presence.PROHIBITED) { - if (prohibitedMatches[field] === undefined) { - prohibitedMatches[field] = lunr.Set.empty - } - - prohibitedMatches[field] = prohibitedMatches[field].union(matchingDocumentsSet) - - /* - * Prohibited matches should not be part of the query vector used for - * similarity scoring and no metadata should be extracted so we continue - * to the next field - */ - continue - } - - /* - * The query field vector is populated using the termIndex found for - * the term and a unit value with the appropriate boost applied. - * Using upsert because there could already be an entry in the vector - * for the term we are working with. In that case we just add the scores - * together. - */ - queryVectors[field].upsert(termIndex, clause.boost, function (a, b) { return a + b }) - - /** - * If we've already seen this term, field combo then we've already collected - * the matching documents and metadata, no need to go through all that again - */ - if (termFieldCache[termField]) { - continue - } - - for (var l = 0; l < matchingDocumentRefs.length; l++) { - /* - * All metadata for this term/field/document triple - * are then extracted and collected into an instance - * of lunr.MatchData ready to be returned in the query - * results - */ - var matchingDocumentRef = matchingDocumentRefs[l], - matchingFieldRef = new lunr.FieldRef(matchingDocumentRef, field), - metadata = fieldPosting[matchingDocumentRef], - fieldMatch - - if ((fieldMatch = matchingFields[matchingFieldRef]) === undefined) { - matchingFields[matchingFieldRef] = new lunr.MatchData(expandedTerm, field, metadata) - } else { - fieldMatch.add(expandedTerm, field, metadata) - } - - } - - termFieldCache[termField] = true - } - } - } - - /** - * If the presence was required we need to update the requiredMatches field sets. - * We do this after all fields for the term have collected their matches because - * the clause terms presence is required in _any_ of the fields not _all_ of the - * fields. - */ - if (clause.presence === lunr.Query.presence.REQUIRED) { - for (var k = 0; k < clause.fields.length; k++) { - var field = clause.fields[k] - requiredMatches[field] = requiredMatches[field].intersect(clauseMatches) - } - } - } - - /** - * Need to combine the field scoped required and prohibited - * matching documents into a global set of required and prohibited - * matches - */ - var allRequiredMatches = lunr.Set.complete, - allProhibitedMatches = lunr.Set.empty - - for (var i = 0; i < this.fields.length; i++) { - var field = this.fields[i] - - if (requiredMatches[field]) { - allRequiredMatches = allRequiredMatches.intersect(requiredMatches[field]) - } - - if (prohibitedMatches[field]) { - allProhibitedMatches = allProhibitedMatches.union(prohibitedMatches[field]) - } - } - - var matchingFieldRefs = Object.keys(matchingFields), - results = [], - matches = Object.create(null) - - /* - * If the query is negated (contains only prohibited terms) - * we need to get _all_ fieldRefs currently existing in the - * index. This is only done when we know that the query is - * entirely prohibited terms to avoid any cost of getting all - * fieldRefs unnecessarily. - * - * Additionally, blank MatchData must be created to correctly - * populate the results. - */ - if (query.isNegated()) { - matchingFieldRefs = Object.keys(this.fieldVectors) - - for (var i = 0; i < matchingFieldRefs.length; i++) { - var matchingFieldRef = matchingFieldRefs[i] - var fieldRef = lunr.FieldRef.fromString(matchingFieldRef) - matchingFields[matchingFieldRef] = new lunr.MatchData - } - } - - for (var i = 0; i < matchingFieldRefs.length; i++) { - /* - * Currently we have document fields that match the query, but we - * need to return documents. The matchData and scores are combined - * from multiple fields belonging to the same document. - * - * Scores are calculated by field, using the query vectors created - * above, and combined into a final document score using addition. - */ - var fieldRef = lunr.FieldRef.fromString(matchingFieldRefs[i]), - docRef = fieldRef.docRef - - if (!allRequiredMatches.contains(docRef)) { - continue - } - - if (allProhibitedMatches.contains(docRef)) { - continue - } - - var fieldVector = this.fieldVectors[fieldRef], - score = queryVectors[fieldRef.fieldName].similarity(fieldVector), - docMatch - - if ((docMatch = matches[docRef]) !== undefined) { - docMatch.score += score - docMatch.matchData.combine(matchingFields[fieldRef]) - } else { - var match = { - ref: docRef, - score: score, - matchData: matchingFields[fieldRef] - } - matches[docRef] = match - results.push(match) - } - } - - /* - * Sort the results objects by score, highest first. - */ - return results.sort(function (a, b) { - return b.score - a.score - }) - } - - /** - * Prepares the index for JSON serialization. - * - * The schema for this JSON blob will be described in a - * separate JSON schema file. - * - * @returns {Object} - */ - lunr.Index.prototype.toJSON = function () { - var invertedIndex = Object.keys(this.invertedIndex) - .sort() - .map(function (term) { - return [term, this.invertedIndex[term]] - }, this) - - var fieldVectors = Object.keys(this.fieldVectors) - .map(function (ref) { - return [ref, this.fieldVectors[ref].toJSON()] - }, this) - - return { - version: lunr.version, - fields: this.fields, - fieldVectors: fieldVectors, - invertedIndex: invertedIndex, - pipeline: this.pipeline.toJSON() - } - } - - /** - * Loads a previously serialized lunr.Index - * - * @param {Object} serializedIndex - A previously serialized lunr.Index - * @returns {lunr.Index} - */ - lunr.Index.load = function (serializedIndex) { - var attrs = {}, - fieldVectors = {}, - serializedVectors = serializedIndex.fieldVectors, - invertedIndex = Object.create(null), - serializedInvertedIndex = serializedIndex.invertedIndex, - tokenSetBuilder = new lunr.TokenSet.Builder, - pipeline = lunr.Pipeline.load(serializedIndex.pipeline) - - if (serializedIndex.version != lunr.version) { - lunr.utils.warn("Version mismatch when loading serialised index. Current version of lunr '" + lunr.version + "' does not match serialized index '" + serializedIndex.version + "'") - } - - for (var i = 0; i < serializedVectors.length; i++) { - var tuple = serializedVectors[i], - ref = tuple[0], - elements = tuple[1] - - fieldVectors[ref] = new lunr.Vector(elements) - } - - for (var i = 0; i < serializedInvertedIndex.length; i++) { - var tuple = serializedInvertedIndex[i], - term = tuple[0], - posting = tuple[1] - - tokenSetBuilder.insert(term) - invertedIndex[term] = posting - } - - tokenSetBuilder.finish() - - attrs.fields = serializedIndex.fields - - attrs.fieldVectors = fieldVectors - attrs.invertedIndex = invertedIndex - attrs.tokenSet = tokenSetBuilder.root - attrs.pipeline = pipeline - - return new lunr.Index(attrs) - } - /*! - * lunr.Builder - * Copyright (C) 2020 Oliver Nightingale - */ - - /** - * lunr.Builder performs indexing on a set of documents and - * returns instances of lunr.Index ready for querying. - * - * All configuration of the index is done via the builder, the - * fields to index, the document reference, the text processing - * pipeline and document scoring parameters are all set on the - * builder before indexing. - * - * @constructor - * @property {string} _ref - Internal reference to the document reference field. - * @property {string[]} _fields - Internal reference to the document fields to index. - * @property {object} invertedIndex - The inverted index maps terms to document fields. - * @property {object} documentTermFrequencies - Keeps track of document term frequencies. - * @property {object} documentLengths - Keeps track of the length of documents added to the index. - * @property {lunr.tokenizer} tokenizer - Function for splitting strings into tokens for indexing. - * @property {lunr.Pipeline} pipeline - The pipeline performs text processing on tokens before indexing. - * @property {lunr.Pipeline} searchPipeline - A pipeline for processing search terms before querying the index. - * @property {number} documentCount - Keeps track of the total number of documents indexed. - * @property {number} _b - A parameter to control field length normalization, setting this to 0 disabled normalization, 1 fully normalizes field lengths, the default value is 0.75. - * @property {number} _k1 - A parameter to control how quickly an increase in term frequency results in term frequency saturation, the default value is 1.2. - * @property {number} termIndex - A counter incremented for each unique term, used to identify a terms position in the vector space. - * @property {array} metadataWhitelist - A list of metadata keys that have been whitelisted for entry in the index. - */ - lunr.Builder = function () { - this._ref = "id" - this._fields = Object.create(null) - this._documents = Object.create(null) - this.invertedIndex = Object.create(null) - this.fieldTermFrequencies = {} - this.fieldLengths = {} - this.tokenizer = lunr.tokenizer - this.pipeline = new lunr.Pipeline - this.searchPipeline = new lunr.Pipeline - this.documentCount = 0 - this._b = 0.75 - this._k1 = 1.2 - this.termIndex = 0 - this.metadataWhitelist = [] - } - - /** - * Sets the document field used as the document reference. Every document must have this field. - * The type of this field in the document should be a string, if it is not a string it will be - * coerced into a string by calling toString. - * - * The default ref is 'id'. - * - * The ref should _not_ be changed during indexing, it should be set before any documents are - * added to the index. Changing it during indexing can lead to inconsistent results. - * - * @param {string} ref - The name of the reference field in the document. - */ - lunr.Builder.prototype.ref = function (ref) { - this._ref = ref - } - - /** - * A function that is used to extract a field from a document. - * - * Lunr expects a field to be at the top level of a document, if however the field - * is deeply nested within a document an extractor function can be used to extract - * the right field for indexing. - * - * @callback fieldExtractor - * @param {object} doc - The document being added to the index. - * @returns {?(string|object|object[])} obj - The object that will be indexed for this field. - * @example Extracting a nested field - * function (doc) { return doc.nested.field } - */ - - /** - * Adds a field to the list of document fields that will be indexed. Every document being - * indexed should have this field. Null values for this field in indexed documents will - * not cause errors but will limit the chance of that document being retrieved by searches. - * - * All fields should be added before adding documents to the index. Adding fields after - * a document has been indexed will have no effect on already indexed documents. - * - * Fields can be boosted at build time. This allows terms within that field to have more - * importance when ranking search results. Use a field boost to specify that matches within - * one field are more important than other fields. - * - * @param {string} fieldName - The name of a field to index in all documents. - * @param {object} attributes - Optional attributes associated with this field. - * @param {number} [attributes.boost=1] - Boost applied to all terms within this field. - * @param {fieldExtractor} [attributes.extractor] - Function to extract a field from a document. - * @throws {RangeError} fieldName cannot contain unsupported characters '/' - */ - lunr.Builder.prototype.field = function (fieldName, attributes) { - if (/\//.test(fieldName)) { - throw new RangeError("Field '" + fieldName + "' contains illegal character '/'") - } - - this._fields[fieldName] = attributes || {} - } - - /** - * A parameter to tune the amount of field length normalisation that is applied when - * calculating relevance scores. A value of 0 will completely disable any normalisation - * and a value of 1 will fully normalise field lengths. The default is 0.75. Values of b - * will be clamped to the range 0 - 1. - * - * @param {number} number - The value to set for this tuning parameter. - */ - lunr.Builder.prototype.b = function (number) { - if (number < 0) { - this._b = 0 - } else if (number > 1) { - this._b = 1 - } else { - this._b = number - } - } - - /** - * A parameter that controls the speed at which a rise in term frequency results in term - * frequency saturation. The default value is 1.2. Setting this to a higher value will give - * slower saturation levels, a lower value will result in quicker saturation. - * - * @param {number} number - The value to set for this tuning parameter. - */ - lunr.Builder.prototype.k1 = function (number) { - this._k1 = number - } - - /** - * Adds a document to the index. - * - * Before adding fields to the index the index should have been fully setup, with the document - * ref and all fields to index already having been specified. - * - * The document must have a field name as specified by the ref (by default this is 'id') and - * it should have all fields defined for indexing, though null or undefined values will not - * cause errors. - * - * Entire documents can be boosted at build time. Applying a boost to a document indicates that - * this document should rank higher in search results than other documents. - * - * @param {object} doc - The document to add to the index. - * @param {object} attributes - Optional attributes associated with this document. - * @param {number} [attributes.boost=1] - Boost applied to all terms within this document. - */ - lunr.Builder.prototype.add = function (doc, attributes) { - var docRef = doc[this._ref], - fields = Object.keys(this._fields) - - this._documents[docRef] = attributes || {} - this.documentCount += 1 - - for (var i = 0; i < fields.length; i++) { - var fieldName = fields[i], - extractor = this._fields[fieldName].extractor, - field = extractor ? extractor(doc) : doc[fieldName], - tokens = this.tokenizer(field, { - fields: [fieldName] - }), - terms = this.pipeline.run(tokens), - fieldRef = new lunr.FieldRef(docRef, fieldName), - fieldTerms = Object.create(null) - - this.fieldTermFrequencies[fieldRef] = fieldTerms - this.fieldLengths[fieldRef] = 0 - - // store the length of this field for this document - this.fieldLengths[fieldRef] += terms.length - - // calculate term frequencies for this field - for (var j = 0; j < terms.length; j++) { - var term = terms[j] - - if (fieldTerms[term] == undefined) { - fieldTerms[term] = 0 - } - - fieldTerms[term] += 1 - - // add to inverted index - // create an initial posting if one doesn't exist - if (this.invertedIndex[term] == undefined) { - var posting = Object.create(null) - posting["_index"] = this.termIndex - this.termIndex += 1 - - for (var k = 0; k < fields.length; k++) { - posting[fields[k]] = Object.create(null) - } - - this.invertedIndex[term] = posting - } - - // add an entry for this term/fieldName/docRef to the invertedIndex - if (this.invertedIndex[term][fieldName][docRef] == undefined) { - this.invertedIndex[term][fieldName][docRef] = Object.create(null) - } - - // store all whitelisted metadata about this token in the - // inverted index - for (var l = 0; l < this.metadataWhitelist.length; l++) { - var metadataKey = this.metadataWhitelist[l], - metadata = term.metadata[metadataKey] - - if (this.invertedIndex[term][fieldName][docRef][metadataKey] == undefined) { - this.invertedIndex[term][fieldName][docRef][metadataKey] = [] - } - - this.invertedIndex[term][fieldName][docRef][metadataKey].push(metadata) - } - } - - } - } - - /** - * Calculates the average document length for this index - * - * @private - */ - lunr.Builder.prototype.calculateAverageFieldLengths = function () { - - var fieldRefs = Object.keys(this.fieldLengths), - numberOfFields = fieldRefs.length, - accumulator = {}, - documentsWithField = {} - - for (var i = 0; i < numberOfFields; i++) { - var fieldRef = lunr.FieldRef.fromString(fieldRefs[i]), - field = fieldRef.fieldName - - documentsWithField[field] || (documentsWithField[field] = 0) - documentsWithField[field] += 1 - - accumulator[field] || (accumulator[field] = 0) - accumulator[field] += this.fieldLengths[fieldRef] - } - - var fields = Object.keys(this._fields) - - for (var i = 0; i < fields.length; i++) { - var fieldName = fields[i] - accumulator[fieldName] = accumulator[fieldName] / documentsWithField[fieldName] - } - - this.averageFieldLength = accumulator - } - - /** - * Builds a vector space model of every document using lunr.Vector - * - * @private - */ - lunr.Builder.prototype.createFieldVectors = function () { - var fieldVectors = {}, - fieldRefs = Object.keys(this.fieldTermFrequencies), - fieldRefsLength = fieldRefs.length, - termIdfCache = Object.create(null) - - for (var i = 0; i < fieldRefsLength; i++) { - var fieldRef = lunr.FieldRef.fromString(fieldRefs[i]), - fieldName = fieldRef.fieldName, - fieldLength = this.fieldLengths[fieldRef], - fieldVector = new lunr.Vector, - termFrequencies = this.fieldTermFrequencies[fieldRef], - terms = Object.keys(termFrequencies), - termsLength = terms.length - - - var fieldBoost = this._fields[fieldName].boost || 1, - docBoost = this._documents[fieldRef.docRef].boost || 1 - - for (var j = 0; j < termsLength; j++) { - var term = terms[j], - tf = termFrequencies[term], - termIndex = this.invertedIndex[term]._index, - idf, score, scoreWithPrecision - - if (termIdfCache[term] === undefined) { - idf = lunr.idf(this.invertedIndex[term], this.documentCount) - termIdfCache[term] = idf - } else { - idf = termIdfCache[term] - } - - score = idf * ((this._k1 + 1) * tf) / (this._k1 * (1 - this._b + this._b * (fieldLength / this.averageFieldLength[fieldName])) + tf) - score *= fieldBoost - score *= docBoost - scoreWithPrecision = Math.round(score * 1000) / 1000 - // Converts 1.23456789 to 1.234. - // Reducing the precision so that the vectors take up less - // space when serialised. Doing it now so that they behave - // the same before and after serialisation. Also, this is - // the fastest approach to reducing a number's precision in - // JavaScript. - - fieldVector.insert(termIndex, scoreWithPrecision) - } - - fieldVectors[fieldRef] = fieldVector - } - - this.fieldVectors = fieldVectors - } - - /** - * Creates a token set of all tokens in the index using lunr.TokenSet - * - * @private - */ - lunr.Builder.prototype.createTokenSet = function () { - this.tokenSet = lunr.TokenSet.fromArray( - Object.keys(this.invertedIndex).sort() - ) - } - - /** - * Builds the index, creating an instance of lunr.Index. - * - * This completes the indexing process and should only be called - * once all documents have been added to the index. - * - * @returns {lunr.Index} - */ - lunr.Builder.prototype.build = function () { - this.calculateAverageFieldLengths() - this.createFieldVectors() - this.createTokenSet() - - return new lunr.Index({ - invertedIndex: this.invertedIndex, - fieldVectors: this.fieldVectors, - tokenSet: this.tokenSet, - fields: Object.keys(this._fields), - pipeline: this.searchPipeline - }) - } - - /** - * Applies a plugin to the index builder. - * - * A plugin is a function that is called with the index builder as its context. - * Plugins can be used to customise or extend the behaviour of the index - * in some way. A plugin is just a function, that encapsulated the custom - * behaviour that should be applied when building the index. - * - * The plugin function will be called with the index builder as its argument, additional - * arguments can also be passed when calling use. The function will be called - * with the index builder as its context. - * - * @param {Function} plugin The plugin to apply. - */ - lunr.Builder.prototype.use = function (fn) { - var args = Array.prototype.slice.call(arguments, 1) - args.unshift(this) - fn.apply(this, args) - } - /** - * Contains and collects metadata about a matching document. - * A single instance of lunr.MatchData is returned as part of every - * lunr.Index~Result. - * - * @constructor - * @param {string} term - The term this match data is associated with - * @param {string} field - The field in which the term was found - * @param {object} metadata - The metadata recorded about this term in this field - * @property {object} metadata - A cloned collection of metadata associated with this document. - * @see {@link lunr.Index~Result} - */ - lunr.MatchData = function (term, field, metadata) { - var clonedMetadata = Object.create(null), - metadataKeys = Object.keys(metadata || {}) - - // Cloning the metadata to prevent the original - // being mutated during match data combination. - // Metadata is kept in an array within the inverted - // index so cloning the data can be done with - // Array#slice - for (var i = 0; i < metadataKeys.length; i++) { - var key = metadataKeys[i] - clonedMetadata[key] = metadata[key].slice() - } - - this.metadata = Object.create(null) - - if (term !== undefined) { - this.metadata[term] = Object.create(null) - this.metadata[term][field] = clonedMetadata - } - } - - /** - * An instance of lunr.MatchData will be created for every term that matches a - * document. However only one instance is required in a lunr.Index~Result. This - * method combines metadata from another instance of lunr.MatchData with this - * objects metadata. - * - * @param {lunr.MatchData} otherMatchData - Another instance of match data to merge with this one. - * @see {@link lunr.Index~Result} - */ - lunr.MatchData.prototype.combine = function (otherMatchData) { - var terms = Object.keys(otherMatchData.metadata) - - for (var i = 0; i < terms.length; i++) { - var term = terms[i], - fields = Object.keys(otherMatchData.metadata[term]) - - if (this.metadata[term] == undefined) { - this.metadata[term] = Object.create(null) - } - - for (var j = 0; j < fields.length; j++) { - var field = fields[j], - keys = Object.keys(otherMatchData.metadata[term][field]) - - if (this.metadata[term][field] == undefined) { - this.metadata[term][field] = Object.create(null) - } - - for (var k = 0; k < keys.length; k++) { - var key = keys[k] - - if (this.metadata[term][field][key] == undefined) { - this.metadata[term][field][key] = otherMatchData.metadata[term][field][key] - } else { - this.metadata[term][field][key] = this.metadata[term][field][key].concat(otherMatchData.metadata[term][field][key]) - } - - } - } - } - } - - /** - * Add metadata for a term/field pair to this instance of match data. - * - * @param {string} term - The term this match data is associated with - * @param {string} field - The field in which the term was found - * @param {object} metadata - The metadata recorded about this term in this field - */ - lunr.MatchData.prototype.add = function (term, field, metadata) { - if (!(term in this.metadata)) { - this.metadata[term] = Object.create(null) - this.metadata[term][field] = metadata - return - } - - if (!(field in this.metadata[term])) { - this.metadata[term][field] = metadata - return - } - - var metadataKeys = Object.keys(metadata) - - for (var i = 0; i < metadataKeys.length; i++) { - var key = metadataKeys[i] - - if (key in this.metadata[term][field]) { - this.metadata[term][field][key] = this.metadata[term][field][key].concat(metadata[key]) - } else { - this.metadata[term][field][key] = metadata[key] - } - } - } - /** - * A lunr.Query provides a programmatic way of defining queries to be performed - * against a {@link lunr.Index}. - * - * Prefer constructing a lunr.Query using the {@link lunr.Index#query} method - * so the query object is pre-initialized with the right index fields. - * - * @constructor - * @property {lunr.Query~Clause[]} clauses - An array of query clauses. - * @property {string[]} allFields - An array of all available fields in a lunr.Index. - */ - lunr.Query = function (allFields) { - this.clauses = [] - this.allFields = allFields - } - - /** - * Constants for indicating what kind of automatic wildcard insertion will be used when constructing a query clause. - * - * This allows wildcards to be added to the beginning and end of a term without having to manually do any string - * concatenation. - * - * The wildcard constants can be bitwise combined to select both leading and trailing wildcards. - * - * @constant - * @default - * @property {number} wildcard.NONE - The term will have no wildcards inserted, this is the default behaviour - * @property {number} wildcard.LEADING - Prepend the term with a wildcard, unless a leading wildcard already exists - * @property {number} wildcard.TRAILING - Append a wildcard to the term, unless a trailing wildcard already exists - * @see lunr.Query~Clause - * @see lunr.Query#clause - * @see lunr.Query#term - * @example query term with trailing wildcard - * query.term('foo', { wildcard: lunr.Query.wildcard.TRAILING }) - * @example query term with leading and trailing wildcard - * query.term('foo', { - * wildcard: lunr.Query.wildcard.LEADING | lunr.Query.wildcard.TRAILING - * }) - */ - - lunr.Query.wildcard = new String("*") - lunr.Query.wildcard.NONE = 0 - lunr.Query.wildcard.LEADING = 1 - lunr.Query.wildcard.TRAILING = 2 - - /** - * Constants for indicating what kind of presence a term must have in matching documents. - * - * @constant - * @enum {number} - * @see lunr.Query~Clause - * @see lunr.Query#clause - * @see lunr.Query#term - * @example query term with required presence - * query.term('foo', { presence: lunr.Query.presence.REQUIRED }) - */ - lunr.Query.presence = { - /** - * Term's presence in a document is optional, this is the default value. - */ - OPTIONAL: 1, - - /** - * Term's presence in a document is required, documents that do not contain - * this term will not be returned. - */ - REQUIRED: 2, - - /** - * Term's presence in a document is prohibited, documents that do contain - * this term will not be returned. - */ - PROHIBITED: 3 - } - - /** - * A single clause in a {@link lunr.Query} contains a term and details on how to - * match that term against a {@link lunr.Index}. - * - * @typedef {Object} lunr.Query~Clause - * @property {string[]} fields - The fields in an index this clause should be matched against. - * @property {number} [boost=1] - Any boost that should be applied when matching this clause. - * @property {number} [editDistance] - Whether the term should have fuzzy matching applied, and how fuzzy the match should be. - * @property {boolean} [usePipeline] - Whether the term should be passed through the search pipeline. - * @property {number} [wildcard=lunr.Query.wildcard.NONE] - Whether the term should have wildcards appended or prepended. - * @property {number} [presence=lunr.Query.presence.OPTIONAL] - The terms presence in any matching documents. - */ - - /** - * Adds a {@link lunr.Query~Clause} to this query. - * - * Unless the clause contains the fields to be matched all fields will be matched. In addition - * a default boost of 1 is applied to the clause. - * - * @param {lunr.Query~Clause} clause - The clause to add to this query. - * @see lunr.Query~Clause - * @returns {lunr.Query} - */ - lunr.Query.prototype.clause = function (clause) { - if (!('fields' in clause)) { - clause.fields = this.allFields - } - - if (!('boost' in clause)) { - clause.boost = 1 - } - - if (!('usePipeline' in clause)) { - clause.usePipeline = true - } - - if (!('wildcard' in clause)) { - clause.wildcard = lunr.Query.wildcard.NONE - } - - if ((clause.wildcard & lunr.Query.wildcard.LEADING) && (clause.term.charAt(0) != lunr.Query.wildcard)) { - clause.term = "*" + clause.term - } - - if ((clause.wildcard & lunr.Query.wildcard.TRAILING) && (clause.term.slice(-1) != lunr.Query.wildcard)) { - clause.term = "" + clause.term + "*" - } - - if (!('presence' in clause)) { - clause.presence = lunr.Query.presence.OPTIONAL - } - - this.clauses.push(clause) - - return this - } - - /** - * A negated query is one in which every clause has a presence of - * prohibited. These queries require some special processing to return - * the expected results. - * - * @returns boolean - */ - lunr.Query.prototype.isNegated = function () { - for (var i = 0; i < this.clauses.length; i++) { - if (this.clauses[i].presence != lunr.Query.presence.PROHIBITED) { - return false - } - } - - return true - } - - /** - * Adds a term to the current query, under the covers this will create a {@link lunr.Query~Clause} - * to the list of clauses that make up this query. - * - * The term is used as is, i.e. no tokenization will be performed by this method. Instead conversion - * to a token or token-like string should be done before calling this method. - * - * The term will be converted to a string by calling `toString`. Multiple terms can be passed as an - * array, each term in the array will share the same options. - * - * @param {object|object[]} term - The term(s) to add to the query. - * @param {object} [options] - Any additional properties to add to the query clause. - * @returns {lunr.Query} - * @see lunr.Query#clause - * @see lunr.Query~Clause - * @example adding a single term to a query - * query.term("foo") - * @example adding a single term to a query and specifying search fields, term boost and automatic trailing wildcard - * query.term("foo", { - * fields: ["title"], - * boost: 10, - * wildcard: lunr.Query.wildcard.TRAILING - * }) - * @example using lunr.tokenizer to convert a string to tokens before using them as terms - * query.term(lunr.tokenizer("foo bar")) - */ - lunr.Query.prototype.term = function (term, options) { - if (Array.isArray(term)) { - term.forEach(function (t) { this.term(t, lunr.utils.clone(options)) }, this) - return this - } - - var clause = options || {} - clause.term = term.toString() - - this.clause(clause) - - return this - } - lunr.QueryParseError = function (message, start, end) { - this.name = "QueryParseError" - this.message = message - this.start = start - this.end = end - } - - lunr.QueryParseError.prototype = new Error - lunr.QueryLexer = function (str) { - this.lexemes = [] - this.str = str - this.length = str.length - this.pos = 0 - this.start = 0 - this.escapeCharPositions = [] - } - - lunr.QueryLexer.prototype.run = function () { - var state = lunr.QueryLexer.lexText - - while (state) { - state = state(this) - } - } - - lunr.QueryLexer.prototype.sliceString = function () { - var subSlices = [], - sliceStart = this.start, - sliceEnd = this.pos - - for (var i = 0; i < this.escapeCharPositions.length; i++) { - sliceEnd = this.escapeCharPositions[i] - subSlices.push(this.str.slice(sliceStart, sliceEnd)) - sliceStart = sliceEnd + 1 - } - - subSlices.push(this.str.slice(sliceStart, this.pos)) - this.escapeCharPositions.length = 0 - - return subSlices.join('') - } - - lunr.QueryLexer.prototype.emit = function (type) { - this.lexemes.push({ - type: type, - str: this.sliceString(), - start: this.start, - end: this.pos - }) - - this.start = this.pos - } - - lunr.QueryLexer.prototype.escapeCharacter = function () { - this.escapeCharPositions.push(this.pos - 1) - this.pos += 1 - } - - lunr.QueryLexer.prototype.next = function () { - if (this.pos >= this.length) { - return lunr.QueryLexer.EOS - } - - var char = this.str.charAt(this.pos) - this.pos += 1 - return char - } - - lunr.QueryLexer.prototype.width = function () { - return this.pos - this.start - } - - lunr.QueryLexer.prototype.ignore = function () { - if (this.start == this.pos) { - this.pos += 1 - } - - this.start = this.pos - } - - lunr.QueryLexer.prototype.backup = function () { - this.pos -= 1 - } - - lunr.QueryLexer.prototype.acceptDigitRun = function () { - var char, charCode - - do { - char = this.next() - charCode = char.charCodeAt(0) - } while (charCode > 47 && charCode < 58) - - if (char != lunr.QueryLexer.EOS) { - this.backup() - } - } - - lunr.QueryLexer.prototype.more = function () { - return this.pos < this.length - } - - lunr.QueryLexer.EOS = 'EOS' - lunr.QueryLexer.FIELD = 'FIELD' - lunr.QueryLexer.TERM = 'TERM' - lunr.QueryLexer.EDIT_DISTANCE = 'EDIT_DISTANCE' - lunr.QueryLexer.BOOST = 'BOOST' - lunr.QueryLexer.PRESENCE = 'PRESENCE' - - lunr.QueryLexer.lexField = function (lexer) { - lexer.backup() - lexer.emit(lunr.QueryLexer.FIELD) - lexer.ignore() - return lunr.QueryLexer.lexText - } - - lunr.QueryLexer.lexTerm = function (lexer) { - if (lexer.width() > 1) { - lexer.backup() - lexer.emit(lunr.QueryLexer.TERM) - } - - lexer.ignore() - - if (lexer.more()) { - return lunr.QueryLexer.lexText - } - } - - lunr.QueryLexer.lexEditDistance = function (lexer) { - lexer.ignore() - lexer.acceptDigitRun() - lexer.emit(lunr.QueryLexer.EDIT_DISTANCE) - return lunr.QueryLexer.lexText - } - - lunr.QueryLexer.lexBoost = function (lexer) { - lexer.ignore() - lexer.acceptDigitRun() - lexer.emit(lunr.QueryLexer.BOOST) - return lunr.QueryLexer.lexText - } - - lunr.QueryLexer.lexEOS = function (lexer) { - if (lexer.width() > 0) { - lexer.emit(lunr.QueryLexer.TERM) - } - } - - // This matches the separator used when tokenising fields - // within a document. These should match otherwise it is - // not possible to search for some tokens within a document. - // - // It is possible for the user to change the separator on the - // tokenizer so it _might_ clash with any other of the special - // characters already used within the search string, e.g. :. - // - // This means that it is possible to change the separator in - // such a way that makes some words unsearchable using a search - // string. - lunr.QueryLexer.termSeparator = lunr.tokenizer.separator - - lunr.QueryLexer.lexText = function (lexer) { - while (true) { - var char = lexer.next() - - if (char == lunr.QueryLexer.EOS) { - return lunr.QueryLexer.lexEOS - } - - // Escape character is '\' - if (char.charCodeAt(0) == 92) { - lexer.escapeCharacter() - continue - } - - if (char == ":") { - return lunr.QueryLexer.lexField - } - - if (char == "~") { - lexer.backup() - if (lexer.width() > 0) { - lexer.emit(lunr.QueryLexer.TERM) - } - return lunr.QueryLexer.lexEditDistance - } - - if (char == "^") { - lexer.backup() - if (lexer.width() > 0) { - lexer.emit(lunr.QueryLexer.TERM) - } - return lunr.QueryLexer.lexBoost - } - - // "+" indicates term presence is required - // checking for length to ensure that only - // leading "+" are considered - if (char == "+" && lexer.width() === 1) { - lexer.emit(lunr.QueryLexer.PRESENCE) - return lunr.QueryLexer.lexText - } - - // "-" indicates term presence is prohibited - // checking for length to ensure that only - // leading "-" are considered - if (char == "-" && lexer.width() === 1) { - lexer.emit(lunr.QueryLexer.PRESENCE) - return lunr.QueryLexer.lexText - } - - if (char.match(lunr.QueryLexer.termSeparator)) { - return lunr.QueryLexer.lexTerm - } - } - } - - lunr.QueryParser = function (str, query) { - this.lexer = new lunr.QueryLexer(str) - this.query = query - this.currentClause = {} - this.lexemeIdx = 0 - } - - lunr.QueryParser.prototype.parse = function () { - this.lexer.run() - this.lexemes = this.lexer.lexemes - - var state = lunr.QueryParser.parseClause - - while (state) { - state = state(this) - } - - return this.query - } - - lunr.QueryParser.prototype.peekLexeme = function () { - return this.lexemes[this.lexemeIdx] - } - - lunr.QueryParser.prototype.consumeLexeme = function () { - var lexeme = this.peekLexeme() - this.lexemeIdx += 1 - return lexeme - } - - lunr.QueryParser.prototype.nextClause = function () { - var completedClause = this.currentClause - this.query.clause(completedClause) - this.currentClause = {} - } - - lunr.QueryParser.parseClause = function (parser) { - var lexeme = parser.peekLexeme() - - if (lexeme == undefined) { - return - } - - switch (lexeme.type) { - case lunr.QueryLexer.PRESENCE: - return lunr.QueryParser.parsePresence - case lunr.QueryLexer.FIELD: - return lunr.QueryParser.parseField - case lunr.QueryLexer.TERM: - return lunr.QueryParser.parseTerm - default: - var errorMessage = "expected either a field or a term, found " + lexeme.type - - if (lexeme.str.length >= 1) { - errorMessage += " with value '" + lexeme.str + "'" - } - - throw new lunr.QueryParseError(errorMessage, lexeme.start, lexeme.end) - } - } - - lunr.QueryParser.parsePresence = function (parser) { - var lexeme = parser.consumeLexeme() - - if (lexeme == undefined) { - return - } - - switch (lexeme.str) { - case "-": - parser.currentClause.presence = lunr.Query.presence.PROHIBITED - break - case "+": - parser.currentClause.presence = lunr.Query.presence.REQUIRED - break - default: - var errorMessage = "unrecognised presence operator'" + lexeme.str + "'" - throw new lunr.QueryParseError(errorMessage, lexeme.start, lexeme.end) - } - - var nextLexeme = parser.peekLexeme() - - if (nextLexeme == undefined) { - var errorMessage = "expecting term or field, found nothing" - throw new lunr.QueryParseError(errorMessage, lexeme.start, lexeme.end) - } - - switch (nextLexeme.type) { - case lunr.QueryLexer.FIELD: - return lunr.QueryParser.parseField - case lunr.QueryLexer.TERM: - return lunr.QueryParser.parseTerm - default: - var errorMessage = "expecting term or field, found '" + nextLexeme.type + "'" - throw new lunr.QueryParseError(errorMessage, nextLexeme.start, nextLexeme.end) - } - } - - lunr.QueryParser.parseField = function (parser) { - var lexeme = parser.consumeLexeme() - - if (lexeme == undefined) { - return - } - - if (parser.query.allFields.indexOf(lexeme.str) == -1) { - var possibleFields = parser.query.allFields.map(function (f) { return "'" + f + "'" }).join(', '), - errorMessage = "unrecognised field '" + lexeme.str + "', possible fields: " + possibleFields - - throw new lunr.QueryParseError(errorMessage, lexeme.start, lexeme.end) - } - - parser.currentClause.fields = [lexeme.str] - - var nextLexeme = parser.peekLexeme() - - if (nextLexeme == undefined) { - var errorMessage = "expecting term, found nothing" - throw new lunr.QueryParseError(errorMessage, lexeme.start, lexeme.end) - } - - switch (nextLexeme.type) { - case lunr.QueryLexer.TERM: - return lunr.QueryParser.parseTerm - default: - var errorMessage = "expecting term, found '" + nextLexeme.type + "'" - throw new lunr.QueryParseError(errorMessage, nextLexeme.start, nextLexeme.end) - } - } - - lunr.QueryParser.parseTerm = function (parser) { - var lexeme = parser.consumeLexeme() - - if (lexeme == undefined) { - return - } - - parser.currentClause.term = lexeme.str.toLowerCase() - - if (lexeme.str.indexOf("*") != -1) { - parser.currentClause.usePipeline = false - } - - var nextLexeme = parser.peekLexeme() - - if (nextLexeme == undefined) { - parser.nextClause() - return - } - - switch (nextLexeme.type) { - case lunr.QueryLexer.TERM: - parser.nextClause() - return lunr.QueryParser.parseTerm - case lunr.QueryLexer.FIELD: - parser.nextClause() - return lunr.QueryParser.parseField - case lunr.QueryLexer.EDIT_DISTANCE: - return lunr.QueryParser.parseEditDistance - case lunr.QueryLexer.BOOST: - return lunr.QueryParser.parseBoost - case lunr.QueryLexer.PRESENCE: - parser.nextClause() - return lunr.QueryParser.parsePresence - default: - var errorMessage = "Unexpected lexeme type '" + nextLexeme.type + "'" - throw new lunr.QueryParseError(errorMessage, nextLexeme.start, nextLexeme.end) - } - } - - lunr.QueryParser.parseEditDistance = function (parser) { - var lexeme = parser.consumeLexeme() - - if (lexeme == undefined) { - return - } - - var editDistance = parseInt(lexeme.str, 10) - - if (isNaN(editDistance)) { - var errorMessage = "edit distance must be numeric" - throw new lunr.QueryParseError(errorMessage, lexeme.start, lexeme.end) - } - - parser.currentClause.editDistance = editDistance - - var nextLexeme = parser.peekLexeme() - - if (nextLexeme == undefined) { - parser.nextClause() - return - } - - switch (nextLexeme.type) { - case lunr.QueryLexer.TERM: - parser.nextClause() - return lunr.QueryParser.parseTerm - case lunr.QueryLexer.FIELD: - parser.nextClause() - return lunr.QueryParser.parseField - case lunr.QueryLexer.EDIT_DISTANCE: - return lunr.QueryParser.parseEditDistance - case lunr.QueryLexer.BOOST: - return lunr.QueryParser.parseBoost - case lunr.QueryLexer.PRESENCE: - parser.nextClause() - return lunr.QueryParser.parsePresence - default: - var errorMessage = "Unexpected lexeme type '" + nextLexeme.type + "'" - throw new lunr.QueryParseError(errorMessage, nextLexeme.start, nextLexeme.end) - } - } - - lunr.QueryParser.parseBoost = function (parser) { - var lexeme = parser.consumeLexeme() - - if (lexeme == undefined) { - return - } - - var boost = parseInt(lexeme.str, 10) - - if (isNaN(boost)) { - var errorMessage = "boost must be numeric" - throw new lunr.QueryParseError(errorMessage, lexeme.start, lexeme.end) - } - - parser.currentClause.boost = boost - - var nextLexeme = parser.peekLexeme() - - if (nextLexeme == undefined) { - parser.nextClause() - return - } - - switch (nextLexeme.type) { - case lunr.QueryLexer.TERM: - parser.nextClause() - return lunr.QueryParser.parseTerm - case lunr.QueryLexer.FIELD: - parser.nextClause() - return lunr.QueryParser.parseField - case lunr.QueryLexer.EDIT_DISTANCE: - return lunr.QueryParser.parseEditDistance - case lunr.QueryLexer.BOOST: - return lunr.QueryParser.parseBoost - case lunr.QueryLexer.PRESENCE: - parser.nextClause() - return lunr.QueryParser.parsePresence - default: - var errorMessage = "Unexpected lexeme type '" + nextLexeme.type + "'" - throw new lunr.QueryParseError(errorMessage, nextLexeme.start, nextLexeme.end) - } - } - - /** - * export the module via AMD, CommonJS or as a browser global - * Export code from https://github.com/umdjs/umd/blob/master/returnExports.js - */ - ; (function (root, factory) { - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - define(factory) - } else if (typeof exports === 'object') { - /** - * Node. Does not work with strict CommonJS, but - * only CommonJS-like enviroments that support module.exports, - * like Node. - */ - module.exports = factory() - } else { - // Browser globals (root is window) - root.lunr = factory() - } - }(this, function () { - /** - * Just return a value to define the module export. - * This example returns an object, but the module - * can return a function as the exported value. - */ - return lunr - })) -})(); diff --git a/operator/config-api.html b/operator/config-api.html deleted file mode 100644 index 7a9bc2b37..000000000 --- a/operator/config-api.html +++ /dev/null @@ -1,792 +0,0 @@ -VinylDNS: API Configuration Guide

API Configuration Guide

- -

Note: ALL configuration assumes a vinyldns namespace. For example, sqs settings would be under vinyldns.sqs.

- -

Configuration

- - - -

There are a lot of configuration settings in VinylDNS. So much so that it may seem overwhelming to configure vinyldns to -your environment. This document describes the configuration settings, highlighting the settings you are most likely to -change. All of the configuration settings are captured at the end.

- -

It is important to note that the api and portal have different configuration. We will review the configuration for -each separately.

- -

Configuration Overview

- -

How do we config?

- -

All configuration is done using Typesafe Config. It provides a means to -specifying default configurations, and overriding the configured values in a number of ways:

- -
    -
  1. The default configuration provides “safe” default values for all configuration. This makes it possible for you to -only change the configuration values that you need to, and assume the default for the rest. This can typically be -found in a file named reference.conf. The Typesafe Config library manages populating unspecified values for you -automatically.
  2. -
  3. You can override the reference.conf file by providing your own application.conf file when the system starts up. -We will review how to do that in the sections that follow.
  4. -
  5. You can override individual configuration properties when the application starts up using standard jvm arguments. -For example, you can specify -Dmy.config.value=42, and that will override both application.conf and -reference.conf (defaults)
  6. -
  7. You can further override configuration properties with environment variables. The Typesafe Config provides special -syntax that allows you to use environment variables. You can make the environment variable optional (meaning use it -if it is there) -or required (fail to start up without the environment variable). We will illustrate use of environment variables in -this guide.
  8. -
- -

Using Environment Variables

- -

We strongly recommend that you use environment variables in particular for secrets. Laying down environment variables -in a flat file is a security vulnerability for your installation. To demonstrate environment variable usage, here is a -following snippet…

- -
  queue.settings {
-     access-key = ${AWS_ACCESS_KEY}
-     secret-key = ${AWS_SECRET_ACCESS_KEY}
-     signing-region = ${SQS_REGION}
-     service-endpoint = ${SQS_SERVICE_ENDPOINT}
-     queue-name = ${SQS_QUEUE_NAME}
-  }
-
- -

In the example, if any of the values in ${xxx} are not found in the environment, the application will not start up!

- -

Configuring API Server

- -

The API configuration has a lot of values, the important ones reviewed here. There are several configuration settings -that are specific to your environment.

- -

The most important configuration is around your system dependencies. Presently, these are your settings for:

- -
    -
  • AWS SQS
  • -
  • MySQL
  • -
- -

Queue Configuration

- -

VinylDNS supports both SQS and MySQL queue implementations.

- -

There are a couple of implementation-dependent settings that need to be specified:

- -
    -
  • messages-per-poll: Number of messages retrieved in a single queue receive request. Valid values are 1 through 10 ( -default).
  • -
  • polling-interval: Interval to delay between each poll for messages.
  • -
- -

If using SQS, be sure to follow the AWS SQS Setup Guide first to get the values you need to configure -here.

- -

If using MySQL, follow the MySQL Setup Guide first to get the values you need to configure here.

- -

The following in a sample SQS config:

- -
vinyldns {
-
-  queue {
-     class-name = "vinyldns.sqs.queue.SqsMessageQueueProvider"
-   
-     messages-per-poll = 10
-     polling-interval = 250.millis
-   
-     # connection information to SQS
-     settings {
-        # AWS access key and secret.
-        access-key = "x"
-        secret-key = "x"
-      
-        # Regional endpoint to make your requests (eg. 'us-west-2', 'us-east-1', etc.). This is the region where your queue is housed.
-        signing-region = "x"
-      
-        # Endpoint to access queue
-        service-endpoint = "http://vinyldns-elasticmq:9324/"
-      
-        # Queue name. Should be used in conjunction with service endpoint, rather than using a queue url which is subject to change.
-        queue-name = "vinyldns"
-     }
-  }
-}
-
- -

The following is a sample MySQL queue config:

- -
queue {
-  class-name = "vinyldns.mysql.queue.MySqlMessageQueueProvider"
-
-  polling-interval = 250.millis
-  messages-per-poll = 10
-  max-retries = 50 # Override max retries; default = 100
-
-  settings = {
-     name = "vinyldns"
-     driver = "org.mariadb.jdbc.Driver"
-     migration-url = "jdbc:mariadb://localhost:19004/?user=root&password=pass"
-     url = "jdbc:mariadb://localhost:19004/vinyldns?user=root&password=pass"
-     user = "root"
-     password = "pass"
-   
-     # see https://github.com/brettwooldridge/HikariCP
-     connection-timeout-millis = 1000
-     idle-timeout = 10000
-     max-lifetime = 30000
-     maximum-pool-size = 5
-     minimum-idle = 0
-   
-     my-sql-properties = {
-        cachePrepStmts=true
-        prepStmtCacheSize=250
-        prepStmtCacheSqlLimit=2048
-        rewriteBatchedStatements=true
-     }
-  }
-}
-
- -

Database Configuration

- -

VinylDNS supports a MySQL database. You can enable all repos in a single backend, or have a mix of the two. For each -backend, you need to configure the table(s) that should be loaded.

- -

If using MySQL, follow the MySQL Setup Guide first to get the values you need to configure here.

- -
vinyldns {
-
-  # this list should include only the datastores being used by your instance
-  data-stores = ["mysql"]
-
-  mysql {
-   
-     # this is the path to the mysql provider. This should not be edited
-     # from the default in reference.conf
-     class-name = "vinyldns.mysql.repository.MySqlDataStoreProvider"
-   
-     settings {
-        # the name of the database, recommend to leave this as is
-        name = "vinyldns"
-      
-        # the jdbc driver, recommended to leave this as is
-        driver = "org.mariadb.jdbc.Driver"
-      
-        # the URL used to create the schema, typically this will be without the "database" name
-        migration-url = "jdbc:mariadb://localhost:19002/?user=root&password=pass"
-      
-        # the main connection URL
-        url = "jdbc:mariadb://localhost:19002/vinyldns?user=root&password=pass"
-      
-        # the user to connect to MySQL
-        user = "root"
-      
-        # the password to connect to MySQL
-        password = "pass"
-      
-        ## see https://github.com/brettwooldridge/HikariCP for more detail on the following fields
-        # the maximum number of connections to scale the connection pool to
-        maximum-pool-size = 20
-      
-        # the maximum number of milliseconds to wait for a connection from the connection pool
-        connection-timeout-millis = 1000
-      
-        # the minimum number of idle connections that HikariCP tries to maintain in the pool
-        minimum-idle = 10
-      
-        # the maximum number of milliseconds that a connection is can sit idle in the pool
-        idle-timeout = 10000
-      
-        # The max lifetime of a connection in a pool.  Should be several seconds shorter than the database imposed connection time limit
-        max-lifetime = 600000
-      
-        # controls whether JMX MBeans are registered
-        register-mbeans = true
-      
-        # my-sql-properties allows you to include any additional mysql performance settings you want.
-        # Note that the properties within my-sql-properties must be camel case!
-        # see https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration for guidance
-        my-sql-properties {
-        prepStmtCacheSize = 300
-        prepStmtCacheSqlLimit = 2048
-        cachePrepStmts = true
-        useServerPrepStmts = true
-        rewriteBatchedStatements = true
-        }
-     }
-   
-     repositories {
-        # all repositories with config sections here will be enabled in mysql
-        zone {
-        # no additional settings for repositories enabled in mysql
-        }
-        batch-change {
-        }
-        user {
-        }
-        record-set {
-        }
-     }
-  }
-
-}
-
- -

Cryptography Settings

- -

VinylDNS uses symmetric cryptography in order to encrypt/decrypt sensitive information in the system. This includes TSIG -keys and user secrets. Cryptography is used in both the portal as well as the api.

- -

Cryptography is pluggable, meaning you can bring your own crypto with you. All that is required is to provide an -implementation -of CryptoAlgebra -using a crypto library of choice. The default implementation is NoOpCrypto, which does not do any encryption (not -recommended for production). VinylDNS provides a cryptography implementation called JavaCrypto that you can use for -production. The example that follows illustrates using the provided JavaCrypto.

- -

If you create your own implementation, you have to build your jar and make it (and all dependencies) available to the -VinylDNS API and the VinylDNS portal.

- -

The following are the configuration settings for crypto. Notice here the only thing we see is the type. The type -is the fully qualified class name for the CryptoAlgebra you will be using. If your crypto implementation requires -additional settings, they will be configured inside the crypto element, adjacent to the type.

- -
vinyldns {
-  crypto {
-     type = "vinyldns.core.crypto.JavaCrypto"
-     secret = "8B06A7F3BC8A2497736F1916A123AA40E88217BE9264D8872597EF7A6E5DCE61"
-  }
-}
-
- -

Default Zone Connections

- -

VinylDNS has three ways of indicating zone connections:

- -
    -
  1. Global default connection applies to all zones unless overridden by one of the following connections. This -configuration is required.
  2. -
  3. Backends allows you to specify zone connection information for an individual zone by choosing a pre-configured zone -connection. This configuration is optional.
  4. -
  5. Zone level override allows you to specify zone update and transfer connection information for each zone. More -information is in the Zone Model.
  6. -
- -

VinylDNS has 2 connections for each zone:

- -
    -
  1. The DDNS connection - used for making DDNS updates to the zone
  2. -
  3. The Transfer connection - used for making AXFR requests for zone syncing with the DNS backend
  4. -
- -

VinylDNS also ties in testing network connectivity to the default zone connection’s primary server into its API health -checks. A value for the health check connection timeout in milliseconds can be specified using health-check-timeout; a -default value of 10000 will be used if not provided.

- -
vinyldns {
-
-  # timeout for DNS backend connectivity health check
-  health-check-timeout = 5000
-
-  # the DDNS connection information for the default dns backend
-  defaultZoneConnection {
-     # this is not really used, but must be set, usually set to the keyName itself, or a descriptive name if you are interested
-     name = "vinyldns."
-   
-     # the name of the TSIG key
-     keyName = "vinyldns."
-   
-     # the TSIG secret key
-     key = "nzisn+4G2ldMn0q1CV3vsg=="
-   
-     # the host name or IP address, note you can add a port if not using the default by settings hostname:port
-     primaryServer = "ddns1.foo.bar.com"
-   
-     # the key algorithm to use: HMAC-MD5, HMAC-SHA1, HMAC-SHA224, HMAC-SHA256, HMAC-SHA384, HMAC-SHA512
-     algorithm = "HMAC-MD5"
-  }
-
-  # the AXFR connection information for the default dns backend
-  defaultTransferConnection {
-     name = "vinyldns."
-     keyName = "vinyldns."
-     key = "nzisn+4G2ldMn0q1CV3vsg=="
-     primaryServer = "localhost:19001"
-     algorithm = "HMAC-MD5"
-  }
-}
-
-  # Zone Connection Data, ID can be specified in a zone to override the global default configuration
-  backends = [
-     {
-        id = "test-backend-id"
-        zone-connection {
-        name = "vinyldns."
-        key-name = "vinyldns."
-        key = "nzisn+4G2ldMn0q1CV3vsg=="
-        primary-server = "127.0.0.1:19001"
-        algorithm = "HMAC-MD5"
-     }
-     transfer-connection {
-        name = "vinyldns."
-        key-name = "vinyldns."
-        key = "nzisn+4G2ldMn0q1CV3vsg=="
-        primary-server = "127.0.0.1:19001"
-        algorithm = "HMAC-MD5"
-     }
-  }
-]
-
- -

Additional Configuration Settings

- -

Approved Name Servers

- -

When running a large DNS installation, allowing users the ability to self-manage zone delegations can lead to a lot of -problems when not done properly. Also, allowing delegation to untrusted DNS servers can be a security risk.

- -

To “lock down” zone delegation, you can configure name servers that you trust, so zone delegation is controlled.

- -

The entries in the list can be host names, IP addresses, or regular expressions.

- -
approved-name-servers = [
-  "172.17.42.1.",
-  "ddns1.foo.bar.",
-  ".*awsdns.*"
-]
-
- -

Processing Disabled

- -

The processing disabled flag can be used if doing a blue/green deployment. When processing is disabled, the VinylDNS -engine will not be actively polling the message queue for messages.

- -

processing-disabled = false | true

- -

Color

- -

For blue-green deployments, you can configure the color of the current node. Not applicable to every environment.

- -

color = "green"

- -

Version

- -

Version of the application that is deployed. Currently, this is a configuration value.

- -

version = "0.8.0"

- -

Note: You can get installation information including color, version, default key name, and processing-disabled by -hitting the status endpoint GET /status

- -

HTTP Host and Port

- -

To specify what host and port to bind to when starting up the API server, default is 9000.

- -
rest {
-  host = "0.0.0.0"
-  port = 9000
-}
-
- -

Sync Delay

- -

VinylDNS uses a “sync-delay” setting that prevents users from syncing their zones too frequently. The settings is -inspected per zone, and is the number of milliseconds since the last sync to wait before allowing another sync for -that zone.

- -
sync-delay = 10000
-
- -

Notifiers

- -

VinylDNS provides the ability to send notifications via configured notifiers when a batch change is either implemented -or rejected. Notifiers in VinylDNS are designed to be pluggable (ie. bring-your-own-implementation), granting users the -flexibility to implement their own which can smoothly integrate into their instance.

- -

Setup requires a notifiers key which contains all of the configured notifiers that will be used by the running -instance.

- -
notifiers = ["email", "sns"]
-
- -

E-mail notifier

- -

Configuration for the e-mail notifier appears like the following:

- -
email = {
-   # Path to notifier provider implementation
-   class-name = "vinyldns.api.notifier.email.EmailNotifierProvider"
-
-   settings = {
-      # Sender address for e-mail notifications
-      from = "Sender <do-not-reply@example.sender>"
-
-      smtp {
-         # Host SMTP server
-         host = "example.host"
-      }
-   }
-}
-
- -

Note that settings.from and settings.smtp are both required, though the smtp values requirements depend on the -specific exchange service that you are interfacing with.

- -

Below is an example e-mail notification:

- -

Sample E-mail Notification

- -

AWD Simple Notification Service (SNS) notifier

- -

Configuration for the AWS SNS notifier appears like the following:

- -
sns {
-  # Path to notifier provider implementation
-  class-name = "vinyldns.api.notifier.sns.SnsNotifierProvider"
-
-  settings {
-  # SNS topic Amazon Resource Name (ARN)
-  topic-arn = "arn:aws:sns:us-east-1:000000000000:batchChanges"
-
-  # AWS access key and secret
-  access-key = "vinyldnsTest"
-  secret-key = "notNeededForSnsLocal"
-
-  # Endpoint to access SNS
-  service-endpoint = "http://127.0.0.1:19006"
-
-  # Regional endpoint to make your requests (eg. 'us-west-2', 'us-east-1', etc.). This is the region where your SNS is housed.
-  signing-region = "us-east-1"
-  }
-}
-
- -

Batch Manual Review Enabled

- -

Configuration setting that determines whether batch changes with non-fatal errors can be reviewed rather than failing -immediately. When enabling manual review, the expectation is that a DNS technician is actively querying and addressing -batch change requests that are in a manual review state. If your process flow does not accommodate this expectation, we -advise disabling manual review.

- -
manual-batch-review-enabled = true
-
- -

Manual Review Domains

- -

Configuration setting that determines what Batch Change/DNS Change input names require manual review -if manual-batch-review-enabled is set to true. If manual-batch-review-enabled is set to false any input names -that match entries in the configured list will be treated as fatal errors.

- -
manual-review-domains = {
-  domain-list = [
-     "needs-review.*"
-  ]
-  ip-list = [
-     "192.0.2.254",
-     "192.0.2.255",
-     "fd69:27cc:fe91:0:0:0:ffff:1",
-     "fd69:27cc:fe91:0:0:0:ffff:2"
-  ]
-  zone-name-list = [
-     "zone.requires.review."
-  ]
-}
-
- -

Scheduled Batch Changes Enabled

- -

Configuration setting that determines if users are able to make Batch Changes with a scheduled -time. manual-batch-review-enabled must be enabled as well. If enabled, a VinylDNS administrator cannot approve the -Batch Change until after the scheduled time. An administrator could also reject the Batch Change.

- -
scheduled-changes-enabled = true
-
- -

IPv6 Zone Discovery Boundaries

- -

Configuration setting that determines the range that will be searched for in reverse IPv6 Zone Discovery. This allows -you to limit the search for what is appropriate for your organization. For example, min = 2, max = 3 will only search in -zones in the form X.X.ip6.arpa. and X.X.X.ip6.arpa.. Note the following constraints: 0 < min <= max <= 32. If your -organization only makes zone cuts at one point, you may set min == max.

- -

The default values if omitted are min = 5, max = 20.

- -
v6-discovery-nibble-boundaries {
-  min = 5
-  max = 20
-}
-
-
- -

Full Example Config

- -
# The default application.conf is not intended to be used in production.  It assumes a docker-compose
-# setup for all of the services.  Provide your own application.conf on the docker mount with your
-  # own settings
-  vinyldns {
-
-  queue {
-     class-name = "vinyldns.sqs.queue.SqsMessageQueueProvider"
-   
-     messages-per-poll = 10
-     polling-interval = 250.millis
-   
-     settings {
-        # AWS access key and secret.
-        access-key = "x"
-        secret-key = "x"
-      
-        # Regional endpoint to make your requests (eg. 'us-west-2', 'us-east-1', etc.). This is the region where your queue is housed.
-        signing-region = "x"
-      
-        # Endpoint to access queue
-        service-endpoint = "http://localhost:9324/"
-      
-        # Queue name. Should be used in conjunction with service endpoint, rather than using a queue url which is subject to change.
-        queue-name = "vinyldns"
-     }
-  }
-
-  # host and port the server binds to.  This should not be changed
-  rest {
-     host = "0.0.0.0"
-     port = 9000
-  }
-
-  # The maximum number of records VinylDNS will load when syncing a DNS Zone
-  # this is to prevent possible out of memory errors when loading a Zone
-  # this does not stop the zone from existing in DNS, but you will not be able to manage it in VinylDNS if the number of records exceeds the max
-  max-zone-size = 60000
-
-  # the delay between zone syncs so we are not syncing too often
-  sync-delay = 10000
-
-  # crypto settings for symmetric cryptography of secrets in the system
-  # Note: for production systems secrets should not live in plain text in a file
-  crypto {
-    type = "vinyldns.core.crypto.NoOpCrypto"
-  }
-
-  # both datastore options are in use
-  data-stores = ["mysql"]
-
-  mysql {
-     class-name = "vinyldns.mysql.repository.MySqlDataStoreProvider"
-   
-     settings {
-        name = "vinyldns"
-        driver = "org.mariadb.jdbc.Driver"
-        migration-url = "jdbc:mariadb://localhost:19002/?user=root&password=pass"
-        url = "jdbc:mariadb://localhost:19002/vinyldns?user=root&password=pass"
-        user = "root"
-        password = "pass"
-        maximum-pool-size = 20
-        minimum-idle = 10
-        connection-timeout-millis = 1000
-        idle-timeout = 10000
-        max-lifetime = 600000
-        register-mbeans = true
-        my-sql-properties {
-           prepStmtCacheSize = 300
-           prepStmtCacheSqlLimit = 2048
-           cachePrepStmts = true
-           useServerPrepStmts = true
-           rewriteBatchedStatements = true
-        }
-     }
-   
-     repositories {
-        zone {
-        }
-        batch-change {
-        }
-        user {
-        }
-        record-set {
-        }
-        group {
-        }
-        membership {
-        }
-        group-change {
-        }
-        zone-change {
-        }
-        record-change {
-        }
-     }
-  }
-
-  # the DDNS connection information for the default dns backend
-  defaultZoneConnection {
-     name = "vinyldns."
-     keyName = "vinyldns."
-     key = "nzisn+4G2ldMn0q1CV3vsg=="
-     primaryServer = "localhost:19001"
-     algorithm = "HMAC-MD5"
-  }
-
-  # the AXFR connection information for the default dns backend
-  defaultTransferConnection {
-     name = "vinyldns."
-     keyName = "vinyldns."
-     key = "nzisn+4G2ldMn0q1CV3vsg=="
-     primaryServer = "localhost:19001"
-     algorithm = "HMAC-MD5"
-  }
-
-  # the max number of changes in a single batch change.  Change carefully as this has performance
-  # implications
-  batch-change-limit = 1000
-
-  # notifier configuration
-  notifiers = ["email", "sns"]
-
-  email = {
-     # Path to notifier provider implementation
-     class-name = "vinyldns.api.notifier.email.EmailNotifierProvider"
-   
-     settings = {
-     # Sender address for e-mail notifications
-     from = "Sender <do-not-reply@example.sender>"
-   
-     smtp {
-        # Host SMTP server
-        host = "example.host"
-     }
-  }
-
-  sns {
-     # Path to notifier provider implementation
-     class-name = "vinyldns.api.notifier.sns.SnsNotifierProvider"
-   
-     settings {
-        # SNS topic Amazon Resource Name (ARN)
-        topic-arn = "arn:aws:sns:us-east-1:000000000000:batchChanges"
-      
-        # AWS access key and secret
-        access-key = "vinyldnsTest"
-        secret-key = "notNeededForSnsLocal"
-      
-        # Endpoint to access SNS
-        service-endpoint = "http://127.0.0.1:19006"
-      
-        # Regional endpoint to make your requests (eg. 'us-west-2', 'us-east-1', etc.). This is the region where your SNS is housed.
-        signing-region = "us-east-1"
-     }
-  }
-
-  # true if you want to enable manual review for non-fatal errors
-  manual-batch-review-enabled = true
-
-  # true if you want to allow Batch Changes to be scheduled.  manual-batch-review-enabled must also be true.
-  scheduled-changes-enabled = true
-
-  # types of unowned records that users can access in shared zones
-  shared-approved-types = ["A", "AAAA", "CNAME", "PTR", "TXT"]
-
-  # FQDNs / IPs that cannot be modified via VinylDNS
-  # regex-list: list of regular expressions matching any FQDN that are not allowed to be modified by this VinylDNS instance
-  # ip-list: list of IP addresses that cannot be modified by this VinylDNS instance
-  high-value-domains = {
-     regex-list = [
-     "high-value-domain.*"
-     ]
-     ip-list = [
-        "192.0.2.252",
-        "192.0.2.253",
-        "fd69:27cc:fe91:0:0:0:0:ffff",
-        "fd69:27cc:fe91:0:0:0:ffff:0"
-     ]
-  }
-
-  # FQDNS / IPs / zone names that require manual review when submitted through Batch Change/DNS Change
-  # Treated as a fatal error if manual review is not enabled
-  manual-review-domains = {
-     domain-list = [
-        "needs-review.*"
-     ]
-     ip-list = [
-        "192.0.2.254",
-        "192.0.2.255",
-        "fd69:27cc:fe91:0:0:0:ffff:1",
-        "fd69:27cc:fe91:0:0:0:ffff:2"
-     ]
-     zone-name-list = [
-        "zone.requires.review."
-     ]
-  }
-
-  # Zone Connection Data
-  backends = [
-     {
-        id = "test-backend-id"
-        zone-connection {
-           name = "vinyldns."
-           key-name = "vinyldns."
-           key = "nzisn+4G2ldMn0q1CV3vsg=="
-           primary-server = "127.0.0.1:19001"
-           algorithm = "HMAC-MD5"
-        }
-        transfer-connection {
-           name = "vinyldns."
-           key-name = "vinyldns."
-           key = "nzisn+4G2ldMn0q1CV3vsg=="
-           primary-server = "127.0.0.1:19001"
-           algorithm = "HMAC-MD5"
-        }
-     }
-  ]
-
-}
-
-  # Akka settings, these should not need to be modified unless you know akka http really well.
-  akka {
-     loglevel = "INFO"
-     loggers = ["akka.event.slf4j.Slf4jLogger"]
-     logging-filter = "akka.event.slf4j.Slf4jLoggingFilter"
-     logger-startup-timeout = 30s
-  }
-
-  akka.http {
-     server {
-        # The time period within which the TCP binding process must be completed.
-        # Set to `infinite` to disable.
-        bind-timeout = 5s
-      
-        # Show verbose error messages back to the client
-        verbose-error-messages = on
-     }
-   
-     parsing {
-        # akka-http doesn't like the AWS4 headers
-        illegal-header-warnings = on
-     }
-  }
-}
-
-
\ No newline at end of file diff --git a/operator/config-portal.html b/operator/config-portal.html deleted file mode 100644 index f935fa243..000000000 --- a/operator/config-portal.html +++ /dev/null @@ -1,324 +0,0 @@ -VinylDNS: Portal Configuration Guide

Portal Configuration Guide

-

The portal configuration is much smaller than the API Server.

- -

Note: Unlike the API server, not all configuration resides under a vinyldns namespace.

- -

Configuration

- - -

Database Configuration

-

VinylDNS supports a MySQL backend (see API Database Configuration).

- -

Follow the MySQL Setup Guide first to get the values you need to configure here.

- -

The Portal uses the following tables:

- -
    -
  • user
  • -
  • userChanges
  • -
- -

Note that the user table is shared between the API and the portal, and must be configured with -the same values in both configs:

- -
vinyldns {
-
-  # this list should include only the datastores being used by your portal instance (user and userChange repo)
-  data-stores = ["mysql"]
-  
-  mysql {
-    
-    # this is the path to the mysql provider. This should not be edited
-    # from the default in reference.conf
-    class-name = "vinyldns.mysql.repository.MySqlDataStoreProvider"
-    
-    settings {
-      # the name of the database, recommend to leave this as is
-      name = "vinyldns"
-      
-      # the jdbc driver, recommended to leave this as is
-      driver = "org.mariadb.jdbc.Driver"
-  
-      # the URL used to create the schema, typically this will be without the "database" name
-      migration-url = "jdbc:mariadb://localhost:19002/?user=root&password=pass"
-  
-      # the main connection URL
-      url = "jdbc:mariadb://localhost:19002/vinyldns?user=root&password=pass"
-  
-      # the user to connect to MySQL
-      user = "root"
-  
-      # the password to connect to MySQL
-      password = "pass"
-  
-      ## see https://github.com/brettwooldridge/HikariCP for more detail on the following fields
-      # the maximum number of connections to scale the connection pool to
-      maximum-pool-size = 20
-  
-      # the maximum number of milliseconds to wait for a connection from the connection pool
-      connection-timeout-millis = 1000
-      
-      # the minimum number of idle connections that HikariCP tries to maintain in the pool
-      minimum-idle = 10
-            
-      # the maximum number of milliseconds that a connection is can sit idle in the pool
-      idle-timeout = 10000
-  
-      # The max lifetime of a connection in a pool.  Should be several seconds shorter than the database imposed connection time limit
-      max-lifetime = 600000
-      
-      # controls whether JMX MBeans are registered
-      register-mbeans = true
-      
-      # my-sql-properties allows you to include any additional mysql performance settings you want.
-      # Note that the properties within my-sql-properties must be camel case!
-      # see https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration for guidance
-      my-sql-properties {
-        prepStmtCacheSize = 300
-        prepStmtCacheSqlLimit = 2048
-        cachePrepStmts = true
-        useServerPrepStmts = true
-        rewriteBatchedStatements = true
-      }
-    }
-    
-    repositories {
-      # all repositories with config sections here will be enabled in mysql
-      user {
-      # no additional settings for repositories enabled in mysql
-      }
-    }
-  }
-}
-
- -

LDAP

-

Be sure to follow the LDAP Setup Guide first to get the values you need to configure here.

- -

LDAP configuration connects VinylDNS to your Directory where user information is stored.

- -

The default value for user sync enabled is false and user sync hours polling interval is 24 (max value). If the hours polling interval -is configured higher than 24, 24 hours will be used.

- -
LDAP {
-  # The name of the user to connect VinylDNS to LDAP
-  user="test"
-
-  # The password for the user to connect VinylDNS to LDAP
-  password="test"
-
-  # The domain for the user connecting VinylDNS to LDAP
-  domain="test"
-
-  # One or more search bases to find users.  If users come from multiple domains, list them here
-  searchBase = [{organization = "someDomain", domainName = "DC=test,DC=test,DC=com"}, {organization = "anotherDomain", domainName = "DC=test,DC=com"}]
-
-  # Connection information to LDAP
-  context {
-    initialContextFactory = "com.sun.jndi.ldap.LdapCtxFactory"
-    securityAuthentication = "simple"
-
-    # Set this to point to your LDAP
-    providerUrl = "ldaps://somedomain.com:9999"
-  }
-  
-  user-sync {
-    enabled = true # Default value is false
-    hours-polling-interval = 12 # Default value is 24
-  }
-}
-
- -

Cryptography Settings

-

The Portal encrypts user secrets at rest using the same mechanism as the API server.

- -

Note: It is extremely important that these settings match the API server, otherwise the API server will not -be able to decrypt user secrets and your installation will fail!

- -

Cryptography is pluggable, meaning you can bring your own crypto with you. All that is required is to provide an -implementation of CryptoAlgebra -using a crypto library of choice. The default implementation is NoOpCrypto, which does not do any encryption (not recommended for production).

- -

The following are the configuration settings for crypto. Notice here the only thing we see is the type. The type -is the fully qualified class name for the CryptoAlgebra you will be using. If your crypto implementation requires -additional settings, they will be configured inside the crypto element, adjacent to the type.

- -
crypto {
-  type = "vinyldns.core.crypto.JavaCrypto"
-  secret = "8B06A7F3BC8A2497736F1916A123AA40E88217BE9264D8872597EF7A6E5DCE61"
-}
-
- - -

Custom links display either on the nav bar once logged in, or on the log in screen. These links are useful to point -to internal documentation and procedures. For example, how to raise certain tickets with engineering, or -internal slack channels.

- -
# an array of links
-links = [
-  {
-    # indicates that this link should be display on the sidebar once logged in
-    displayOnSidebar = true
-
-    # display this link also on the login screen
-    displayOnLoginScreen = true
-
-    # text to display for the link
-    title = "API Documentation"
-
-    # the hyperlink address being linked to
-    href = "https://vinyldns.io"
-
-    # a fa icon to display
-    icon = "fa fa-file-text-o"
-  }
-]
-
- -

Additional Configuration Settings

- -

Play Secret

-

The play secret must be set to a secret value, and should be an environment variable

- -
# See https://www.playframework.com/documentation/latest/ApplicationSecret for more details.
-play.http.secret.key = "vinyldnsportal-change-this-for-production"
-
- -

Test Login

-

The test login should not be used for production environments. It is useful to tinker with VinylDNS. If this -setting is true, then you can login with testuser and testpassword. Logging in using the testuser will not -contact LDAP.

- -

portal.test_login = false

- -

HTTP Port

-

The HTTP Port that the Portal server will bind to

- -

http.port=9001

- -

Shared Zones Display / Record Owner Selection

-

Necessary to enable shared zones submission and record ownership

- -

shared-display-enabled = true

- -

Batch Change Limit

-

How many changes are allowable in a single DNS change request

- -

batch-change-limit = 1000

- -

Manual Review Enabled

-

Triggers the manual review process for certain DNS requests

- -

manual-batch-review-enabled = true

- -

Scheduled Changes

-

Allows users to schedule changes to be run sometime in the future

- -

scheduled-changes-enabled = true

- -

Full Example Config

-
# This is the main configuration file for the application.
-# ~~~~~
-
-# Secret key
-# ~~~~~
-# The secret key is used to secure cryptographics functions.
-#
-# This must be changed for production, but we recommend not changing it in this file.
-#
-# See https://www.playframework.com/documentation/latest/ApplicationSecret for more details.
-play.http.secret.key = "vinyldnsportal-change-this-for-production"
-
-# The application languages
-# ~~~~~
-play.i18n.langs = [ "en" ]
-portal.vinyldns.backend.url = "http://vinyldns-api:9000"
-portal.test_login = false
-
-# configuration for the users and groups store
-data-stores = ["mysql"]
-
-mysql {
-  class-name = "vinyldns.mysql.repository.MySqlDataStoreProvider"
-  
-  settings {
-    name = "vinyldns"
-    driver = "org.mariadb.jdbc.Driver"
-    migration-url = "jdbc:mariadb://localhost:19002/?user=root&password=pass"
-    url = "jdbc:mariadb://localhost:19002/vinyldns?user=root&password=pass"
-    user = "root"
-    password = "pass"
-    maximum-pool-size = 20
-    minimum-idle = 10
-    connection-timeout-millis = 1000
-    idle-timeout = 10000
-    max-lifetime = 600000
-    register-mbeans = true
-    my-sql-properties {
-      prepStmtCacheSize = 300
-      prepStmtCacheSqlLimit = 2048
-      cachePrepStmts = true
-      useServerPrepStmts = true
-      rewriteBatchedStatements = true
-    }
-  }
-  
-  repositories {
-    user {
-    }
-  }
-}
-
-}
-
-play.filters.enabled += "play.filters.csrf.CSRFFilter"
-
-# Expire session after 10 hours
-play.http.session.maxAge = 10h
-
-# session secure should be false in order to run properly locally, this is set properly on deployment
-play.http.session.secure = false
-play.http.session.httpOnly = true
-
-# use no-op by default
-crypto {
-  type = "vinyldns.core.crypto.NoOpCrypto"
-}
-
-http.port=9001
-
-links = [
-  {
-    displayOnSidebar = true
-    displayOnLoginScreen = true
-    title = "API Documentation"
-    href = "https://vinyldns.io"
-    icon = "fa fa-file-text-o"
-  }
-]
-
-
\ No newline at end of file diff --git a/operator/index.html b/operator/index.html deleted file mode 100644 index d856afc09..000000000 --- a/operator/index.html +++ /dev/null @@ -1,26 +0,0 @@ -VinylDNS: Operator Guide

Operator Guide

-

This operator guide will help administrators install and operate VinylDNS API and Portal.

- -
    -
  1. Setup the pre-requisite systems - VinylDNS has several external dependencies that are required in order to operate.
  2. -
  3. Setup the VinylDNS API server
  4. -
  5. Setup the VinylDNS Portal server
  6. -
-
\ No newline at end of file diff --git a/operator/pre.html b/operator/pre.html deleted file mode 100644 index 4a4ed9562..000000000 --- a/operator/pre.html +++ /dev/null @@ -1,109 +0,0 @@ -VinylDNS: Pre-requisites

VinylDNS Pre-requisites

- -

VinylDNS has the following external requirements that need to be setup so that VinylDNS can operate. Those include:

- -
    -
  1. DNS - your DNS servers VinylDNS will interact with
  2. -
  3. Database - the database houses all of VinylDNS information including history, records, zones, and users
  4. -
  5. Message Queue - the message queue supports high-availability and throttling of commands to DNS -backend servers
  6. -
  7. LDAP - ldap supports both authentication as well as the source of truth for users that are managed inside -the VinylDNS database
  8. -
- -

DNS

- -

VinylDNS is not a DNS, rather it integrates with your existing DNS installations to enable DNS self-service and -streamline DNS operations.

- -

VinylDNS communicates to your DNS via:

- -
    -
  • DDNS - DDNS is used for all record updates
  • -
  • AXFR - Zone Transfers are used to load DNS records into the VinylDNS database.
  • -
- -

VinylDNS communicates to your DNS using “connections”. A connection allows you to specify:

- -
    -
  1. The TSIG key name
  2. -
  3. The TSIG key secret
  4. -
  5. The server (and optionally port) to communicate to DNS with
  6. -
- -

There are 2 connections, one for DDNS and another for zone transfers. This allows you to use a different DNS server -/ key for zone transfers.

- -

Connections (DDNS and Transfer) can be setup

- -
    -
  • per zone - every zone can override the global default by specifying its own connections.
  • -
  • global default - assuming you are managing a primary system, you -can configure default zone connections. When no zone connection is -specified on a zone, the global defaults will be used.
  • -
- -

Message Queues

- -

Most operations that take place in VinylDNS use a message queue. These operations require high-availability, -fault-tolerance with retry, and throttling. The message queue supports these characteristics in VinylDNS.

- -

Some operations do not use the message queue, these include user and group changes as they do not carry the same -fault-tolerance and throttling requirements.

- -

Message Queue Types

- -

AWS SQS

- -

Our VinylDNS instance uses AWS SQS to fulfill its message queue service needs. SQS has the following characteristics:

- -
    -
  1. High-Availability
  2. -
  3. Retry - in the event that a message cannot be processed, or if a node fails midstream processing, it will be -automatically made available for another node to process
  4. -
  5. Back-pressure - SQS is a pull based system, meaning that if VinylDNS is currently busy, new messages will not be -pulled for processing. As soon as a node becomes available, the message will be pulled. This is much preferable to -a push based system, where bottlenecks in processing could cause an increase in heap pressure in the API nodes -themselves.
  6. -
  7. Price - SQS is very reasonably priced. Comcast operates multiple message queues for different environments (dev, -staging, prod, etc). The price to use SQS is in the single digit dollars per month. VinylDNS can be tuned to run -exclusively in the free tier.
  8. -
- -

Review the Setup AWS SQS Guide for more information.

- -

MySQL

- -

VinylDNS has also implemented a message queue using MySQL, which incorporates the features that we currently utilize -through AWS SQS such as changing visibility timeout and re-queuing operations.

- -

Review the Setup MySQL Guide for more information.

- -

LDAP

- -

VinylDNS uses LDAP in order to authenticate users in the Portal. LDAP is not used in the API, instead the API -uses its own user and group database for authentication.

- -

When a user first logs into VinylDNS, their user information (first name, last name, user name, email) will be pulled -from LDAP, and stored in the UserRepository. Credentials will also be generated for the user and stored encrypted in -the UserRepository.

- -

Review the Setup LDAP Guide for more information

-
\ No newline at end of file diff --git a/operator/setup-api.html b/operator/setup-api.html deleted file mode 100644 index 66d47ec8e..000000000 --- a/operator/setup-api.html +++ /dev/null @@ -1,56 +0,0 @@ -VinylDNS: Setup API Server

Setup API Server

-

The API Server is the main run-time for VinylDNS. To setup the API server, follow these steps:

- -
    -
  1. Pre-requisites
  2. -
  3. Setup MySQL
  4. -
  5. Setup AWS SQS
  6. -
  7. Configure API Server
  8. -
  9. Using the API Docker Image
  10. -
- -

Using the API Docker Image

-

The API server is provided via the VinylDNS API Image. -The docker image allows you to mount your own config, as well as your own external dependency jars.

- -

The API server is stateless, allowing you to run multiple instances in multiple data centers for high-availability -purposes.

- -

Note: If using VinylDNS Java Crypto and the pre-requisites defined here, no additional jars need to be loaded.

- -

Environment variables

-
    -
  1. MYSQL_ADDRESS - the IP address of the mysql server; defaults to vinyldns-mysql assuming a docker compose setup
  2. -
  3. MYSQL_PORT - the port of the mysql server; defaults to 3306
  4. -
- -

Volume Mounts

-

The API exposes volumes that allow the user to customize the runtime. Those mounts include:

- -
    -
  • /opt/vinyldns/lib_extra - place here additional jar files that need to be loaded into the classpath when the application starts up. -This is used for “plugins” that are proprietary or not part of the standard build. All jar files here will be placed on the class path.
  • -
  • /opt/vinyldns/conf - place an application.conf file here with your own custom settings. Once you have your config created, -place here.
  • -
- -

Ports

-

The API only exposes port 9000 for HTTP access to all endpoints

-
\ No newline at end of file diff --git a/operator/setup-ldap.html b/operator/setup-ldap.html deleted file mode 100644 index f326835db..000000000 --- a/operator/setup-ldap.html +++ /dev/null @@ -1,41 +0,0 @@ -VinylDNS: Setup LDAP

Setup LDAP

-

VinylDNS uses LDAP for authenticating users in the portal as well as the source of user information loaded into -VinylDNS. VinylDNS does support service accounts, which are useful for automation.

- -

Important Note: VinylDNS presently maintains its own user, group, and membership repository. The only way for a -user to be created is to login to the portal. Implementers can choose to out-of-band manage the VinylDNS repositories.

- -

There are no steps necessary for setup than having a Directory that can communicate via LDAP, and a user (account) that -can read data from the Directory. Once you have that information, proceed to the Portal Configuration.

- -

Considerations -You should communicate to your Directory over LDAP using TLS. To do so, the SSL certs should be installed -on the portal servers, or provided via a java trust store (key store). The portal provides an option to specific -a java key store when it starts up.

- -

Configuring LDAP

-

Before you can configure LDAP, make note of the host, username, and password that you will be using. -Follow the Portal Configuration to complete the setup.

- -

Syncing users against LDAP

-

VinylDNS has implemented an optional feature to perform a recurring LDAP lookup against all non-test users in the database and perform -a user lock for users that no longer exist in the directory. Automated user locking of deprecated accounts both streamlines -the user management process and enforces an extra layer of security around VinylDNS.

-
\ No newline at end of file diff --git a/operator/setup-mysql.html b/operator/setup-mysql.html deleted file mode 100644 index 39f720992..000000000 --- a/operator/setup-mysql.html +++ /dev/null @@ -1,42 +0,0 @@ -VinylDNS: Setup MySQL

Setup MySQL

-

Our instance of VinylDNS currently stores data in MySQL.

- -
    -
  • zone - holds zones
  • -
  • zone_access - holds user or group identifiers that have access to zones
  • -
  • batch_change - holds batch changes (multiple changes across zones in a single batch)
  • -
  • single_change - holds individual changes within a batch_change
  • -
  • user - holds user information, including access keys and secrets
  • -
  • record-set - holds record data
  • -
- -

Setting up the database

-

VinylDNS uses Flyway to manage SQL migrations. This means that any database changes, including -creating the database, adding tables, etc. are all automatically applied when VinylDNS starts up. You do not need -to do anything other than giving access to VinylDNS API from your MySQL server instance. You can view the database -schema and migrations in the mysql module db/migration folder

- -

VinylDNS uses HikariCP for a high-speed connection -pool.

- -

Configuring MySQL

-

Before you can configure MySQL, make note of the host, username, and password that you will be using. -Follow the API Database Configuration to complete the setup.

-
\ No newline at end of file diff --git a/operator/setup-portal.html b/operator/setup-portal.html deleted file mode 100644 index 5cfb65e86..000000000 --- a/operator/setup-portal.html +++ /dev/null @@ -1,63 +0,0 @@ -VinylDNS: Setup the Portal Server

Setup the Portal Server

- -

The Portal Server is the web UI for VinylDNS. To setup the Portal server, follow these steps:

- -
    -
  1. Setup API Server
  2. -
  3. Setup LDAP
  4. -
  5. Configure Portal Server
  6. -
  7. Using the Portal Docker Image
  8. -
- -

Once you have you pre-requisites ready, review the Portal Configuration Guide for how to build out -your configuration file.

- -

Using the Portal Docker Image

- -

The Portal server is provided as a VinylDNS Portal Image.

- -

The API server is stateless, allowing you to run multiple instances in multiple data centers for high-availability -purposes.

- -

Volume mounts

- -
    -
  • /opt/vinyldns/lib_extra - place here additional jar files that need to be loaded into the classpath when the -application starts up. This is used for “plugins” that are proprietary or not part of the standard build. All jar -files here will be placed on the class path.
  • -
  • /opt/vinyldns/conf/application.conf - to override default configuration settings. Follow -the Portal Configuration Guide
  • -
- -

Configuring a custom Java trustStore

- -

To add a custom Java trustStore for LDAP certs, add the trustStore to /opt/vinyldns/conf/trustStore.jks. Then -add -Djavax.net.ssl.trustStore=/opt/vinyldns/conf/trustStore.jks to the JVM_OPTS environment variable for the -container.

- -

Example:

- -
docker run -e JVM_OPTS="-Djavax.net.ssl.trustStore=/opt/vinyldns/conf/trustStore.jks" ...
-
- -

Additional JVM parameters

- -

Additional JVM parameters can be added to the JVM_OPTS environment variable

-
\ No newline at end of file diff --git a/operator/setup-sqs.html b/operator/setup-sqs.html deleted file mode 100644 index f70883549..000000000 --- a/operator/setup-sqs.html +++ /dev/null @@ -1,51 +0,0 @@ -VinylDNS: Setup AWS SQS

Setup AWS SQS

-

SQS is used to provide high-availability and failover in the event that a node crashes mid-stream while processing a message. -The backend processing for VinylDNS is built to be idempotent so changes can be fully re-applied. The SQS queue -also provides a mechanism to throttle updates, in the event that an out-of-control client submits thousands or -millions of concurrent requests, they will all be throttled through SQS.

- -

You must setup an SQS queue before you can start working with VinylDNS. An AWS SQS Getting Started Guide -provides the information you need to setup your queue.

- -

Setting up AWS SQS

-

As opposed to MySQL where everything is created when the application starts up, the SQS queue needs to be setup by hand. -This section goes through those settings that are required.

- -

The traffic with AWS SQS is rather low. Presently, Comcast operates multiple SQS queues across multiple environments (dev, staging, prod), -and incur a cost of less than $10 USD per month. SQS allows up to 1MM requests per month in the free tier. It is possible -to operate VinylDNS entirely in the “free” tier. You can “tune down” your usage by increasing your polling interval.

- -

The following SQS Queue Attributes are recommended (these are in AWS when you create an SQS Queue):

- -
    -
  • Queue Type - Standard
  • -
  • Delivery Delay - 0 seconds
  • -
  • Default Visibility Timeout - 1 minute (how long it takes a record change to complete, usually a second)
  • -
  • Message Retention Period - 4 days
  • -
  • Maximum Message Size - 256KB
  • -
  • Receive Message Wait Time - 0 seconds
  • -
  • Maximum Receives - 100 (how many times a message will be retried before failing. Note: if any messages retry more than 100 times, there is likely a problem requiring immediate attention)
  • -
  • Dead Letter Queue - use a dead letter queue for all queues
  • -
- -

Configuring SQS

-

Before you can configure SQS, make note of the AWS account (access key and secret access key) as well as the -SQS Queue Url that you will be using. Follow the SQS Configuration to complete the setup.

-
\ No newline at end of file diff --git a/portal/access.html b/portal/access.html deleted file mode 100644 index ecaa25d1d..000000000 --- a/portal/access.html +++ /dev/null @@ -1,29 +0,0 @@ -VinylDNS: Access the Portal

Access the portal

- -

Login

-

The login page is where you provide your account username and password to access VinylDNS. The URL to access VinylDNS varies by instance. Check with your VinylDNS administrators for login information.

- -

Login screen

- -

Logout

-

To logout of VinylDNS select your username in the top right of the portal to reveal the dropdown menu containing the Logout link.

- -

Logout link

-
\ No newline at end of file diff --git a/portal/connect-to-zone.html b/portal/connect-to-zone.html deleted file mode 100644 index 17098da1f..000000000 --- a/portal/connect-to-zone.html +++ /dev/null @@ -1,36 +0,0 @@ -VinylDNS: Connect to your Zone

Connect to your Zone

-

Once your zone is setup for use with VinylDNS, you can use the VinylDNS portal to connect to it.

- -
    -
  1. If you don’t already have an admin group in VinylDNS for your zone select the Groups link in the navigation and create an admin group for your zone. Members of the group will have full access to the zone. See Manage Access for more details.
  2. -
  3. Select the Zones link from the navigation, then click the Connect button. This will show the Connect to a Zone - form. Zones main screenshot Connect to zone form screenshot
  4. -
  5. Enter the full name of the zone, example “test.sys.example.com”
  6. -
  7. Enter the email distribution list for the zone. This is typically a distribution list - email for the team that owns the zone.
  8. -
  9. Select the admin group for the zone.
  10. -
  11. If you do not have any custom TSIG keys, you can leave the connection information empty.
  12. -
  13. If you do have custom TSIG keys, read the section on Understand Connections.
  14. -
  15. Click the Connect button at the bottom of the form.
  16. -
  17. You may have to click the Refresh button from the zone list to see your new zone. -Created zone listed screenshot
  18. -
  19. If you see error messages, please consult the FAQ.
  20. -
-
\ No newline at end of file diff --git a/portal/connections.html b/portal/connections.html deleted file mode 100644 index 6814f5174..000000000 --- a/portal/connections.html +++ /dev/null @@ -1,38 +0,0 @@ -VinylDNS: Understand Connections

Understand Connections

-

VinylDNS provides the ability to specify two different connections to the backend DNS servers.

- -
    -
  • The primary connection is used for issuing DNS updates
  • -
  • The transfer connection is used for syncing DNS data with VinylDNS
  • -
- -

If you do not have any keys, then you can leave this information empty. VinylDNS will -assume a set of default keys that should provide the access VinylDNS needs to manage -your zone.

- -

If you have an existing TSIG key that you are using for issuing DDNS updates to DNS, -and you wish to continue to use it, you must request that your zone be setup to -allow transfers from VinylDNS. Note: If you make any changes outside of VinylDNS they will not be reflected in VinylDNS unless you manually sync the zone.

- -

If you have an existing TSIG key that you are using for issuing DDNS updates, -and you no longer need the key, please contact your VinylDNS administrators to ensure that the key is revoked and the zone is setup with the default VinylDNS TSIG key. Once -your key is revoked, you can leave the connections empty in which case VinylDNS -will assume the default keys and they should work.

-
\ No newline at end of file diff --git a/portal/create-a-group.html b/portal/create-a-group.html deleted file mode 100644 index 16334999b..000000000 --- a/portal/create-a-group.html +++ /dev/null @@ -1,30 +0,0 @@ -VinylDNS: Create a Group

Create a group

-
    -
  1. In the Groups area of the site select the New Group button. This will bring up a form.
  2. -
  3. Enter a name for the group, email address and an optional description.
  4. -
  5. Select the Create button to submit the group information.
  6. -
  7. If all fields are valid you’ll see the group listed in the table on the screen when the form closes.
  8. -
- -

Groups main screenshot -Groups form screenshot -Created group listed in "My Groups" tab screenshot -Created group listed in "All Groups" tab screenshot

-
\ No newline at end of file diff --git a/portal/credentials.html b/portal/credentials.html deleted file mode 100644 index 23c55f750..000000000 --- a/portal/credentials.html +++ /dev/null @@ -1,28 +0,0 @@ -VinylDNS: Credentials

Credentials

-

In order to use tooling to access VinylDNS, all users must download their credentials from the VinylDNS -portal. The credentials are located in the User Menu in the top right corner of the site after login.

- -

Regenerate Credentials

-

If your credentials are compromised you can generate new ones. In the User Menu select Regenerate Credentials. -Regenerating your credentials will invalidate your previous credentials. If you are using any VinylDNS tools beyond the -portal you can then select Download Credentials to retrieve your new credentials and update the tools you use.

- -

User credentials

-
\ No newline at end of file diff --git a/portal/dns-changes.html b/portal/dns-changes.html deleted file mode 100644 index 59a98f655..000000000 --- a/portal/dns-changes.html +++ /dev/null @@ -1,86 +0,0 @@ -VinylDNS: DNS Changes

DNS Changes

-

DNS Changes is an alternative to submitting individual RecordSet changes and provides the following:

- -
    -
  • The ability to include records of multiple record types across multiple zones.
  • -
  • Input names are entered as fully-qualified domain names (or IP addresses for PTR records), so users don’t have to think in record/zone context.
  • -
- -

Note: DNS Change is portal-only terminology. The API equivalent is batch change.

- -

Access

-
    -
  • Access permissions will follow existing rules (admin group or ACL access). Note that an update (delete and add of the same record name or delete of single entry of multi-record DNS record set, zone and record type combination) requires Write or Delete access.
  • -
  • Records in shared zones. All users are permitted to create new records or update unowned records in shared zones.
  • -
- -

Supported record types

-
    -
  • Current supported record types for DNS change are: A, AAAA, CNAME, PTR, TXT, and MX.
  • -
  • Additionally, there are A+PTR and AAAA+PTR types that will be processed as separate A (or AAAA) and PTR changes in the VinylDNS backend. Deletes for A+PTR and AAAA+PTR require Input Name and Record Data.
  • -
  • Supported record types for records in shared zones may vary. -Contact your VinylDNS administrators to find the allowed record types. -This does not apply to zone administrators or users with specific ACL access rules.
  • -
- -

Requirements

-
    -
  • DNS change requests must contain at least one change.
  • -
  • The maximum number of single changes within a DNS change varies by instance of VinylDNS. Contact your VinylDNS administrators to find the DNS change limit for your instance.
  • -
  • To update an existing record, you must delete the record first and add all expected records within the same request; a delete and add of the same record set within a DNS change request will be processed as an update.
  • -
  • When creating a new record in a shared zone, or updating an existing unowned record, a record owner group is required. Once the owner group is assigned only users in that group, zone admins, and users with ACL permissions can modify the record.
  • -
- -
-

Create a DNS Change

-
    -
  1. Go to the DNS Changes section of the site.
  2. -
  3. Select the New DNS Change button.
  4. -
  5. Add a description.
  6. -
  7. Add record changes in one of two ways: -
      -
    • Select the Add a Change button to add additional rows for data entry as needed.
    • -
    • Select the Import CSV button to choose and upload a CSV file of the record changes. See DNS Change CSV Import for more information.
    • -
    -
  8. -
  9. Select the submit button. Confirm your submission. -
      -
    • If your submission was successful you’ll redirect to the DNS Change summary page where you will see the status of the DNS Change request overall and of the individual records in the DNS Change.
    • -
    • If there are errors in the DNS Change you will remain on the form with prompts to correct errors before you attempt to submit again.
    • -
    -
  10. -
- -

DNS Changes main page screenshot -New DNS Change form screenshot -Submitted DNS Change screenshot

- -

DNS Change CSV Import

-

Download a sample CSV here

-
    -
  • The header row is required. The order of the columns is Change Type, Record Type, Input Name, TTL, Record Data.
  • -
  • The TTL field is optional for each record, but the column is still required. If TTL is empty VinylDNS will use the existing TTL value for record updates or the default TTL value for new records.
  • -
- -

Review a DNS Change

-

You can review your submitted DNS Change requests by selecting the linked DNS Change ID or View button for the DNS Change on the main page of the DNS Changes section in the portal.

- -

List of DNS Change requests screenshot

-
\ No newline at end of file diff --git a/portal/groups.html b/portal/groups.html deleted file mode 100644 index ab23298fe..000000000 --- a/portal/groups.html +++ /dev/null @@ -1,30 +0,0 @@ -VinylDNS: Groups

Groups

- -

Groups are the primary way users are granted access to zones. Users can create groups for two purposes in VinylDNS: to be the zone admin group for a zone or to be assigned more limited access via ACL rules. Every zone in VinylDNS must have a zone admin group assigned. VinylDNS does not currently integrate with any services to generate pre-defined zone admin groups.

- - - -

Groups main "My Groups" tab screenshot

- -

Groups main "All Groups" tab screenshot

-
\ No newline at end of file diff --git a/portal/index.html b/portal/index.html deleted file mode 100644 index 8eeab4b50..000000000 --- a/portal/index.html +++ /dev/null @@ -1,50 +0,0 @@ -VinylDNS: Portal Guide

Portal Guide

- -

The VinylDNS portal is the primary user interface for interacting with VinylDNS. Users can retrieve their credentials and manage zones, records, and user groups. This guide covers the functionality of the portal.

- - - -

Portal screenshot

- -

User Menu

-

The User Menu is located in the top right corner of the portal and accessed by selecting your username. It contains a Logout link to sign out of the portal and the Download Credentials link.

- -

Credentials

-

In order to use tooling to access VinylDNS, all users must download their credentials from the VinylDNS portal.

- -

Learn more

- -

Zones

-

The Zones section of the portal is for managing DNS zones and records. This area also includes more granular management of user abilities. -To access Zones in the portal select the Zones link in the left column navigation. -Access to individual zones in this part of the portal is limited to zone administrators and users with explicit permissions.

- -

Learn More

- -

Groups

-

The Groups section of the portal is for managing high level user access and abilities. To access Groups in the portal select the Groups link in the left column navigation.

- -

Learn More

- -

DNS Changes

-

The DNS Changes section of the portal allows users to implement multiple record changes simultaneously and across different zones. To access DNS Changes in the portal select the DNS Changes link in the left column navigation.

- -

Learn More

-
\ No newline at end of file diff --git a/portal/manage-access.html b/portal/manage-access.html deleted file mode 100644 index 2f2341f54..000000000 --- a/portal/manage-access.html +++ /dev/null @@ -1,50 +0,0 @@ -VinylDNS: Manage Access

Manage Access to Zones and Records

- -

Full Access

- -

Members of a zone admin group have full access to all records and permissions in the zone. Each zone is limited to one -admin group. Typically, this should be a limited set of users. If you wish to add other users to a group you can do so -in the Groups section of the portal.

- -

Limited Access

- -

If you don’t want a user to have full access to a zone you can use ACL rules to give them more granular access. With ACL -rules, the zone admins can grant individual users or groups read, write or delete access to all records in the zone, or -a subset of record names and/or types.

- -
    -
  1. Go to the desired zone
  2. -
  3. Select the Manage Zone tab
  4. -
  5. Select the Create ACL rule button
  6. -
  7. Fill in the form
  8. -
  9. Submit the form
  10. -
- -

ACL rule form screenshot

- -

Shared Zones

- -

The shared zone feature is designed to allow more granular record ownership and management in a flexible way. Super -users can mark zones as ‘shared’ which then allow any users to create new records or claim existing unowned records in -zones. Zone administrators can assign records in a shared zone to specific groups by designating a group when creating -the record set or when updating existing records in the portal. Users who are not zone administrators can create new -records in shared zones, or claim and modify unowned records in shared zones, through -the DNS Changes interface.

-
\ No newline at end of file diff --git a/portal/manage-membership.html b/portal/manage-membership.html deleted file mode 100644 index c260bd48a..000000000 --- a/portal/manage-membership.html +++ /dev/null @@ -1,37 +0,0 @@ -VinylDNS: Manage Membership

Manage membership

-

If you create a group in VinylDNS you are automatically made a member and group manager of the group. To manage the members of the group select the View button next to the desired group to view the Membership page.

- -

Add members:

-

In the text box over the table enter the username of the person you want to add to the group. If you want to make them a group manager check the Is Group Manager? checkbox. Select the Add Group Member button.

- -

Delete members:

-

Select the Delete button in the row of the user you wish to remove.

- -

Change managerial rights:

-

Toggle the switch under the Group Manager column in the row of the user. The switch to the right and green means the user is a group manager. If the switch is to the left and red it means the user is not an group manager.

- -

Relinquish managerial rights:

-

You can relinquish your managerial rights if there is at least one other group manager in the group. If that condition is met you can toggle the Group Manager switch for yourself.

- -

Remove yourself from a group:

-

If you wish to remove yourself entirely from a group there must be at least one other manager of the group. If that condition is met you can select the Delete button that corresponds with your username and you will be removed from the group entirely.

- -

Group membership screenshot

-
\ No newline at end of file diff --git a/portal/manage-records.html b/portal/manage-records.html deleted file mode 100644 index 60cc6fdf6..000000000 --- a/portal/manage-records.html +++ /dev/null @@ -1,58 +0,0 @@ -VinylDNS: Manage Records

Manage Records

-

There are currently two ways to manage records in the VinylDNS portal. This covers managing individual records through their associated zone. To manage multiple records at once, possibly across zones, and records in shared zones you can use the DNS Changes area of the portal.

- -

Access

-

Only zone administrators and users with ACL rules can manage records this way.

- -

Supported record types

-

A, AAAA, CNAME, DS, MX, NAPTR, NS, PTR, SRV, SSHFP, and TXT

- -
- -

To manage records in a zone go to the Zones section of the portal and select the View button that corresponds with the zone you want to manage. The Manage Records tab will be the active tab by default. Once you are in the Manage Records tab of the zone, you can create new records sets or update or delete existing record sets.

- -

Zone Records in Manage Records tab screenshot

- -

The Records pane, below the Recent Record Changes pane, lists record sets. Record sets are records that have the same -name but different record data. Not all record types support record sets.

- -

When you make any change, it will be immediately queued for processing. Typically processing happens in a second or two. You may need to select the Refresh button if you don’t see the change reflected in the portal.

- -

If for any reason the change failed, you can view the change in the Recent Record Changes pane -at the top of the screen, or look at the Change History tab to see what went wrong. -The Additional Info column will contain details of the change failure.

- -

Recent Changes section in Manage Records tab screenshot -Change History tab screenshot

- -

Record sorting and filtering

-

It is now possible to sort records in VinylDNS by record name ascending/descending order in addition to filtering the record types that will be displayed, providing more ease and control when navigating your DNS records. -To change the sort order for record name, click on the Name header in the Records table to toggle between ascending and descending order. -To filter record types, click on the Filter By Record Type link to reveal the record type options and adjust your selection.

- -

Sort records screenshot

- -

When searching for a record name using the search bar, exact matches are returned; however it is possible to use * to fuzzy match on desired patterns (e.g. foo* will match foo and foobar).

- -

Sync Zones

-

If you make changes to the records in a zone outside of VinylDNS you must manually sync the zone so VinylDNS is aware of those records. Use the Sync Zone button in the Records pane.

- -

Sync zones screenshot

-
\ No newline at end of file diff --git a/portal/manual-review-scheduling.html b/portal/manual-review-scheduling.html deleted file mode 100644 index 65d330bcf..000000000 --- a/portal/manual-review-scheduling.html +++ /dev/null @@ -1,78 +0,0 @@ -VinylDNS: Manual Review & Scheduling

DNS Changes: Manual Review & Scheduling

- -

Configuration Note: DNS Change manual review and scheduling are configured features in VinylDNS. Check with your VinylDNS administrators to determine if they are enabled in your instance.**

- - - -

Manual Review

- -

If a DNS Change is submitted with only non-fatal errors you will be notified to either correct those errors or submit your DNS Change for manual review. -If you submit the DNS Change for manual review a VinylDNS administrator will determine if your request can be approved or if it needs to be rejected. -After the review your DNS Change will include the review details, including the review status, reviewer name, review time and review comment, if provided.

- -

New DNS Change form with non-fatal errors

- -

New DNS Change reviewed

- -

Scheduling

- -

VinylDNS processes DNS Changes immediately, unless they have a Request Date and Time. The day and time must be in the future. The portal accepts and returns the Request Date and Time as your local time. -A VinylDNS administrator will review the DNS Change after the requested time and either approve or reject it for processing. -New DNS Change form with scheduling field

- -

Filter by Open Requests

- -

If you have many DNS Changes you may find it helpful to filter your list of requests by those that are currently open. -In the top right corner of the DNS Changes table is a checkbox labeled “View Open Requests Only”. If the checkbox is selected the DNS Changes list will be limited to only Pending Review and Scheduled DNS Changes.

- -

DNS Changes listed filtered by open requests

- -

Cancelling DNS Changes

- -

Users can cancel any DNS Change they create if it has a review status of “Pending Review”. Either select the “Cancel” button in the main DNS Changes list or the “Cancel” button in the DNS Change Detail page. A modal will appear for the user to confirm the cancellation.

- -

DNS Change cancel prompt

- -

Cancelled DNS Change

- -

Reviewing Pending DNS Changes

- -

VinylDNS administrators can use the portal to review DNS Changes.

- -

In the DNS Changes view there are two tabs, “My Requests” and “All Requests”. “My Requests” are only your own DNS Changes. -“All Requests” are requests by everyone in the VinylDNS instance. Both tabs can be filtered by open requests.

- -

DNS Changes admin view

- -

On the detail page for a DNS change that is pending review, administrators will see a review section beneath the list of single changes. -The administrator can provide a comment, then choose Approve or Reject and finally confirm their choice. -If the DNS Change is approved and there are no new errors or it’s rejected then the review is completed and the DNS Change status and review information is updated. -If the DNS Change still has errors after the approval attempt, the page will display the new errors and the administrator needs to address those or reject the DNS change.

- -

DNS Change detail page with review section

- -

DNS Change with errors after approval attempt

-
\ No newline at end of file diff --git a/portal/recordset-search.html b/portal/recordset-search.html deleted file mode 100644 index d71adc3f8..000000000 --- a/portal/recordset-search.html +++ /dev/null @@ -1,33 +0,0 @@ -VinylDNS: RecordSet Search
-

RecordSet Search provides a view to lookup the state of DNS records within VinylDNS without requiring -access to the specific zone. To use the search, a search term containing at least two alphanumeric characters must -be entered.

- -

RecordSet Search main page screenshot -RecordSet Search name filter screenshot

- -

Record type and/or record owner group to further filter the search results.

- -

RecordSet Search filters screenshot

- -

There is also a collapsible help section that provides further information regarding search querying tips.

- -

RecordSet Search info screenshot

-
\ No newline at end of file diff --git a/portal/search-zones.html b/portal/search-zones.html deleted file mode 100644 index 0be4f9f52..000000000 --- a/portal/search-zones.html +++ /dev/null @@ -1,37 +0,0 @@ -VinylDNS: Search Zones

Search Zones

- -

The search box on the Zones page is designed to search on the zone name. It will search the “My Zones” and “All Zones” tabs simultaneously. -For partial name matching use * in the search term. -Without * the search will be run for exact zone names. The trailing . is accounted for whether it’s in the search term or not.

- -

Examples:

- -

Given a list of zone names: another.example.com., example.com., test.com., test.net., xyz.efg.

- -

Search test returns: No Zones -Search test.com returns: test.com. -Search test* returns: test.com., test.net. -Search *example returns: example.com., another.example.com. -Search *e* returns: another.example.com., example.com., test.com., test.net., xyz.efg.

- -

Search zones My Zones tab

- -

Search zones All Zones tab

-
\ No newline at end of file diff --git a/portal/zones.html b/portal/zones.html deleted file mode 100644 index 090b68b94..000000000 --- a/portal/zones.html +++ /dev/null @@ -1,40 +0,0 @@ -VinylDNS: Zones

Zones

- -

The My Zones tab lists zones you have access to (through ownership or ACL rules). -The list contains links to the individual zone pages where you can manage the zone, it’s records and ACL access.

- -

The All Zones tab is intended as a reference, it includes zones you have access to as well as all other private and shared zones in VinylDNS. -If needed, you can use the contact information in the list to reach out to the owners of the zones you don’t have access to.

- -

Note you may have access to specific records in shared zones, but you are not permitted to access those zones in this area. -Those records are accessible via the DNS Changes area of the portal.

- - - -

Zones page - My Zones tab

- -

Zones page - All Zones tab

-
\ No newline at end of file diff --git a/static/dns-changes-csv-sample.csv b/static/dns-changes-csv-sample.csv deleted file mode 100644 index 426c23a43..000000000 --- a/static/dns-changes-csv-sample.csv +++ /dev/null @@ -1,14 +0,0 @@ -Change Type,Record Type,Input Name,TTL,Record Data -Add,A+PTR,test.example.,7200,1.1.1.1 -Add,A,test1.example.,7200,1.2.3.4 -Add,AAAA+PTR,test2.example.,200,fd69:27cc:fe91::60 -Add,AAAA,test3.example.com.,,fd69:27cc:fe91::60 -Add,CNAME,test4.example.com.,,test0.example.com. -Add,PTR,192.0.2.193,200,test.example.com. -Add,TXT,test5.example.com,7200,example text -DeleteRecordSet,A+PTR,test5.example.com.,,1.1.1.1 -DeleteRecordSet,A,test6.exmaple.com.,, -DeleteRecordSet,AAAA+PTR,test7.example.com.,,fd69:27cc:fe91::60 -DeleteRecordSet,CNAME,test8.example.com.,, -DeleteRecordSet,PTR,193.0.2.192,, -DeleteRecordSet,TXT,test5.example.com,,