deckhand/doc/source/users/replacement.rst
Rick Bartra 60e82b7bd6 Validate additional 'metadata.replacement' scenarios
This patch set adds additional documentation and unit tests
to validate further replacement scenarios.

In particular this commit adds an additional document check that
looks for documents exisitng in different layers that contain the
same name and same schema without any of them having `replacement: true`

Change-Id: I7c033d32a6755f36e609789a748cbc6d4af06bc2
2018-10-30 10:23:14 -04:00

8.4 KiB

Document Replacement

Note

Document replacement is an advanced concept in Deckhand. This section assumes that the reader already has an understanding of layering and substitution.

Document replacement, in the simplest terms, involves a child document replacing its parent. That is, the entire child document replaces its parent document. Replacement aims to lessen data duplication by taking advantage of document-abstraction and document layering patterns.

Unlike the layering replace action, which allows a child document to selectively replace portions of the parent's data section with that of its own, document replacement allows a child document to replace the entire parent document.

Elaborate on these patterns in a separate section.

Replacement introduces the replacement: true property underneath the top-level metadata section. This property is subject to certain preconditions, discussed in the Requirements section below.

Replacement aims to replace specific values in a parent document via document replacement for particular sites, while allowing the same parent document to be consumed directly (layered with, substituted from) for completely different sites. This means that the same YAML template can be referenced from a global namespace by different site-level documents, and when necessary, specific sites can override the global defaults with specific overrides via document replacement. Effectively, this means that the same template can be referenced without having to duplicate all of its data, just to override a few values between the otherwise-exactly-the-same templates.

Like abstract documents, documents that are replaced are not returned from Deckhand's rendered-documents endpoint. (Documents that do replace -- those with the replacement: true property -- are returned instead.)

Requirements

Document replacement has the following requirements:

  • Only a child document can replace its parent.
  • The child document must have the replacement: true property underneath its metadata section.
  • The child document must be able to select the correct parent. For more information on this, please reference the parent-selection section.
  • Additionally, the child document must have the same metadata.name and schema as its parent. Their metadata.layeringDefinition.layer must differ.

The following result in validation errors:

  • A document with replacement: true doesn't have a parent.
  • A document with replacement: true doesn't have the same metadata.name and schema as its parent.
  • A replacement document cannot itself be replaced. That is, only one level of replacement is allowed.

Here are the following possible scenarios regarding child and parent replacement values:

Child | Parent | Status
True | True | Throws InvalidDocumentReplacement exception
False | True | Throws InvalidDocumentReplacement exception
True | False | Valid scenario
False | False | Throws InvalidDocumentReplacement exception

Examples

Note that each key in the examples below is mandatory and that the parentSelector labels should be able to select the parent to be replaced.

Document replacer (child):

---
# Note that the schema and metadata.name keys are the same as below.
schema: armada/Chart/v1
metadata:
  name: airship-deckhand
  # The replacement: true key is mandatory.
  replacement: true
  layeringDefinition:
    # Note that the layer differs from that of the parent below.
    layer: N-1
    # The key-value pairs underneath `parentSelector` must be compatible with
    # key-value pairs underneath the `labels` section in the parent document
    # below.
    parentSelector:
      selector: foo
    actions:
      - ...
data: ...

Which replaces the document replacee (parent):

---
# Note that the schema and metadata.name keys are the same as above.
schema: armada/Chart/v1
metadata:
  name: airship-deckhand
  labels:
    selector: foo
  layeringDefinition:
    # Note that the layer differs from that of the child above.
    layer: N
data: ...

Why Replacement?

Layering without Replacement

Layering without replacement can introduce a lot of data duplication across documents. Take the following use case: Some sites need to be deployed with log debugging enabled and other sites need to be deployed with log debugging disabled.

To achieve this, two top-layer documents can be created:

---
schema: armada/Chart/v1
metadata:
  name: airship-deckhand-1
  layeringDefinition:
    layer: global
    ...
data:
  debug: false
  # Note that the data below can be arbitrarily long and complex.
  ...

And:

---
schema: armada/Chart/v1
metadata:
  name: airship-deckhand-2
  layeringDefinition:
    layer: global
    ...
data:
  debug: true
  # Note that the data below can be arbitrarily long and complex.
  ...

However, what if the only thing that differs between the two documents is just debug: true|false and every other value in both documents is precisely the same?

Clearly, the pattern above leads to a lot of data duplication.

Layering with Replacement

Using document replacement, the above duplication can be partially eliminated. For example:

# Replacer (child document).
---
schema: armada/Chart/v1
metadata:
  name: airship-deckhand
  replacement: true
  layeringDefinition:
    layer: site
    parentSelector:
      selector: foo
    actions:
      - method: merge
        path: .
      - method: replace
        path: .debug
data:
  debug: true
  ...

And:

# Replacee (parent document).
---
schema: armada/Chart/v1
metadata:
  name: airship-deckhand
  labels:
    selector: foo
  layeringDefinition:
    layer: global
    ...
data:
  debug: false
  ...

In the case above, for sites that require debug: false, only the global-level document should be included in the payload to Deckhand, along with all other documents required for site deployment.

However, for sites that require debug: true, both documents should be included in the payload to Deckhand, along with all other documents required for site deployment.

Implications for Pegleg

In practice, when using Pegleg, each document above can be placed in a separate file and Pegleg can either reference only the parent document if log debugging needs to be enabled or both documents if log debugging needs to be disabled. This pattern allows data duplication to be lessened.

How It Works

Document replacement involves a child document replacing its parent. There are three fundamental cases that are handled:

  1. A child document replaces its parent. Only the child is returned.
  2. Same as (1), except that the parent document is used as a substitution source. With replacement, the child is used as the substitution source instead.
  3. Same as (2), except that the parent document is used as a layering source (that is, yet another child document layers with the parent). With replacement, the child is used as the layering source instead.