deckhand/doc/design.md

32 KiB

Deckhand Design

Purpose

Deckhand is a document-based configuration storage service built with auditability and validation in mind.

Essential Functionality

  • layering - helps reduce duplication in configuration while maintaining auditability across many sites
  • substitution - provides separation between secret data and other configuration data, while allowing a simple interface for clients
  • revision history - improves auditability and enables services to provide functional validation of a well-defined collection of documents that are meant to operate together
  • validation - allows services to implement and register different kinds of validations and report errors

Documents

All configuration data is stored entirely as structured documents, for which schemas must be registered.

Document Format

The document format is modeled loosely after Kubernetes practices. The top level of each document is a dictionary with 3 keys: schema, metadata, and data.

  • schema - Defines the name of the JSON schema to be used for validation. Must have the form: <namespace>/<kind>/<version>, where the meaning of each component is:
    • namespace - Identifies the owner of this type of document. The values deckhand and metadata are reserved for internal use.
    • kind - Identifies a type of configuration resource in the namespace.
    • version - Describe the version of this resource, e.g. "v1".
  • metadata - Defines details that Deckhand will inspect and understand. There are multiple schemas for this section as discussed below. All the various types of metadata include a name field which must be unique for each document schema.
  • data - Data to be validated by the schema described by the schema field. Deckhand only interacts with content here as instructed to do so by the metadata section. The form of this section is considered to be completely owned by the namespace in the schema.

Document Metadata

There are 2 supported kinds of document metadata. Documents with Document metadata are the most common, and are used for normal configuration data. Documents with Control metadata are used to customize the behavior of Deckhand.

schema: metadata/Document/v1

This type of metadata allows the following metadata hierarchy:

  • name - string, required - Unique within a revision for a given schema.
  • storagePolicy - string, required - Either cleartext or encrypted. If encyrpted is specified, then the data section of the document will be stored in an secure backend (likely via OpenStack Barbican). metadata and schema fields are always stored in cleartext.
  • layeringDefinition - dict, required - Specifies layering details. See the Layering section below for details.
    • abstract - boolean, required - An abstract document is not expected to pass schema validation after layering and substitution are applied. Non-abstract (concrete) documents are.
    • layer - string, required - References a layer in the LayeringPolicy control document.
    • parentSelector - labels, optional - Used to construct document chains for executing merges.
    • actions - list, optional - A sequence of actions to apply this documents data during the merge process.
      • method - string, required - How to layer this content.
      • path - string, required - What content in this document to layer onto parent content.
  • substitutions - list, optional - A sequence of substitutions to apply. See the Substitutions section for additional details.
    • dest - dict, required - A description of the inserted content destination.
      • path - string, required - The JSON path where the data will be placed into the data section of this document.
      • pattern - string, optional - A regex to search for in the string specified at path in this document and replace with the source data.
    • src - dict, required - A description of the inserted content source.
      • schema - string, required - The schema of the source document.
      • name - string, required - The metadata.name of the source document.
      • path - string, required - The JSON path from which to extract data in the source document relative to its data section.

Here is a fictitious example of a complete document which illustrates all the valid fields in the metadata section.

---
schema: some-service/ResourceType/v1
metadata:
  schema: metadata/Document/v1
  name: unique-name-given-schema
  storagePolicy: cleartext
  labels:
    genesis: enabled
    master: enabled
  layeringDefinition:
    abstract: true
    layer: region
    parentSelector:
      required_key_a: required_label_a
      required_key_b: required_label_b
    actions:
      - method: merge
        path: .path.to.merge.into.parent
      - method: delete
        path: .path.to.delete
  substitutions:
    - dest:
        path: .substitution.target
      src:
        schema: another-service/SourceType/v1
        name: name-of-source-document
        path: .source.path
data:
  path:
    to:
      merge:
        into:
          parent:
            foo: bar
          ignored:  # Will not be part of the resultant document after layering.
            data: here
  substitution:
    target: null  # Paths do not need to exist to be specified as substitution destinations.
...
schema: metadata/Control/v1

This schema is the same as the Document schema, except it omits the storagePolicy, layeringDefinition, and substitutions keys, as these actions are not supported on Control documents.

The complete list of valid Control document kinds is specified below along with descriptions of each document kind.

Layering

Layering provides a restricted data inheritance model intended to help reduce duplication in configuration. Documents with different schemas are never layered together (see the Substitution section if you need to combine data from multiple types of documents).

Layering is controlled in two places:

  1. The LayeringPolicy control document (described below), which defines the valid layers and their order of precedence.
  2. In the metadata.layeringDefinition section of normal (metadata.schema=metadata/Document/v1) documents.

When rendering a particular document, you resolve the chain of parents upward through the layers, and begin working back down each layer rendering at each document in the chain.

When rendering each layer, the parent document is used as the starting point, so the entire contents of the parent are brought forward. Then the list of actions will be applied in order. Supported actions are:

  • merge - "deep" merge child data at the specified path into the existing data
  • replace - overwrite existing data with child data at the specified path
  • delete - remove the existing data at the specified path

After actions are applied for a given layer, substitutions are applied (see the Substitution section for details).

Selection of document parents is controlled by the parentSelector field and works as follows. A given document, C, that specifies a parentSelector will have exactly one parent, P. Document P will be the highest precedence (i.e. part of the lowest layer defined in the layerOrder list from the LayeringPolicy) document that has the labels indicated by the parentSelector (and possibly additional labels) from the set of all documents of the same schema as C that are in layers above the layer C is in. For example, consider the following sample documents:

---
schema: deckhand/LayeringPolicy/v1
metadata:
  schema: metadata/Control/v1
  name: layering-policy
data:
  layerOrder:
    - global
    - region
    - site
---
schema: example/Kind/v1
metadata:
  schema: metadata/Document/v1
  name: global-1234
  labels:
    key1: value1
  layeringDefinition:
    abstract: true
    layer: global
data:
  a:
    x: 1
    y: 2
---
schema: example/Kind/v1
metadata:
  schema: metadata/Document/v1
  name: region-1234
  labels:
    key1: value1
  layeringDefinition:
    abstract: true
    layer: region
    parentSelector:
      key1: value1
    actions:
      - method: replace
        path: .a
data:
  a:
    z: 3
---
schema: example/Kind/v1
metadata:
  schema: metadata/Document/v1
  name: site-1234
  layeringDefinition:
    layer: site
    parentSelector:
      key1: value1
    actions:
      - method: merge
        path: .
data:
  b: 4
...

When rendering, the parent chosen for site-1234 will be region-1234, since it is the highest precedence document that matches the label selector defined by parentSelector, and the parent chosen for region-1234 will be global-1234 for the same reason. The rendered result for site-1234 would be:

---
schema: example/Kind/v1
metadata:
  name: site-1234
data:
  a:
    z: 3
  b: 4
...

If region-1234 were later removed, then the parent chosen for site-1234 would become global-1234, and the rendered result would become:

---
schema: example/Kind/v1
metadata:
  name: site-1234
data:
  a:
    x: 1
    y: 2
  b: 4
...

Substitution

Substitution is primarily designed as a mechanism for inserting secrets into configuration documents, but works for unencrypted source documents as well. Substitution is applied at each layer after all merge actions occur.

Concrete (non-abstract) documents can be used as a source of substitution into other documents. This substitution is layer-independent, so given the 3 layer example above, which includes global, region and site layers, a document in the region layer could insert data from a document in the site layer.

Here is a sample set of documents demonstrating subistution:

---
schema: deckhand/Certificate/v1
metadata:
  name: example-cert
  storagePolicy: cleartext
  layeringDefinition:
    layer: site
data: |
  CERTIFICATE DATA  
---
schema: deckhand/CertificateKey/v1
metadata:
  name: example-key
  storagePolicy: encrypted
  layeringDefinition:
    layer: site
data: |
  KEY DATA  
