Skip to content

include-file function #2350

@frankfarzan

Description

@frankfarzan

A weakness of execution configuration pattern is that it interleaves configuration and code. For example, gatekeeper constraint templates wrap Rego code in KRM. Similarly, starlark code is wrapped in StarlarkRun resource. We can improve the development UX by providing an imperative pre-processor function that injects the content of a file into a particular field of a KRM resource. Note that this is useful for gatekeeper admission controller, even when not using the gatekeeper kpt function.

Strawman:

Assume one or more resources (which may be deeply nested) in the current directory have a comment directive pointing to a file containing code, e.g.:

apiVersion: fn.kpt.dev/v1alpha1
kind: StarlarkRun
metadata:
  name: set-namespace-to-prod
# kpt-include: myscript.star
source: |
...

This script references myscript.star in the same directory:

def setnamespace(resources, namespace):
  for resource in resources:
    # mutate the resource
    resource["metadata"]["namespace"] = namespace
setnamespace(ctx.resource_list["items"], "prod")

And we have a gatekeeper template:

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata: # kpt-merge: /k8sbannedconfigmapkeysv1
  name: k8sbannedconfigmapkeysv1
spec:
  crd:
    spec:
      names:
        kind: K8sBannedConfigMapKeysV1
        validation:
          openAPIV3Schema:
            properties:
              keys:
                type: array
                items:
                  type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      # kpt-include: myscript.rego
      rego: |
...

That references myscript.rego:

package ban_keys

violation[{"msg": sprintf("%v", [val])}] {
  keys = {key | input.review.object.data[key]}
  banned = {key | input.parameters.keys[_] = key}
  overlap = keys & banned
  count(overlap) > 0
  val := sprintf("The following banned keys are being used in the ConfigMap: %v", [overlap])
}

After running the imperative function:

$ kpt fn eval -i gcr.io/kpt-fn/include-file --mount-current

(See #2351)

All resources containing the kpt-include comment directive are expanded:

apiVersion: fn.kpt.dev/v1alpha1
kind: StarlarkRun
metadata:
  name: set-namespace-to-prod
# kpt-include: myscript.star
source: |
  # set the namespace on all resources
  def setnamespace(resources, namespace):
    for resource in resources:
      # mutate the resource
      resource["metadata"]["namespace"] = namespace
  setnamespace(ctx.resource_list["items"], "prod")
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata: # kpt-merge: /k8sbannedconfigmapkeysv1
  name: k8sbannedconfigmapkeysv1
spec:
  crd:
    spec:
      names:
        kind: K8sBannedConfigMapKeysV1
        validation:
          openAPIV3Schema:
            properties:
              keys:
                type: array
                items:
                  type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
     # kpt-include: myscript.rego
      rego: |-
        package ban_keys

        violation[{"msg": sprintf("%v", [val])}] {
          keys = {key | input.review.object.data[key]}
          banned = {key | input.parameters.keys[_] = key}
          overlap = keys & banned
          count(overlap) > 0
          val := sprintf("The following banned keys are being used in the ConfigMap: %v", [overlap])
        }

Considerations:

  • Potential for abuse of this function. We don't want to encourage its use for maintaining partial resource configuration as a DRY technique (i.e. injecting KRM into KRM). Injecting into a single field of type string mitigates this. Should also consider a more descriptive name.
  • Whether to support relative paths or only allow the file in the same directory as the KRM. The latter is fine to start with to keep things simple.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/hydrateenhancementNew feature or requestp1triagedIssue has been triaged by adding an `area/` label

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions