×

Structure of the metadata.yaml file

The metadata.yaml file provides a central configuration point to define and configure the templates in a reference configuration. The file features a hierarchy of parts and components. parts are groups of components and components are groups of templates. Under each component, you can configure template dependencies, validation rules, and add descriptive metadata.

Example metadata.yaml file
apiVersion: v2
parts: (1)
  - name: Part1 (2)
    components:
      - name: Component1 (3)
        <component1_configuration> (4)
  - name: Part2
      - name: Component2
        <component2_configuration>
1 Every part typically describes a workload or a set of workloads.
2 Specify a part name.
3 Specify a component name.
4 Specify the configuration for a template. For example, define template relationships or configure what fields to use in a comparison.

Configuring template relationships

By defining relationships between templates in your reference configuration, you can support use-cases with complex dependencies. For example, you can configure a component to require specific templates, require one template from a group, or allow any template from a group, and so on.

Procedure
  • Create a metadata.yaml file to match your use case. Use the following structure as an example:

    Example metadata.yaml file
    apiVersion: v2
    parts:
      - name: Part1
        components:
          - name: Component1
            allOf: (1)
              - path: RequiredTemplate1.yaml
              - path: RequiredTemplate2.yaml
          - name: Component2
            allOrNoneOf: (2)
              - path: OptionalBlockTemplate1.yaml
              - path: OptionalBlockTemplate2.yaml
          - name: Component3
            anyOf: (3)
              - path: OptionalTemplate1.yaml
              - path: OptionalTemplate2.yaml
          - name: Component4
            noneOf: (4)
              - path: BannedTemplate1.yaml
              - path: BannedTemplate2.yaml
          - name: Component5
            oneOf: (5)
              - path: RequiredExclusiveTemplate1.yaml
              - path: RequiredExclusiveTemplate2.yaml
          - name: Component6
            anyOneOf: (6)
              - path: OptionalExclusiveTemplate1.yaml
              - path: OptionalExclusiveTemplate2.yaml
    #...
    1 Specifies required templates.
    2 Specifies a group of templates that are either all required or all optional. If one corresponding custom resource (CR) is present in the cluster, then all corresponding CRs must be present in the cluster.
    3 Specifies optional templates.
    4 Specifies templates to exclude. If a corresponding CR is present in the cluster, the plugin returns a validation error.
    5 Specifies templates where only one can be present. If none, or more than one of the corresponding CRs are present in the cluster, the plugin returns a validation error .
    6 Specifies templates where only one can be present in the cluster. If more than one of the corresponding CRs are present in the cluster, the plugin returns a validation error.

Configuring expected variation in a template

You can handle variable content within a template by using Golang templating syntax. Using this syntax, you can configure validation logic that handles optional, required, and conditional content within the template.

  • The cluster-compare plugin requires all templates to render as valid YAML. To avoid parsing errors for missing fields, use conditional templating syntax such as {{- if .spec.<optional_field> }} when implementing templating syntax. This conditional logic ensures templates process missing fields gracefully and maintains valid YAML formatting.

  • You can use the Golang templating syntax with custom and built-in functions for complex use cases. All Golang built-in functions are supported including the functions in the Sprig library.

Procedure
  • Create a metadata.yaml file to match your use case. Use the following structure as an example:

    apiVersion: v2
    kind: Service
    metadata:
      name: frontend (1)
      namespace: {{ .metadata.namespace }}  (2)
      labels:
        app: guestbook
        tier: frontend
    spec:
      {{- if and .spec.type (eq (.spec.type) "NodePort" "LoadBalancer") }}
      type: {{.spec.type }} (3)
      {{- else }}
      type: should be NodePort or LoadBalancer
      {{- end }}
      ports:
      - port: 80
      selector:
        app: guestbook
        {{- if .spec.selector.tier }} (4)
        tier: frontend
        {{- end }}
    1 Configures a required field that must match the specified value.
    2 Configures a required field that can have any value.
    3 Configures validation for the .spec.type field.
    4 Configures an optional field.

Configuring the metadata.yaml file to exclude template fields

You can configure the metadata.yaml file to exclude fields from a comparison. Exclude fields that are irrelevant to a comparison, for example annotations or labels that are inconsequential to a cluster configuration.

You can configure exclusions in the metadata.yaml file in the following ways:

  • Exclude all fields in a custom resource not specified in a template.

  • Exclude specific fields that you define using the pathToKey field.

    pathToKey is a dot separated path. Use quotes to escape key values featuring a period.

Excluding all fields not specified in a template

During the comparison process, the cluster-compare plugin renders a template by merging fields from the corresponding custom resource (CR). If you configure the ignore-unspecified-fields to true, all fields that are present in the CR, but not in the template, are excluded from the merge. Use this approach when you want to focus the comparison on the fields specified in the template only.

Procedure
  • Create a metadata.yaml file to match your use case. Use the following structure as an example:

    apiVersion: v2
    parts:
      - name: Part1
        components:
          - name: Namespace
            allOf:
              - path: namespace.yaml
                config:
                  ignore-unspecified-fields: true (1)
    #...
    1 Specify true to exclude from the comparison all fields in a CR that are not explicitly configured in the corresponding namespace.yaml template.

Excluding specific fields by setting default exclusion fields

You can exclude fields by defining a default value for fieldsToOmitRefs in the defaultOmitRef field. This default exclusion applies to all templates, unless overridden by the config.fieldsToOmitRefs field for a specific template.