---
schema: deckhand/Passphrase/v1
metadata:
  name: example-password
  storagePolicy: encrypted
  layeringDefinition:
    layer: site
data: my-secret-password
---
schema: armada/Chart/v1
metadata:
  name: example-chart-01
  storagePolicy: cleartext
  layeringDefinition:
    layer: region
  substitutions:
    - dest:
        path: .chart.values.tls.certificate
      src:
        schema: deckhand/Certificate/v1
        name: example-cert
        path: .
    - dest:
        path: .chart.values.tls.key
      src:
        schema: deckhand/CertificateKey/v1
        name: example-key
        path: .
    - dest:
        path: .chart.values.some_url
        pattern: INSERT_[A-Z]+_HERE
      src:
        schema: deckhand/Passphrase/v1
        name: example-password
        path: .
data:
  chart:
    details:
      data: here
    values:
      some_url: http://admin:INSERT_PASSWORD_HERE@service-name:8080/v1
...

The rendered document will look like:

---
schema: armada/Chart/v1
metadata:
  name: example-chart-01
  storagePolicy: cleartext
  layeringDefinition:
    layer: region
  substitutions:
    - dest:
        path: .chart.values.tls.certificate
      src:
        schema: deckhand/Certificate/v1
        name: example-cert
        path: .
    - dest:
        path: .chart.values.tls.key
      src:
        schema: deckhand/CertificateKey/v1
        name: example-key
        path: .
    - dest:
        path: .chart.values.some_url
        pattern: INSERT_[A-Z]+_HERE
      src:
        schema: deckhand/Passphrase/v1
        name: example-password
        path: .
data:
  chart:
    details:
      data: here
    values:
      some_url: http://admin:my-secret-password@service-name:8080/v1
      tls:
        certificate: |
          CERTIFICATE DATA          
        key: |
          KEY DATA          
...

Control Documents

Control documents (documents which have metadata.schema=metadata/Control/v1), are special, and are used to control the behavior of Deckhand at runtime. Only the following types of control documents are allowed.

DataSchema

DataSchema documents are used by various services to register new schemas that Deckhand can use for validation. No DataSchema documents with names beginning with deckhand/ or metadata/ are allowed. Tme metadata.name field of each DataSchema document specifies the top level schema that it is used to validate.

The contents of its data key are expected to be the json schema definition for the target document type from the target's top level data key down.

---
schema: deckhand/DataSchema/v1  # This specifies the official JSON schema meta-schema.
metadata:
  schema: metadata/Control/v1
  name: promenade/Node/v1  # Specifies the documents to be used for validation.
  labels:
    application: promenade
data:  # Valid JSON Schema is expected here.
  $schema: http://blah
...

LayeringPolicy

Only one LayeringPolicy document can exist within the system at any time. It is an error to attempt to insert a new LayeringPolicy document if it has a different metadata.name than the existing document. If the names match, it is treated as an update to the existing document.

This document defines the strict order in which documents are merged together from their component parts. It should result in a validation error if a document refers to a layer not specified in the LayeringPolicy.

---
schema: deckhand/LayeringPolicy/v1
metadata:
  schema: metadata/Control/v1
  name: layering-policy
data:
  layerOrder:
    - global
    - site-type
    - region
    - site
    - force
...

ValidationPolicy

Unlike LayeringPolicy, many ValidationPolicy documents are allowed. This allows services to check whether a particular revision (described below) of documents meets a configurable set of validations without having to know up front the complete list of validations.

Each validation name specified here is a reference to data that is postable by other services. Names beginning with deckhand are reserved for internal use. See the Validation section below for more details.

Since validations may indicate interactions with external and changing circumstances, an optional expiresAfter key may be specified for each validation as an ISO8601 duration. If no expiresAfter is specified, a successful validation does not expire. Note that expirations are specific to the combination of ValidationPolicy and validation, not to each validation by itself.

---
schema: deckhand/ValidationPolicy/v1
metadata:
  schema: metadata/Control/v1
  name: site-deploy-ready
data:
  validations:
    - name: deckhand-schema-validation
    - name: drydock-site-validation
      expiresAfter: P1W
    - name: promenade-site-validation
      expiresAfter: P1W
    - name: armada-deployability-validation
...

Provided Utility Document Kinds

These are documents that use the Document metadata schema, but live in the deckhand namespace.

Certificate

---
schema: deckhand/Certificate/v1
metadata:
  schema: metadata/Document/v1
  name: application-api
  storagePolicy: cleartext
data: |-
  -----BEGIN CERTIFICATE-----
  MIIDYDCCAkigAwIBAgIUKG41PW4VtiphzASAMY4/3hL8OtAwDQYJKoZIhvcNAQEL
  ...snip...
  P3WT9CfFARnsw2nKjnglQcwKkKLYip0WY2wh3FE7nrQZP6xKNaSRlh6p2pCGwwwH
  HkvVwA==
  -----END CERTIFICATE-----  
...

CertificateKey

---
schema: deckhand/CertificateKey/v1
metadata:
  schema: metadata/Document/v1
  name: application-api
  storagePolicy: encrypted
data: |-
  -----BEGIN RSA PRIVATE KEY-----
  MIIEpQIBAAKCAQEAx+m1+ao7uTVEs+I/Sie9YsXL0B9mOXFlzEdHX8P8x4nx78/T
  ...snip...
  Zf3ykIG8l71pIs4TGsPlnyeO6LzCWP5WRSh+BHnyXXjzx/uxMOpQ/6I=
  -----END RSA PRIVATE KEY-----  
...

Passphrase

---
schema: deckhand/Passphrase/v1
metadata:
  schema: metadata/Document/v1
  name: application-admin-password
  storagePolicy: encrypted
data: some-password
...

Buckets

Collections of documents, called buckets, are managed together. All documents belong to a bucket and all documents that are part of a bucket must be fully specified together.

To create or update a new document in, e.g. bucket mop, one must PUT the entire set of documents already in mop along with the new or modified document. Any documents not included in that PUT will be automatically deleted in the created revision.

This feature allows the separation of concerns when delivering different categories of documents, while making the delivered payload more declarative.

Revision History

Documents will be ingested in batches which will be given a revision index. This provides a common language for describing complex validations on sets of documents.

Revisions can be thought of as commits in a linear git history, thus looking at a revision includes all content from previous revisions.

Validation

The validation system provides a unified approach to complex validations that require coordination of multiple documents and business logic that resides in consumer services.

Services can report success or failure of named validations for a given revision. Those validations can then be referenced by many ValidationPolicy control documents. The intended purpose use is to allow a simple mapping that enables consuming services to be able to quickly check whether the configuration in Deckhand is in a valid state for performing a specific action.

Deckhand-Provided Validations

In addition to allowing 3rd party services to report configurable validation statuses, Deckhand provides a few internal validations which are made available immediately upon document ingestion.

Here is a list of internal validations:

  • deckhand-document-schema-validation - All concrete documents in the revision successfully pass their JSON schema validations. Will cause this to report an error.
  • deckhand-policy-validation - All required policy documents are in-place, and existing documents conform to those policies. E.g. if a 3rd party document specifies a layer that is not present in the layering policy, that will cause this validation to report an error.

Access Control

Deckhand will use standard OpenStack Role Based Access Control using the following actions:

  • purge_database - Remove all documents and revisions from the database.
  • read_cleartext_document - Read unencrypted documents.
  • read_encrypted_document - Read (including substitution and layering) encrypted documents.
  • read_revision - Read details about revisions.
  • read_validation - Read validation policy status, and validation results, including error messages.
  • write_cleartext_document - Create, update or delete unencrypted documents.
  • write_encrypted_document - Create, update or delete encrypted documents.
  • write_validation - Write validation results.

API

This API will only support YAML as a serialization format. Since the IETF does not provide an official media type for YAML, this API will use application/x-yaml.

