spinnaker.execution.stages.before.patchManifest

A policy targeting this object runs before executing each task in a patchManifest stage.

Example Payload

Click to expand
{
  "input": {
    "pipeline": {
      "application": "test",
      "authentication": {
        "allowedAccounts": [
          "spinnaker",
          "staging",
          "staging-ecs"
        ],
        "user": "myUserName"
      },
      "buildTime": 1620926703486,
      "canceled": false,
      "canceledBy": null,
      "cancellationReason": null,
      "description": null,
      "endTime": 1620926705283,
      "id": "01F5KC59TRGWKCP31C4N51CDSB",
      "initialConfig": {},
      "keepWaitingPipelines": false,
      "limitConcurrent": true,
      "name": "test",
      "notifications": [],
      "origin": "api",
      "partition": null,
      "paused": null,
      "pipelineConfigId": "6a4cff2e-8265-4584-8993-2da2eb6254f5",
      "source": null,
      "spelEvaluator": "v4",
      "stages": [],
      "startTime": 1620926703525,
      "startTimeExpiry": null,
      "status": "TERMINAL",
      "systemNotifications": [],
      "templateVariables": null,
      "trigger": {
        "artifacts": [
          {
            "artifactAccount": "myUserName",
            "customKind": false,
            "location": null,
            "metadata": {
              "id": "d14e7e5b-247c-455d-8260-9e9b0a3ae936"
            },
            "name": "manifests/deploy-spinnaker.yaml",
            "provenance": null,
            "reference": "Https://api.github.com/repos/myUserName/hostname/contents/manifests/deploy-spinnaker.yaml",
            "type": "github/file",
            "uuid": null,
            "version": "master"
          }
        ],
        "correlationId": null,
        "isDryRun": false,
        "isRebake": false,
        "isStrategy": false,
        "notifications": [],
        "other": {
          "artifacts": [
            {
              "artifactAccount": "myUserName",
              "customKind": false,
              "metadata": {
                "id": "d14e7e5b-247c-455d-8260-9e9b0a3ae936"
              },
              "name": "manifests/deploy-spinnaker.yaml",
              "reference": "Https://api.github.com/repos/myUserName/hostname/contents/manifests/deploy-spinnaker.yaml",
              "type": "github/file",
              "version": "master"
            }
          ],
          "dryRun": false,
          "enabled": false,
          "eventId": "c1090782-f485-490e-a2d7-31763b3bd4d8",
          "executionId": "01F5KC59TRGWKCP31C4N51CDSB",
          "expectedArtifacts": [
            {
              "boundArtifact": {
                "artifactAccount": "myUserName",
                "customKind": false,
                "metadata": {
                  "id": "d14e7e5b-247c-455d-8260-9e9b0a3ae936"
                },
                "name": "manifests/deploy-spinnaker.yaml",
                "reference": "Https://api.github.com/repos/myUserName/hostname/contents/manifests/deploy-spinnaker.yaml",
                "type": "github/file",
                "version": "master"
              },
              "defaultArtifact": {
                "artifactAccount": "myUserName",
                "customKind": false,
                "metadata": {
                  "id": "d14e7e5b-247c-455d-8260-9e9b0a3ae936"
                },
                "name": "manifests/deploy-spinnaker.yaml",
                "reference": "Https://api.github.com/repos/myUserName/hostname/contents/manifests/deploy-spinnaker.yaml",
                "type": "github/file",
                "version": "master"
              },
              "id": "05ad020e-73a6-49f2-9988-2073831219e9",
              "matchArtifact": {
                "artifactAccount": "myUserName",
                "customKind": true,
                "metadata": {
                  "id": "f7a9b229-0a23-42ab-82de-9990d77084df"
                },
                "name": "manifests/deploy-spinnaker.yaml",
                "type": "github/file"
              },
              "useDefaultArtifact": true,
              "usePriorArtifact": false
            }
          ],
          "notifications": [],
          "parameters": {},
          "preferred": false,
          "rebake": false,
          "resolvedExpectedArtifacts": [
            {
              "boundArtifact": {
                "artifactAccount": "myUserName",
                "customKind": false,
                "metadata": {
                  "id": "d14e7e5b-247c-455d-8260-9e9b0a3ae936"
                },
                "name": "manifests/deploy-spinnaker.yaml",
                "reference": "Https://api.github.com/repos/myUserName/hostname/contents/manifests/deploy-spinnaker.yaml",
                "type": "github/file",
                "version": "master"
              },
              "defaultArtifact": {
                "artifactAccount": "myUserName",
                "customKind": false,
                "metadata": {
                  "id": "d14e7e5b-247c-455d-8260-9e9b0a3ae936"
                },
                "name": "manifests/deploy-spinnaker.yaml",
                "reference": "Https://api.github.com/repos/myUserName/hostname/contents/manifests/deploy-spinnaker.yaml",
                "type": "github/file",
                "version": "master"
              },
              "id": "05ad020e-73a6-49f2-9988-2073831219e9",
              "matchArtifact": {
                "artifactAccount": "myUserName",
                "customKind": true,
                "metadata": {
                  "id": "f7a9b229-0a23-42ab-82de-9990d77084df"
                },
                "name": "manifests/deploy-spinnaker.yaml",
                "type": "github/file"
              },
              "useDefaultArtifact": true,
              "usePriorArtifact": false
            }
          ],
          "strategy": false,
          "type": "manual",
          "user": "myUserName"
        },
        "parameters": {},
        "resolvedExpectedArtifacts": [
          {
            "boundArtifact": {
              "artifactAccount": "myUserName",
              "customKind": false,
              "location": null,
              "metadata": {
                "id": "d14e7e5b-247c-455d-8260-9e9b0a3ae936"
              },
              "name": "manifests/deploy-spinnaker.yaml",
              "provenance": null,
              "reference": "Https://api.github.com/repos/myUserName/hostname/contents/manifests/deploy-spinnaker.yaml",
              "type": "github/file",
              "uuid": null,
              "version": "master"
            },
            "defaultArtifact": {
              "artifactAccount": "myUserName",
              "customKind": false,
              "location": null,
              "metadata": {
                "id": "d14e7e5b-247c-455d-8260-9e9b0a3ae936"
              },
              "name": "manifests/deploy-spinnaker.yaml",
              "provenance": null,
              "reference": "Https://api.github.com/repos/myUserName/hostname/contents/manifests/deploy-spinnaker.yaml",
              "type": "github/file",
              "uuid": null,
              "version": "master"
            },
            "id": "05ad020e-73a6-49f2-9988-2073831219e9",
            "matchArtifact": {
              "artifactAccount": "myUserName",
              "customKind": true,
              "location": null,
              "metadata": {
                "id": "f7a9b229-0a23-42ab-82de-9990d77084df"
              },
              "name": "manifests/deploy-spinnaker.yaml",
              "provenance": null,
              "reference": null,
              "type": "github/file",
              "uuid": null,
              "version": null
            },
            "useDefaultArtifact": true,
            "usePriorArtifact": false
          }
        ],
        "type": "manual",
        "user": "myUserName"
      },
      "type": "PIPELINE"
    },
    "stage": {
      "context": {
        "account": "spinnaker",
        "app": "test",
        "cloudProvider": "kubernetes",
        "location": "staging",
        "manifestName": "deployment hostname",
        "mode": "static",
        "options": {
          "mergeStrategy": "strategic",
          "record": true
        },
        "patchBody": [
          {
            "apiVersion": "apps/v1",
            "kind": "Deployment",
            "metadata": {
              "name": "hostname",
              "namespace": "staging"
            },
            "spec": {
              "replicas": "1",
              "selector": {
                "matchLabels": {
                  "app": "hostname",
                  "version": "v1"
                }
              },
              "strategy": {
                "rollingUpdate": {
                  "maxSurge": 1,
                  "maxUnavailable": 1
                },
                "type": "RollingUpdate"
              },
              "template": {
                "metadata": {
                  "annotations": {
                    "prometheus.io/port": "9113",
                    "prometheus.io/scrape": "true"
                  },
                  "labels": {
                    "app": "hostname",
                    "version": "v1"
                  }
                },
                "spec": {
                  "containers": [
                    {
                      "image": "rstarmer/hostname:v1",
                      "imagePullPolicy": "Always",
                      "name": "hostname",
                      "resources": {},
                      "volumeMounts": [
                        {
                          "mountPath": "/etc/nginx/conf.d/nginx-status.conf",
                          "name": "nginx-status-conf",
                          "readOnly": true,
                          "subPath": "nginx.status.conf"
                        }
                      ]
                    },
                    {
                      "args": [
                        "-nginx.scrape-uri=http://localhost:8090/nginx_status"
                      ],
                      "image": "nginx/nginx-prometheus-exporter:0.3.0",
                      "imagePullPolicy": "Always",
                      "name": "nginx-exporter",
                      "ports": [
                        {
                          "containerPort": 9113,
                          "name": "nginx-ex-port",
                          "protocol": "TCP"
                        }
                      ]
                    }
                  ],
                  "restartPolicy": "Always",
                  "volumes": [
                    {
                      "configMap": {
                        "defaultMode": 420,
                        "name": "nginx-status-conf"
                      },
                      "name": "nginx-status-conf"
                    }
                  ]
                }
              }
            }
          }
        ],
        "source": "text"
      },
      "endTime": null,
      "id": "01F5KC59VXC778CNV0X6TKP9A6",
      "lastModified": null,
      "name": "Patch (Manifest)",
      "outputs": {},
      "parentStageId": null,
      "refId": "30",
      "requisiteStageRefIds": [],
      "scheduledTime": null,
      "startTime": 1620926703872,
      "startTimeExpiry": null,
      "status": "RUNNING",
      "syntheticStageOwner": null,
      "tasks": [
        {
          "endTime": 1620926706122,
          "id": "1",
          "implementingClass": "com.netflix.spinnaker.orca.clouddriver.tasks.manifest.ResolveTargetManifestTask",
          "loopEnd": false,
          "loopStart": false,
          "name": "resolveTargetManifest",
          "stageEnd": false,
          "stageStart": true,
          "startTime": 1620926704220,
          "status": "SUCCEEDED"
        },
        {
          "endTime": null,
          "id": "2",
          "implementingClass": "com.netflix.spinnaker.orca.clouddriver.tasks.manifest.ResolvePatchSourceManifestTask",
          "loopEnd": false,
          "loopStart": false,
          "name": "resolvePatchSourceManifest",
          "stageEnd": false,
          "stageStart": false,
          "startTime": 1620926706461,
          "status": "RUNNING"
        },
        {
          "endTime": null,
          "id": "3",
          "implementingClass": "com.netflix.spinnaker.orca.clouddriver.tasks.manifest.PatchManifestTask",
          "loopEnd": false,
          "loopStart": false,
          "name": "patchManifest",
          "stageEnd": false,
          "stageStart": false,
          "startTime": null,
          "status": "NOT_STARTED"
        },
        {
          "endTime": null,
          "id": "4",
          "implementingClass": "com.netflix.spinnaker.orca.clouddriver.tasks.MonitorKatoTask",
          "loopEnd": false,
          "loopStart": false,
          "name": "monitorPatch",
          "stageEnd": false,
          "stageStart": false,
          "startTime": null,
          "status": "NOT_STARTED"
        },
        {
          "endTime": null,
          "id": "5",
          "implementingClass": "com.netflix.spinnaker.orca.clouddriver.tasks.manifest.PromoteManifestKatoOutputsTask",
          "loopEnd": false,
          "loopStart": false,
          "name": "promoteOutputs",
          "stageEnd": false,
          "stageStart": false,
          "startTime": null,
          "status": "NOT_STARTED"
        },
        {
          "endTime": null,
          "id": "6",
          "implementingClass": "com.netflix.spinnaker.orca.clouddriver.tasks.manifest.WaitForManifestStableTask",
          "loopEnd": false,
          "loopStart": false,
          "name": "waitForManifestToStabilize",
          "stageEnd": false,
          "stageStart": false,
          "startTime": null,
          "status": "NOT_STARTED"
        },
        {
          "endTime": null,
          "id": "7",
          "implementingClass": "com.netflix.spinnaker.orca.pipeline.tasks.artifacts.BindProducedArtifactsTask",
          "loopEnd": false,
          "loopStart": false,
          "name": "bindProducedArtifacts",
          "stageEnd": true,
          "stageStart": false,
          "startTime": null,
          "status": "NOT_STARTED"
        }
      ],
      "type": "patchManifest"
    },
    "user": {
      "isAdmin": false,
      "roles": [],
      "username": "myUserName"
    }
  }
}

