diff --git a/CHANGELOG.md b/CHANGELOG.md index ceef39996dc4..e6de17e0a589 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,20 @@ # Changelog +## v3.1.2 (2021-07-15) + + * [98721a96e](https://github.com/argoproj/argo-workflows/commit/98721a96eef8e4fe9a237b2105ba299a65eaea9a) fixed test + * [6041ffe22](https://github.com/argoproj/argo-workflows/commit/6041ffe228c8f79e6578e097a357dfebf768c78f) fix(controller): Not updating StoredWorkflowSpec when WFT changed during workflow running (#6342) + * [d14760182](https://github.com/argoproj/argo-workflows/commit/d14760182851c280b11d688b70a81f3fe014c52f) fix(cli): v3.1 Argo Auth Token (#6344) + * [ce5679c4b](https://github.com/argoproj/argo-workflows/commit/ce5679c4bd1040fa5d68eea24a4a82ef3844d43c) feat(controller): Store artifact repository in workflow status. Fixes + * [74581157f](https://github.com/argoproj/argo-workflows/commit/74581157f9fd8190027021dd5af409cd3e3e781f) fix(executor): Tolerate docker re-creating containers. Fixes #6244 (#6252) + * [cd208e27f](https://github.com/argoproj/argo-workflows/commit/cd208e27ff0e45f82262b18ebb65081ae5978761) fix(executor): emissary - make /var/run/argo files readable from non-root users. Fixes #6238 (#6304) + +### Contributors + + * Alex Collins + * Saravanan Balasubramanian + * Yuan (Bob) Gong + ## v3.1.1 (2021-06-28) * [4d12bbfee](https://github.com/argoproj/argo-workflows/commit/4d12bbfee13faea6d2715c809fab40ae33a66074) fix(conttroller): Always set finishedAt dote. Fixes #6135 (#6139) diff --git a/USERS.md b/USERS.md index 8a1ca0fb5a4f..b6b2eafc8db3 100644 --- a/USERS.md +++ b/USERS.md @@ -17,6 +17,7 @@ Currently, the following organizations are **officially** using Argo Workflows: 1. [Admiralty](https://admiralty.io/) 1. [Adobe](https://www.adobe.com/) 1. [Alibaba Cloud](https://www.alibabacloud.com/about) +1. [Alibaba Group](https://www.alibabagroup.com/) 1. [Ant Group](https://www.antgroup.com/) 1. [AppDirect](https://www.appdirect.com/) 1. [Astraea](https://astraea.earth/) @@ -127,6 +128,7 @@ Currently, the following organizations are **officially** using Argo Workflows: 1. [Wavefront](https://www.wavefront.com/) 1. [Wellcome Trust](https://wellcome.ac.uk/) 1. [VMware](https://www.vmware.com/) +1. [WooliesX](https://wooliesx.com.au/) 1. [Woolworths Group](https://www.woolworthsgroup.com.au/) 1. [Zhihu](https://www.zhihu.com/) diff --git a/hack/crds.go b/hack/crds.go index 7c617f53f1b9..d77f6d2e3cff 100644 --- a/hack/crds.go +++ b/hack/crds.go @@ -68,7 +68,7 @@ func removeCRDValidation(filename string) { properties := version["schema"].(obj)["openAPIV3Schema"].(obj)["properties"].(obj) for k := range properties { if k == "spec" || k == "status" { - properties[k] = obj{"type": "object", "x-kubernetes-preserve-unknown-fields": true} + properties[k] = obj{"type": "object", "x-kubernetes-preserve-unknown-fields": true, "x-kubernetes-map-type": "atomic"} } } data, err = yaml.Marshal(crd) diff --git a/manifests/base/crds/minimal/argoproj.io_clusterworkflowtemplates.yaml b/manifests/base/crds/minimal/argoproj.io_clusterworkflowtemplates.yaml index fa7da83a96ec..889dfe2f508f 100644 --- a/manifests/base/crds/minimal/argoproj.io_clusterworkflowtemplates.yaml +++ b/manifests/base/crds/minimal/argoproj.io_clusterworkflowtemplates.yaml @@ -26,6 +26,7 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata diff --git a/manifests/base/crds/minimal/argoproj.io_cronworkflows.yaml b/manifests/base/crds/minimal/argoproj.io_cronworkflows.yaml index 2878fe9b4241..812cf1143484 100644 --- a/manifests/base/crds/minimal/argoproj.io_cronworkflows.yaml +++ b/manifests/base/crds/minimal/argoproj.io_cronworkflows.yaml @@ -26,9 +26,11 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true status: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata diff --git a/manifests/base/crds/minimal/argoproj.io_workfloweventbindings.yaml b/manifests/base/crds/minimal/argoproj.io_workfloweventbindings.yaml index 9585686a310f..22e2ecf0f6b4 100644 --- a/manifests/base/crds/minimal/argoproj.io_workfloweventbindings.yaml +++ b/manifests/base/crds/minimal/argoproj.io_workfloweventbindings.yaml @@ -25,6 +25,7 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata diff --git a/manifests/base/crds/minimal/argoproj.io_workflows.yaml b/manifests/base/crds/minimal/argoproj.io_workflows.yaml index f3751e18c985..6e646adc7d4a 100644 --- a/manifests/base/crds/minimal/argoproj.io_workflows.yaml +++ b/manifests/base/crds/minimal/argoproj.io_workflows.yaml @@ -35,9 +35,11 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true status: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata diff --git a/manifests/base/crds/minimal/argoproj.io_workflowtasksets.yaml b/manifests/base/crds/minimal/argoproj.io_workflowtasksets.yaml index 4ecef192eaa2..dbd9d4526dea 100644 --- a/manifests/base/crds/minimal/argoproj.io_workflowtasksets.yaml +++ b/manifests/base/crds/minimal/argoproj.io_workflowtasksets.yaml @@ -23,9 +23,11 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true status: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata diff --git a/manifests/base/crds/minimal/argoproj.io_workflowtemplates.yaml b/manifests/base/crds/minimal/argoproj.io_workflowtemplates.yaml index f6fa080ae136..8165ec25b8ba 100644 --- a/manifests/base/crds/minimal/argoproj.io_workflowtemplates.yaml +++ b/manifests/base/crds/minimal/argoproj.io_workflowtemplates.yaml @@ -25,6 +25,7 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata diff --git a/manifests/install.yaml b/manifests/install.yaml index b997c55a2225..f75279529e3d 100644 --- a/manifests/install.yaml +++ b/manifests/install.yaml @@ -27,6 +27,7 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata @@ -63,9 +64,11 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true status: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata @@ -101,6 +104,7 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata @@ -146,9 +150,11 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true status: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata @@ -185,6 +191,7 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata diff --git a/manifests/namespace-install.yaml b/manifests/namespace-install.yaml index 4ff9e272ab59..b1a2998a52d4 100644 --- a/manifests/namespace-install.yaml +++ b/manifests/namespace-install.yaml @@ -27,6 +27,7 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata @@ -63,9 +64,11 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true status: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata @@ -101,6 +104,7 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata @@ -146,9 +150,11 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true status: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata @@ -185,6 +191,7 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata diff --git a/manifests/quick-start-minimal.yaml b/manifests/quick-start-minimal.yaml index f5d129e742f8..91ea88491a45 100644 --- a/manifests/quick-start-minimal.yaml +++ b/manifests/quick-start-minimal.yaml @@ -27,6 +27,7 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata @@ -63,9 +64,11 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true status: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata @@ -101,6 +104,7 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata @@ -146,9 +150,11 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true status: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata @@ -185,6 +191,7 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata diff --git a/manifests/quick-start-mysql.yaml b/manifests/quick-start-mysql.yaml index 941ee1bd8ab3..da90a7754a52 100644 --- a/manifests/quick-start-mysql.yaml +++ b/manifests/quick-start-mysql.yaml @@ -27,6 +27,7 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata @@ -63,9 +64,11 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true status: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata @@ -101,6 +104,7 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata @@ -146,9 +150,11 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true status: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata @@ -185,6 +191,7 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata diff --git a/manifests/quick-start-postgres.yaml b/manifests/quick-start-postgres.yaml index ddfc2e14c3fc..c64e86898748 100644 --- a/manifests/quick-start-postgres.yaml +++ b/manifests/quick-start-postgres.yaml @@ -27,6 +27,7 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata @@ -63,9 +64,11 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true status: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata @@ -101,6 +104,7 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata @@ -146,9 +150,11 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true status: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata @@ -185,6 +191,7 @@ spec: type: object spec: type: object + x-kubernetes-map-type: atomic x-kubernetes-preserve-unknown-fields: true required: - metadata diff --git a/util/kubeconfig/kubeconfig.go b/util/kubeconfig/kubeconfig.go index 3dcd32797b79..0784004c175b 100644 --- a/util/kubeconfig/kubeconfig.go +++ b/util/kubeconfig/kubeconfig.go @@ -129,7 +129,8 @@ func GetBearerToken(in *restclient.Config, explicitKubeConfigPath string) (strin } req := http.Request{Header: map[string][]string{}} - _, _ = rt.RoundTrip(&req) + newT := NewUserAgentRoundTripper("dummy", rt) + _, _ = newT.RoundTrip(&req) token := req.Header.Get("Authorization") return strings.TrimPrefix(token, "Bearer "), nil diff --git a/util/kubeconfig/roundtripper.go b/util/kubeconfig/roundtripper.go new file mode 100644 index 000000000000..1eb4bb2fa8a6 --- /dev/null +++ b/util/kubeconfig/roundtripper.go @@ -0,0 +1,17 @@ +package kubeconfig + +import "net/http" + +type userAgentRoundTripper struct { + agent string + rt http.RoundTripper +} + +func (rt userAgentRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { + req.Header.Set("User-Agent", rt.agent) + return rt.rt.RoundTrip(req) +} + +func NewUserAgentRoundTripper(agent string, rt http.RoundTripper) http.RoundTripper { + return &userAgentRoundTripper{agent, rt} +} diff --git a/workflow/controller/operator.go b/workflow/controller/operator.go index 9dfbd17ab8ac..3eb0586bb40e 100644 --- a/workflow/controller/operator.go +++ b/workflow/controller/operator.go @@ -3306,21 +3306,25 @@ func (woc *wfOperationCtx) setStoredWfSpec() error { wfDefault = &wfv1.Workflow{} } - if woc.needsStoredWfSpecUpdate() { + workflowTemplateSpec := woc.wf.Status.StoredWorkflowSpec + + // Load the spec from WorkflowTemplate in first time. + if woc.wf.Status.StoredWorkflowSpec == nil { wftHolder, err := woc.fetchWorkflowSpec() if err != nil { return err } - // Join WFT and WfDefault metadata to Workflow metadata. wfutil.JoinWorkflowMetaData(&woc.wf.ObjectMeta, wftHolder.GetWorkflowMetadata(), &wfDefault.ObjectMeta) - + workflowTemplateSpec = wftHolder.GetWorkflowSpec() + } + // Update the Entrypoint, ShutdownStrategy and Suspend + if woc.needsStoredWfSpecUpdate() { // Join workflow, workflow template, and workflow default metadata to workflow spec. - mergedWf, err := wfutil.JoinWorkflowSpec(&woc.wf.Spec, wftHolder.GetWorkflowSpec(), &wfDefault.Spec) + mergedWf, err := wfutil.JoinWorkflowSpec(&woc.wf.Spec, workflowTemplateSpec, &wfDefault.Spec) if err != nil { return err } - woc.wf.Status.StoredWorkflowSpec = &mergedWf.Spec woc.updated = true } else if woc.controller.Config.WorkflowRestrictions.MustNotChangeSpec() { diff --git a/workflow/controller/operator_workflow_template_ref_test.go b/workflow/controller/operator_workflow_template_ref_test.go index d2556e6964b4..48c2f771932a 100644 --- a/workflow/controller/operator_workflow_template_ref_test.go +++ b/workflow/controller/operator_workflow_template_ref_test.go @@ -436,3 +436,56 @@ func TestSuspendResumeWorkflowTemplateRef(t *testing.T) { woc.operate(ctx) assert.Nil(t, woc.wf.Status.StoredWorkflowSpec.Suspend) } + +const wfTmplUpt = ` +apiVersion: argoproj.io/v1alpha1 +kind: WorkflowTemplate +metadata: + name: workflow-template-whalesay-template + namespace: default +spec: + templates: + - name: hello-hello-hello + steps: + - - name: hello1 + template: whalesay + arguments: + parameters: [{name: message, value: "hello1"}] + - - name: hello2a + template: whalesay + arguments: + parameters: [{name: message, value: "hello2a"}] + - name: hello2b + template: whalesay + arguments: + parameters: [{name: message, value: "hello2b"}] + + - name: whalesay + inputs: + parameters: + - name: message + container: + image: docker/whalesay + command: [cowsay] + args: ["{{inputs.parameters.message}}"] +` + +func TestWorkflowTemplateUpdateScenario(t *testing.T) { + + wf := wfv1.MustUnmarshalWorkflow(wfWithTmplRef) + cancel, controller := newController(wf, wfv1.MustUnmarshalWorkflowTemplate(wfTmpl)) + defer cancel() + ctx := context.Background() + woc := newWorkflowOperationCtx(wf, controller) + woc.operate(ctx) + assert.NotEmpty(t, woc.wf.Status.StoredWorkflowSpec) + assert.NotEmpty(t, woc.wf.Status.StoredWorkflowSpec.Templates[0].Container) + + cancel, controller = newController(woc.wf, wfv1.MustUnmarshalWorkflowTemplate(wfTmplUpt)) + defer cancel() + ctx = context.Background() + woc1 := newWorkflowOperationCtx(woc.wf, controller) + woc1.operate(ctx) + assert.NotEmpty(t, woc1.wf.Status.StoredWorkflowSpec) + assert.Equal(t, woc.wf.Status.StoredWorkflowSpec, woc1.wf.Status.StoredWorkflowSpec) +} diff --git a/workflow/util/merge.go b/workflow/util/merge.go index d5fbcbd1a3a4..fa207f8d39fb 100644 --- a/workflow/util/merge.go +++ b/workflow/util/merge.go @@ -78,6 +78,12 @@ func JoinWorkflowSpec(wfSpec, wftSpec, wfDefaultSpec *wfv1.WorkflowSpec) (*wfv1. return nil, err } } + + // This condition will update the workflow Spec suspend value if merged value is different. + // This scenario will happen when Workflow with WorkflowTemplateRef has suspend template + if wfSpec.Suspend != targetWf.Spec.Suspend { + targetWf.Spec.Suspend = wfSpec.Suspend + } return &targetWf, nil }