This is a description of the v1.0 API. Documented paths are considered relative to /api/v1.0.

PUT /bucket/{bucket_name}/documents

Accepts a multi-document YAML body and creates a new revision that updates the contents of the bucket_name bucket. Documents from the specified bucket that exist in previous revisions, but are absent from the request are removed from that revision (though still accessible via older revisions).

Documents in other buckets are not changed and will be included in queries for documents of the newly created revision.

Updates are detected based on exact match to an existing document of schema + metadata.name. It is an error that responds with 409 Conflict to attempt to PUT a document with the same schema + metadata.name as an existing document from a different bucket in the most-recent revision.

This endpoint is the only way to add, update, and delete documents. This triggers Deckhand's internal schema validations for all documents.

If no changes are detected, a new revision should not be created. This allows services to periodically re-register their schemas without creating unnecessary revisions.

This endpoint uses the write_cleartext_document and write_encrypted_document actions.

GET /revisions/{revision_id}/documents

Returns a multi-document YAML response containing all the documents matching the filters specified via query string parameters. Returned documents will be as originally added with no substitutions or layering applied.

Supported query string parameters:

  • schema - string, optional - The top-level schema field to select. This may be partially specified by section, e.g., schema=promenade would select all kind and version schemas owned by promenade, or schema=promenade/Node which would select all versions of promenade/Node documents. One may not partially specify the namespace or kind, so schema=promenade/No would not select promenade/Node/v1 documents, and schema=prom would not select promenade documents.
  • metadata.name - string, optional
  • metadata.layeringDefinition.abstract - string, optional - Valid values are the "true" and "false".
  • metadata.layeringDefinition.layer - string, optional - Only return documents from the specified layer.
  • metadata.label - string, optional, repeatable - Uses the format metadata.label=key=value. Repeating this parameter indicates all requested labels must apply (AND not OR).
  • sort - string, optional, repeatable - Defines the sort order for returning results. Default is by creation date. Repeating this parameter indicates use of multi-column sort with the most significant sorting column applied first.
  • status.bucket - string, optional, repeatable - Used to select documents only from a particular bucket. Repeating this parameter indicates documents from any of the specified buckets should be returned.

This endpoint uses the read_cleartext_document and read_encrypted_document actions.

GET /revisions/{revision_id}/rendered-documents

Returns a multi-document YAML of fully layered and substituted documents. No abstract documents will be returned. This is the primary endpoint that consumers will interact with for their configuration.

Valid query parameters are the same as for /revisions/{revision_id}/documents, minus the paremters in metadata.layeringDetinition, which are not supported.

This endpoint uses the read_cleartext_document and read_encrypted_document actions.

GET /revisions

Lists existing revisions and reports basic details including a summary of validation status for each deckhand/ValidationPolicy that is part of that revision.

Supported query string parameters:

  • tag - string, optional, repeatable - Used to select revisions that have been tagged with particular tags.

Sample response:

---
count: 7
next: https://deckhand/api/v1.0/revisions?limit=2&offset=2
prev: null
results:
  - id: 1
    url: https://deckhand/api/v1.0/revisions/1
    createdAt: 2017-07-14T21:23Z
    buckets: [mop]
    tags: [a, b, c]
    validationPolicies:
      site-deploy-validation:
        status: failed
  - id: 2
    url: https://deckhand/api/v1.0/revisions/2
    createdAt: 2017-07-16T01:15Z
    buckets: [flop, mop]
    tags: [b]
    validationPolicies:
      site-deploy-validation:
        status: succeeded
...

This endpoint uses the read_revision action.

DELETE /revisions

Permanently delete all documents. This removes all revisions and resets the data store.

This endpoint uses the purge_database action.

GET /revisions/{{revision_id}}

Get a detailed description of a particular revision. The status of each ValidationPolicy belonging to the revision is also included. Valid values for the status of each validation policy are:

  • succeded - All validations associated with the policy are success.
  • failed - Any validation associated with the policy has status failed, expired or missing.

Sample response:

