From 73a37f2b2a12d74ddf6a4b54e04b50fa1a7c68a1 Mon Sep 17 00:00:00 2001 From: Ian Howell Date: Fri, 22 Mar 2019 15:40:19 -0500 Subject: [PATCH] Add the `mergeStrategy` option to resource patching (#1269) * This adds the ability to pass a mergeStrategy to a patch resource. this is valuable because the default merge strategy for kubernetes is 'strategic', which does not work with Custom Resources. * This also updates the resource example to demonstrate how it is used --- api/openapi-spec/swagger.json | 4 +++ examples/README.md | 34 ++++++++++++++++++- .../workflow/v1alpha1/openapi_generated.go | 7 ++++ pkg/apis/workflow/v1alpha1/types.go | 4 +++ workflow/executor/resource.go | 7 ++++ 5 files changed, 55 insertions(+), 1 deletion(-) diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index eb0e362aad5b..f42eaec91ec0 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -538,6 +538,10 @@ "description": "Manifest contains the kubernetes manifest", "type": "string" }, + "mergeStrategy": { + "description": "MergeStrategy is the strategy used to merge a patch. It defaults to \"strategic\" Must be one of: strategic, merge, json", + "type": "string" + }, "successCondition": { "description": "SuccessCondition is a label selector expression which describes the conditions of the k8s resource in which it is acceptable to proceed to the following step", "type": "string" diff --git a/examples/README.md b/examples/README.md index 57d8bdcdb119..34398e741696 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1164,7 +1164,6 @@ spec: - name: pi-tmpl resource: # indicates that this is a resource template action: create # can be any kubectl action (e.g. create, delete, apply, patch) - # Patch action will support only **json merge strategic** # The successCondition and failureCondition are optional expressions. # If failureCondition is true, the step is considered failed. # If successCondition is true, the step is considered successful. @@ -1194,6 +1193,39 @@ spec: Resources created in this way are independent of the workflow. If you want the resource to be deleted when the workflow is deleted then you can use [Kubernetes garbage collection](https://kubernetes.io/docs/concepts/workloads/controllers/garbage-collection/) with the workflow resource as an owner reference ([example](./k8s-owner-reference.yaml)). +**Note:** +When patching, the resource will accept another attribute, `mergeStrategy`, which can either be `strategic`, `merge`, or `json`. If this attribute is not supplied, it will default to `strategic`. Keep in mind that Custom Resources cannot be patched with `strategic`, so a different strategy must be chosen. For example, suppose you have the [CronTab CustomResourceDefinition](https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#create-a-customresourcedefinition) defined, and the following instance of a CronTab: + +```yaml +apiVersion: "stable.example.com/v1" +kind: CronTab +spec: + cronSpec: "* * * * */5" + image: my-awesome-cron-image +``` + +This Crontab can be modified using the following Argo Workflow: + +```yaml +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: k8s-patch- +spec: + entrypoint: cront-tmpl + templates: + - name: cront-tmpl + resource: + action: patch + mergeStrategy: merge # Must be one of [strategic merge json] + manifest: | + apiVersion: "stable.example.com/v1" + kind: CronTab + spec: + cronSpec: "* * * * */10" + image: my-awesome-cron-image +``` + ## Docker-in-Docker Using Sidecars An application of sidecars is to implement Docker-in-Docker (DinD). DinD is useful when you want to run Docker commands from inside a container. For example, you may want to build and push a container image from inside your build container. In the following example, we use the docker:dind container to run a Docker daemon in a sidecar and give the main container access to the daemon. diff --git a/pkg/apis/workflow/v1alpha1/openapi_generated.go b/pkg/apis/workflow/v1alpha1/openapi_generated.go index de74605e3487..b203430f3f8f 100644 --- a/pkg/apis/workflow/v1alpha1/openapi_generated.go +++ b/pkg/apis/workflow/v1alpha1/openapi_generated.go @@ -1005,6 +1005,13 @@ func schema_pkg_apis_workflow_v1alpha1_ResourceTemplate(ref common.ReferenceCall Format: "", }, }, + "mergeStrategy": { + SchemaProps: spec.SchemaProps{ + Description: "MergeStrategy is the strategy used to merge a patch. It defaults to \"strategic\" Must be one of: strategic, merge, json", + Type: []string{"string"}, + Format: "", + }, + }, "manifest": { SchemaProps: spec.SchemaProps{ Description: "Manifest contains the kubernetes manifest", diff --git a/pkg/apis/workflow/v1alpha1/types.go b/pkg/apis/workflow/v1alpha1/types.go index ff659353d360..852746236326 100644 --- a/pkg/apis/workflow/v1alpha1/types.go +++ b/pkg/apis/workflow/v1alpha1/types.go @@ -781,6 +781,10 @@ type ResourceTemplate struct { // Must be one of: get, create, apply, delete, replace Action string `json:"action"` + // MergeStrategy is the strategy used to merge a patch. It defaults to "strategic" + // Must be one of: strategic, merge, json + MergeStrategy string `json:"mergeStrategy,omitempty"` + // Manifest contains the kubernetes manifest Manifest string `json:"manifest"` diff --git a/workflow/executor/resource.go b/workflow/executor/resource.go index 9866d858040b..270ab69298dc 100644 --- a/workflow/executor/resource.go +++ b/workflow/executor/resource.go @@ -31,6 +31,13 @@ func (we *WorkflowExecutor) ExecResource(action string, manifestPath string, isD } if action == "patch" { + mergeStrategy := "strategic" + if we.Template.Resource.MergeStrategy != "" { + mergeStrategy = we.Template.Resource.MergeStrategy + } + + args = append(args, "--type") + args = append(args, mergeStrategy) args = append(args, "-p") buff, err := ioutil.ReadFile(manifestPath)