vmware-tanzu / cartographer

Cartographer is a Supply Chain Choreographer.
https://cartographer.sh
Apache License 2.0
443 stars 65 forks source link

Promote a deployment #247

Closed jwntrs closed 2 years ago

jwntrs commented 2 years ago

Description of problem

As an operator, I want to be able to promote an environment after a deployment has succeeded. In order to do so, I need a way to indicate that my deployment has succeeded.

[config] ========> [kapp] =======> [promote]

Proposed solution

Example

Fetches Kubernetes configuration from a git repository Deploys to a staging cluster using kapp controller Promotes to production via pull request if integration tests pass

Deliverable

apiVersion: carto.run/v1alpha1
kind: Deliverable
metadata:
  name: my-app
  labels:
    app.tanzu.vmware.com/deliverable-type: web
spec:
  config:
    git:
      url: https://github.com/ekcasey/hello-world-ops
      ref:
        branch: staging

ClusterDelivery

apiVersion: carto.run/v1alpha1
kind: ClusterDelivery
metadata:
  name: delivery
spec:
  selector:
    app.tanzu.vmware.com/deliverable-type: web
  resources:
    - name: config-provider
      templateRef:
        kind: ClusterSourceTemplate
        name: git-repository
    - name: deployer
      templateRef:
        kind: ClusterDeployTemplate
        name: app-deploy
      source:
        resource: config-provider
    - name: promoter
      templateRef:
        kind: ClusterTemplate
        name: git-merge
      sources:
      - resource: deployer

ClusterSourceTemplate

apiVersion: carto.run/v1alpha1
kind: ClusterSourceTemplate
metadata:
  name: source
spec:
  urlPath: .status.artifact.url
  revisionPath: .status.artifact.revision

  template:
    apiVersion: source.toolkit.fluxcd.io/v1beta1
    kind: GitRepository
    metadata:
      name: $(deliverable.metadata.name)$
    spec:
      interval: 1m
      url: $(deliverable.spec.source.git.url)$
      ref: $(deliverable.spec.source.git.ref)$
      gitImplementation: libgit2
      ignore: ""

ClusterDeploymentTemplate

apiVersion: carto.run/v1alpha1
kind: ClusterDeploymentTemplate
metadata:
  name: app-deploy
spec:
  observedCompletion: # uses observedGeneration
    succeeded: {key: 'status.conditions.#(type=="ReconcileSucceeded").status', value: "True"}

  template:
    apiVersion: kappctrl.k14s.io/v1alpha1
    kind: App
    metadata:
      name: $(deliverable.metadata.name)$
    spec:
      serviceAccountName: default
      fetch:
       - http:
          url: $(source.url)$
      template:
        - ytt: {}
      deploy:
        - kapp: {}

ClusterTemplate - Git Merge

apiVersion: carto.run/v1alpha1
kind: ClusterTemplate
metadata:
  name: git-merge
spec:
  template:
    apiVersion: carto.run/v1alpha1
    kind: Pipeline
    metadata:
      generateName: $(workload.name)$-promotion-
    spec:
      inputs:
        url: $(source.url)$
        revision: $(source.revision)$
        pipeline: test

      runTemplateRef:
        name: default-tekton-template

PipelineRun - Tests

apiVersion: carto.run/v1alpha1
kind: RunTemplate
metadata:
  name: default-tekton-source-provider
spec:
  completion:
    succeeded: {key: 'status.conditions.#(type=="Succeeded").status', value: "True"}
    failed:    {key: 'status.conditions.#(type=="Succeeded").status', value: "False"}

  template:
    apiVersion: tekton.dev/v1beta1
    kind: PipelineRun
    metadata:
      generateName: $(pipeline.metadata.name)$-
    spec:
      pipelineRef: 
        name: $(pipeline.spec.inputs.pipelineName)$

      workspaces:
        - name: source
          volumeClaimTemplate:
            spec:
              accessModes: [ ReadWriteOnce ]

      params:
        - name: source-url
          value: $(pipeline.spec.inputs.source-url)$
        - name: source-revision
          value: $(pipeline.spec.inputs.source-revision)$
waciumawanjohi commented 2 years ago

Sad paths for observedCompletion on the ClusterDeploymentTemplate:

apiVersion: carto.run/v1alpha1
kind: Deliverable
status:
  conditions:
    - type: ResourcesSubmitted
      status: "False"
      reason: "TemplateStampFailure"
      message: "Resource 'deployer' cannot satisfy observedCompletion without observedGeneration in object status"
apiVersion: carto.run/v1alpha1
kind: Deliverable
status:
  conditions:
    - type: ResourcesSubmitted
      status: Unknown
      reason: ConditionNotMet
      message: "Resource 'deployer' is waiting for the specified condition of observedCompletion."
waciumawanjohi commented 2 years ago

Failed key on observedCompletion

spec:
  observedCompletion: # uses observedGeneration
    failed: {key: 'status.conditions.#(type=="ReconcileSucceeded").status', value: "False"}
  1. Failure overrides success:

    spec:
    observedCompletion: # uses observedGeneration
    succeeded: {key: 'status.conditions.#(type=="ReconcileSucceeded").status', value: "True"}
    failed: {key: 'status.conditions.#(type=="ReconcileSucceeded").status', value: "True"}

    This should fail.

  2. When there is only a failed condition and it cannot be read, it is treated in the same manner as succeeded condition cannot be read. We are currently taking the position that it should not be possible to specify only a failing condition.

  3. When there is a failed condition, we do not report that we could not read the condition or that it was not met.

waciumawanjohi commented 2 years ago

Is it required to have observedCompletion or observedMatches? Can they coexist? (Is this an OR, NAND, or XOR relationship?)

waciumawanjohi commented 2 years ago

ObservedMatches

This is a list. Given any match that is not fulfilled, observedMatches should be false.