---
id: 1
url: https://deckhand/api/v1.0/revisions/1
createdAt: 2017-07-14T021:23Z
buckets: [mop]
tags:
  a:
    name: a
    url: https://deckhand/api/v1.0/revisions/1/tags/a
validationPolicies:
  site-deploy-validation:
    url: https://deckhand/api/v1.0/revisions/1/documents?schema=deckhand/ValidationPolicy/v1&name=site-deploy-validation
    status: failed
    validations:
      - name: deckhand-schema-validation
        url: https://deckhand/api/v1.0/revisions/1/validations/deckhand-schema-validation/0
        status: success
      - name: drydock-site-validation
        status: missing
      - name: promenade-site-validation
        url: https://deckhand/api/v1.0/revisions/1/validations/promenade-site-validation/0
        status: expired
      - name: armada-deployability-validation
        url: https://deckhand/api/v1.0/revisions/1/validations/armada-deployability-validation/0
        status: failed
...

Validation status is always for the most recent entry for a given validation. A status of missing indicates that no entries have been created. A status of expired indicates that the validation had succeeded, but the expiresAfter limit specified in the ValidationPolicy has been exceeded.

This endpoint uses the read_revision action.

GET /revisions/{{revision_id}}/diff/{{comparison_revision_id}}

This endpoint provides a basic comparison of revisions in terms of how the buckets involved have changed. Only buckets with existing documents in either of the two revisions in question will be reported; buckets with documents that are only present in revisions between the two being compared are omitted from this report. That is, buckets with documents that were accidentally created (and then deleted to rectify the mistake) that are not directly present in the two revisions being compared are omitted.

The response will contain a status of created, deleted, modified, or unmodified for each bucket.

The ordering of the two revision ids is not important.

For the purposes of diffing, the revision_id "0" is treated as a revision with no documents, so queries comparing revision "0" to any other revision will report "created" for each bucket in the compared revision.

Diffing a revision against itself will respond with the each of the buckets in the revision as unmodified.

Diffing revision "0" against itself results in an empty dictionary as the response.

Examples

A response for a typical case, GET /api/v1.0/revisions/6/diff/3 (or equivalently GET /api/v1.0/revisions/3/diff/6).

---
bucket_a: created
bucket_b: deleted
bucket_c: modified
bucket_d: unmodified
...

A response for diffing against an empty revision, GET /api/v1.0/revisions/0/diff/6:

---
bucket_a: created
bucket_c: created
bucket_d: created
...

A response for diffing a revision against itself, GET /api/v1.0/revisions/6/diff/6:

---
bucket_a: unmodified
bucket_c: unmodified
bucket_d: unmodified
...

Diffing two revisions that contain the same documents, GET /api/v1.0/revisions/8/diff/11:

---
bucket_e: unmodified
bucket_f: unmodified
bucket_d: unmodified
...

Diffing revision zero with itself, GET /api/v1.0/revisions/0/diff/0:

---
{}
...

POST /revisions/{{revision_id}}/validations/{{name}}

Add the results of a validation for a particular revision.

An example POST request body indicating validation success:

---
status: succeeded
validator:
  name: promenade
  version: 1.1.2
...

An example POST request indicating validation failure:

POST /api/v1.0/revisions/3/validations/promenade-site-validation
Content-Type: application/x-yaml

---
status: failed
errors:
  - documents:
      - schema: promenade/Node/v1
        name: node-document-name
      - schema: promenade/Masters/v1
        name: kubernetes-masters
    message: Node has master role, but not included in cluster masters list.
validator:
  name: promenade
  version: 1.1.2
...

This endpoint uses the write_validation action.

GET /revisions/{{revision_id}}/validations

Gets the list of validations which have been reported for this revision.

Sample response:

---
count: 2
next: null
prev: null
results:
  - name: deckhand-schema-validation
    url: https://deckhand/api/v1.0/revisions/4/validations/deckhand-schema-validation
    status: success
  - name: promenade-site-validation
    url: https://deckhand/api/v1.0/revisions/4/validations/promenade-site-validation
    status: failure
...

This endpoint uses the read_validation action.

GET /revisions/{{revision_id}}/validations/{{name}}

Gets the list of validation entry summaries that have been posted.

Sample response:

---
count: 1
next: null
prev: null
results:
  - id: 0
    url: https://deckhand/api/v1.0/revisions/4/validations/promenade-site-validation/0/entries/0
    status: failure
...

This endpoint uses the read_validation action.

GET /revisions/{{revision_id}}/validations/{{name}}/entries/{{entry_id}}

Gets the full details of a particular validation entry, including all posted error details.

Sample response:

---
name: promenade-site-validation
url: https://deckhand/api/v1.0/revisions/4/validations/promenade-site-validation/entries/0
status: failure
createdAt: 2017-07-16T02:03Z
expiresAfter: null
expiresAt: null
errors:
  - documents:
      - schema: promenade/Node/v1
        name: node-document-name
      - schema: promenade/Masters/v1
        name: kubernetes-masters
    message: Node has master role, but not included in cluster masters list.
...

This endpoint uses the read_validation action.

POST /revisions/{{revision_id}}/tags/{{tag}}

Associate the revision with a collection of metadata, if provided, by way of a tag. The tag itself can be used to label the revision.

Sample request with body:

POST `/revisions/0615b731-7f3e-478d-8ba8-a223eab4757e/tags/foobar`
Content-Type: application/x-yaml

---
metadata:
  - name: foo
    thing: bar
...

Sample response:

Content-Type: application/x-yaml
HTTP/1.1 201 Created
Location: https://deckhand/api/v1.0/revisions/0615b731-7f3e-478d-8ba8-a223eab4757e/tags/foobar

---
tag: foobar
metadata:
  - name: foo
    thing: bar
...

Sample request without body:

POST `/revisions/0615b731-7f3e-478d-8ba8-a223eab4757e/tags/foobar`
Content-Type: application/x-yaml

Sample response:

Content-Type: application/x-yaml
HTTP/1.1 201 Created
Location: https://deckhand/api/v1.0/revisions/0615b731-7f3e-478d-8ba8-a223eab4757e/tags/foobar

---
tag: foobar
...

This endpoint uses the write_tag action.

GET /revisions/{{revision_id}}/tags

List the tags associated with a revision.

Sample request with body:

GET `/revisions/0615b731-7f3e-478d-8ba8-a223eab4757e/tags`

Sample response:

Content-Type: application/x-yaml
HTTP/1.1 200 OK

---
- metadata:
  name: foo
  thing: bar
- metadata:
  name: baz
  thing: qux
...

This endpoint uses the read_tag action.

GET /revisions/{{revision_id}}/tags/{{tag}}

Show tag details for tag associated with a revision.

Sample request with body:

GET `/revisions/0615b731-7f3e-478d-8ba8-a223eab4757e/tags/foo`

Sample response:

Content-Type: application/x-yaml
HTTP/1.1 200 OK

---
metadata:
  - name: foo
    thing: bar
...

This endpoint uses the read_tag action.

DELETE /revisions/{{revision_id}}/tags/{{tag}}

Delete tag associated with a revision.

Sample request with body:

GET `/revisions/0615b731-7f3e-478d-8ba8-a223eab4757e/tags/foo`

Sample response:

Content-Type: application/x-yaml
HTTP/1.1 204 No Content

This endpoint uses the delete_tag action.

DELETE /revisions/{{revision_id}}/tags

Delete all tags associated with a revision.

Sample request with body:

GET `/revisions/0615b731-7f3e-478d-8ba8-a223eab4757e/tags`

Sample response:

Content-Type: application/x-yaml
HTTP/1.1 204 No Content

This endpoint uses the delete_tag action.

POST /rollback/{target_revision_id}

Creates a new revision that contains exactly the same set of documents as the revision specified by target_revision_id.

This endpoint uses the write_cleartext_document and write_encrypted_document actions.