Procedure
  • Create a metadata.yaml file to match your use case. Use the following structure as an example:

    Example metadata.yaml file
    apiVersion: v2
    parts:
    
    #...
    
    fieldsToOmit:
       defaultOmitRef: default (1)
       items:
          default:
             - pathToKey: a.custom.default."k8s.io" (2)
    1 Sets the default exclusion for all templates, unless overridden by the config.fieldsToOmitRefs field for a specific template.
    2 The value is excluded for all templates.

Excluding specific fields

You can specify fields to exclude by defining the path to the field, and then referencing the definition in the config section for a template.

Procedure
  • Create a metadata.yaml file to match your use case. Use the following structure as an example:

    Example metadata.yaml file
    apiVersion: v2
    parts:
      - name: Part1
        components:
          - name: Component1
            - path: deployment.yaml
              config:
                fieldsToOmitRefs:
                  - deployments (1)
    
    #...
    
    fieldsToOmit:
       items:
          deployments:
             - pathToKey: spec.selector.matchLabels.k8s-app (2)
    1 References the fieldsToOmit.items.deployments item for the deployment.yaml template.
    2 Excludes the spec.selector.matchLabels.k8s-app field from the comparison.

    Setting fieldsToOmitRefs replaces the default value.

Excluding specific fields by setting default exclusion groups

You can create default groups of fields to exclude. A group of exclusions can reference another group to avoid duplication when defining exclusions.

Procedure
  • Create a metadata.yaml file to match your use case. Use the following structure as an example:

    Example metadata.yaml file
    apiVersion: v2
    parts:
    
    #...
    
    fieldsToOmit:
       defaultOmitRef: default
       items:
        common:
          - pathToKey: metadata.annotations."kubernetes.io/metadata.name"
          - pathToKey: metadata.annotations."kubernetes.io/metadata.name"
          - pathToKey: metadata.annotations."kubectl.kubernetes.io/last-applied-configuration"
          - pathToKey: metadata.creationTimestamp
          - pathToKey: metadata.generation
          - pathToKey: spec.ownerReferences
          - pathToKey: metadata.ownerReferences
        default:
          - include: common (1)
          - pathToKey: status
    1 The common group is included in the default group.

Configuring inline validation for template fields

You can enable inline regular expressions to validate template fields, especially in scenarios where Golang templating syntax is difficult to maintain or overly complex. Using inline regular expressions simplifies templates, improves readability, and allows for more advanced validation logic.

The cluster-compare plugin provides two functions for inline validation:

  • regex: Validates content in a field using a regular expression.

  • capturegroups: Enhances multi-line text comparisons by processing non-capture group text as exact matches, applying regular expression matching only within named capture groups, and ensuring consistency for repeated capture groups.

Configuring inline validation with the regex function

Use the regex inline function to validate fields using regular expressions.

Procedure
  1. Create a metadata.yaml file to match your use case. Use the following structure as an example:

    apiVersion: v2
    parts:
    - name: Part1
      components:
      - name: Example
        allOf:
        - path: example.yaml
          config:
            perField:
            - pathToKey: spec.bigTextBlock (1)
              inlineDiffFunc: regex (2)
    1 Specifies the field for inline validation.
    2 Enables inline validation using regular expressions.
  2. Use a regular expression to validate the field in the associated template:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      namespace: dashboard
    data:
      bigTextBlock: |-
        This is a big text block with some static content, like this line.
        It also has a place where (?<username>[a-z0-9]+) would put in their own name. (?<username>[a-z0-9]+) would put in their own name.

Configuring inline validation with the capturegroups function

Use the capturegroups inline function for more precise validation of fields featuring multi-line strings.

Procedure
  1. Create a metadata.yaml file to match your use case. Use the following structure as an example:

    apiVersion: v2
    parts:
    - name: Part1
      components:
      - name: Example
        allOf:
        - path: example.yaml
          config:
            perField:
            - pathToKey: spec.bigTextBlock (1)
              inlineDiffFunc: capturegroups (2)
    1 Specifies the field for inline validation.
    2 Enables inline validation using capture groups.
  2. Use a regular expression to validate the field in the associated template:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      namespace: dashboard
    data:
      bigTextBlock: |-
        This static content outside of a capture group should match exactly.
        Here is a username capture group: (?<username>[a-z0-9]+).
        It should match this capture group: (?<username>[a-z0-9]+).

Configuring descriptions for the output

Each part, component, or template can include descriptions to provide additional context, instructions, or documentation links. These descriptions are helpful to convey why a specific template or structure is required.

Procedure
  • Create a metadata.yaml file to match your use case. Use the following structure as an example:

    apiVersion: v2
    parts:
      - name: Part1
        description: |-
          General text for every template under this part, unless overridden.
        components:
          - name: Component1
            # With no description set, this inherits the description from the part above.
            OneOf:
              - path: Template1.yaml
                # This inherits the component description, if set.
              - path: Template2.yaml
              - path: Template3.yaml
                description: |-
                  This template has special instructions that don't apply to the others.
          - name: Component2
            description: |-
              This overrides the part text with something more specific.
              Multi-line text is supported, at all levels.
            allOf:
              - path: RequiredTemplate1.yaml
              - path: RequiredTemplate2.yaml
                description: |-
                  Required for important reasons.
              - path: RequiredTemplate3.yaml