Example Policy

  • This example checks the manifest being applied and ensures that it contains a set of required annotations.

    package spinnaker.execution.stages.before.patchManifest
    
    required_annotations:=["app","owner"]
    
    deny["Manifest is missing a required annotation"] {
        annotations :=object.get(input.stage.context.patchBody[_].metadata,"annotations",{})
        # Use object.get to check if data exists
        object.get(annotations,required_annotations[_],null)==null
    }
    
  • This example prevents patchManifest stages from running unless they require recording the patch annotation.

    package spinnaker.execution.stages.before.patchManifest
    
    deny["Patching manifests is not allowed by policy unless recording the patch annotation is enabled."] {
        input.stage.context.options.record!=true
    }
    

Keys

Parameters related to the stage against which the policy is executing can be found in the input.stage.context object.

input.pipeline

Key Type Description
input.pipeline.application string The name of the Spinnaker application to which this pipeline belongs.
input.pipeline.authentication.allowedAccounts[] string The list of accounts to which the user this stage runs as has access.
input.pipeline.authentication.user string The Spinnaker user initiating the change.
input.pipeline.buildTime number
input.pipeline.canceledBy
input.pipeline.canceled boolean
input.pipeline.cancellationReason
input.pipeline.description string Description of the pipeline defined in the UI.
input.pipeline.endTime number
input.pipeline.id string The unique ID of the pipeline.
input.pipeline.keepWaitingPipelines boolean If false and concurrent pipeline execution is disabled, then the pipelines in the waiting queue gets canceled when the next execution starts.
input.pipeline.limitConcurrent boolean True if only 1 concurrent execution of this pipeline is allowed.
input.pipeline.name string The name of this pipeline.
input.pipeline.origin string
input.pipeline.partition
input.pipeline.paused
input.pipeline.pipelineConfigId string
input.pipeline.source
input.pipeline.spelEvaluator string Which version of spring expression language is being used to evaluate SpEL.
input.pipeline.stages[] [array] An array of the stages in the pipeline. Typically if you are writing a policy that examines multiple pipeline stages, it is better to write that policy against either the opa.pipelines package, or the spinnaker.execution.pipelines.before package.
input.pipeline.startTimeExpiry date Unix epoch date at which the pipeline expires.
input.pipeline.startTime number Timestamp from when the pipeline was started.
input.pipeline.status string
input.pipeline.templateVariables
input.pipeline.type string

input.pipeline.trigger

See input.pipeline.trigger for more information.

input.stage

See input.stage for more information.

input.stage.context

Key Type Description
input.stage.context.account string The name of the account containing the manifest that being patched.
input.stage.context.app string The application with which the manifest to be patched is associated.
input.stage.context.cloudProvider string The name of the cloud provider that executes the stage.
input.stage.context.location string The namespace that contains the manifest to be patched.
input.stage.context.manifestName string The name of the manifest to patch.
input.stage.context.mode string Specifies whether the target manifest is identified statically or dynamically.
input.stage.context.options.mergeStrategy string The merge strategy to use when patching Kubernetes objects:
Strategic: (Default) Kubernetes Strategic merge patch.
JSON: JSON Patch, RFC 6902
Merge: JSON Merge Patch, RFC 7386
input.stage.context.options.record boolean Record the applied patch in the kubernetes.io/change-cause annotation. If the annotation already exists, the contents are replaced.
input.stage.context.patchBody[] string The raw kubernetes manifest being applied. This is the element you should write policies against that involve the manifest.
input.stage.context.source string

input.user

This object provides information about the user performing the action. This can be used to restrict actions by role. See input.user for more information.


Last modified August 18, 2023: (02b163b7)