From ba4ffdf8d1948302942c9860a1d2fea8f8d6db8e Mon Sep 17 00:00:00 2001 From: Tianchu Zhao Date: Fri, 8 Oct 2021 07:02:42 +1100 Subject: [PATCH 01/64] fix(ui): fixed width button (#6883) Signed-off-by: Tianchu Zhao --- ui/src/app/shared/components/graph/graph-panel.tsx | 8 ++++---- .../workflow-dag/workflow-dag-render-options-panel.tsx | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ui/src/app/shared/components/graph/graph-panel.tsx b/ui/src/app/shared/components/graph/graph-panel.tsx index e9b07a3cc28b..8840527ea6f4 100644 --- a/ui/src/app/shared/components/graph/graph-panel.tsx +++ b/ui/src/app/shared/components/graph/graph-panel.tsx @@ -134,16 +134,16 @@ export const GraphPanel = (props: Props) => { ]} /> setHorizontal(s => !s)} title='Horizontal/vertical layout'> - + setNodeSize(s => s * 1.2)} title='Zoom in'> - + setNodeSize(s => s / 1.2)} title='Zoom out'> - + setFast(s => !s)} title='Use faster, but less pretty renderer' className={fast ? 'active' : ''}> - + {props.options}
diff --git a/ui/src/app/workflows/components/workflow-dag/workflow-dag-render-options-panel.tsx b/ui/src/app/workflows/components/workflow-dag/workflow-dag-render-options-panel.tsx index e9efee3166e3..09e3f0bf3378 100644 --- a/ui/src/app/workflows/components/workflow-dag/workflow-dag-render-options-panel.tsx +++ b/ui/src/app/workflows/components/workflow-dag/workflow-dag-render-options-panel.tsx @@ -17,7 +17,7 @@ export class WorkflowDagRenderOptionsPanel extends React.Component - + @@ -27,7 +27,7 @@ export class WorkflowDagRenderOptionsPanel extends React.Component - + ); From d31860cd1d20c07ce28b0e7035fbf210019fa38a Mon Sep 17 00:00:00 2001 From: Saravanan Balasubramanian <33908564+sarabala1979@users.noreply.github.com> Date: Thu, 7 Oct 2021 13:58:10 -0700 Subject: [PATCH 02/64] fix: Parameter with Value and Default (#6887) Signed-off-by: Saravanan Balasubramanian --- workflow/common/util.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow/common/util.go b/workflow/common/util.go index a3fcd5f98ff5..f0fe15cac3b4 100644 --- a/workflow/common/util.go +++ b/workflow/common/util.go @@ -124,7 +124,7 @@ func ProcessArgs(tmpl *wfv1.Template, args wfv1.ArgumentsProvider, globalParams, // 3) if no default value, it is an error newTmpl := tmpl.DeepCopy() for i, inParam := range newTmpl.Inputs.Parameters { - if inParam.Default != nil { + if inParam.Value == nil && inParam.Default != nil { // first set to default value inParam.Value = inParam.Default } From 15e9ba84d1b783fe26ed0e507b1d5a868b43ee0e Mon Sep 17 00:00:00 2001 From: Iven Date: Tue, 19 Oct 2021 00:54:44 +0800 Subject: [PATCH 03/64] fix: Skip empty withParam tasks. Fixes #6834 (#6912) Signed-off-by: Iven Hsu --- test/e2e/functional/dag-empty-param.yaml | 39 ++++++++++++++++++++++++ test/e2e/functional_test.go | 17 +++++++++++ workflow/controller/dag.go | 7 ++++- 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 test/e2e/functional/dag-empty-param.yaml diff --git a/test/e2e/functional/dag-empty-param.yaml b/test/e2e/functional/dag-empty-param.yaml new file mode 100644 index 000000000000..6593c4af9ff4 --- /dev/null +++ b/test/e2e/functional/dag-empty-param.yaml @@ -0,0 +1,39 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: dag-param-result- +spec: + entrypoint: dag-param-result-example + templates: + - name: dag-param-result-example + dag: + tasks: + - name: generate + template: gen-number-list + - name: sleep + template: sleep-n-sec + arguments: + parameters: + - name: seconds + value: "{{item}}" + withParam: "{{tasks.generate.outputs.result}}" + dependencies: + - generate + + - name: gen-number-list + script: + image: python:alpine3.6 + command: [python] + source: | + import json + import sys + json.dump([i for i in range(0, -1)], sys.stdout) + + - name: sleep-n-sec + inputs: + parameters: + - name: seconds + container: + image: argoproj/argosay:v1 + command: [sh, -c] + args: ["echo sleeping for {{inputs.parameters.seconds}} seconds; sleep {{inputs.parameters.seconds}}; echo done"] diff --git a/test/e2e/functional_test.go b/test/e2e/functional_test.go index 9cd3a620afdd..69acc67b6898 100644 --- a/test/e2e/functional_test.go +++ b/test/e2e/functional_test.go @@ -400,6 +400,23 @@ func (s *FunctionalSuite) TestLoopEmptyParam() { }) } +func (s *FunctionalSuite) TestDAGEmptyParam() { + s.Given(). + Workflow("@functional/dag-empty-param.yaml"). + When(). + SubmitWorkflow(). + WaitForWorkflow(). + Then(). + ExpectWorkflow(func(t *testing.T, _ *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + assert.Equal(t, wfv1.WorkflowSucceeded, status.Phase) + if assert.Len(t, status.Nodes, 3) { + nodeStatus := status.Nodes.FindByDisplayName("sleep") + assert.Equal(t, wfv1.NodeSkipped, nodeStatus.Phase) + assert.Equal(t, "Skipped, empty params", nodeStatus.Message) + } + }) +} + // 128M is for argo executor func (s *FunctionalSuite) TestPendingRetryWorkflow() { s.Given(). diff --git a/workflow/controller/dag.go b/workflow/controller/dag.go index 1813c713482e..8705c6eb40a9 100644 --- a/workflow/controller/dag.go +++ b/workflow/controller/dag.go @@ -437,7 +437,12 @@ func (woc *wfOperationCtx) executeDAGTask(ctx context.Context, dagCtx *dagContex // For example, if we had task A with withItems of ['foo', 'bar'] which expanded to ['A(0:foo)', 'A(1:bar)'], we still // need to create a node for A. if task.ShouldExpand() { - if taskGroupNode == nil { + // DAG task with empty withParams list should be skipped + if len(expandedTasks) == 0 { + skipReason := "Skipped, empty params" + woc.initializeNode(nodeName, wfv1.NodeTypeSkipped, dagTemplateScope, task, dagCtx.boundaryID, wfv1.NodeSkipped, skipReason) + connectDependencies(nodeName) + } else if taskGroupNode == nil { connectDependencies(nodeName) taskGroupNode = woc.initializeNode(nodeName, wfv1.NodeTypeTaskGroup, dagTemplateScope, task, dagCtx.boundaryID, wfv1.NodeRunning, "") } From 2fbeb80f0c320805de72c42ea5b106ab31f560a8 Mon Sep 17 00:00:00 2001 From: Bob Haddleton Date: Mon, 18 Oct 2021 11:55:44 -0500 Subject: [PATCH 04/64] fix(executor): add test for non-root user creating a script (#6905) Signed-off-by: Bob Haddleton --- test/e2e/functional_test.go | 28 ++++++++++++++++++++++++++++ workflow/executor/executor.go | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/test/e2e/functional_test.go b/test/e2e/functional_test.go index 69acc67b6898..39ce9dc92fd9 100644 --- a/test/e2e/functional_test.go +++ b/test/e2e/functional_test.go @@ -809,6 +809,34 @@ func (s *FunctionalSuite) TestDataTransformation() { }) } +func (s *FunctionalSuite) TestScriptAsNonRoot() { + s.Given(). + Workflow(` +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: script-nonroot- +spec: + entrypoint: whalesay + securityContext: + runAsUser: 1000 + runAsGroup: 1000 + runAsNonRoot: true + templates: + - name: whalesay + script: + image: argoproj/argosay:v2 + command: ["bash"] + source: | + ls -l /argo/staging + cat /argo/stahing/script + sleep 10s +`). + When(). + SubmitWorkflow(). + WaitForWorkflow(fixtures.ToBeSucceeded) +} + func TestFunctionalSuite(t *testing.T) { suite.Run(t, new(FunctionalSuite)) } diff --git a/workflow/executor/executor.go b/workflow/executor/executor.go index e3fee86eb455..4beee60e48c1 100644 --- a/workflow/executor/executor.go +++ b/workflow/executor/executor.go @@ -251,7 +251,7 @@ func (we *WorkflowExecutor) StageFiles() error { default: return nil } - err := ioutil.WriteFile(filePath, body, 0o600) + err := ioutil.WriteFile(filePath, body, 0o644) if err != nil { return errors.InternalWrapError(err) } From 32ecc4654cda8e84d6bb7a696675e14da8665747 Mon Sep 17 00:00:00 2001 From: SalvadorC Date: Mon, 18 Oct 2021 21:37:08 +0200 Subject: [PATCH 05/64] fix: Unreachable code in util/tls/tls.go. Fixes #6950 (#6960) Signed-off-by: chavacava --- util/tls/tls.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/tls/tls.go b/util/tls/tls.go index 227b04e2c9c7..b5a77495fe92 100644 --- a/util/tls/tls.go +++ b/util/tls/tls.go @@ -22,7 +22,7 @@ func pemBlockForKey(priv interface{}) *pem.Block { case *ecdsa.PrivateKey: b, err := x509.MarshalECPrivateKey(k) if err != nil { - log.Fatal(err) + log.Print(err) os.Exit(2) } return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b} From 46f88f4230b546863f83ccf56b94697e39ab0e11 Mon Sep 17 00:00:00 2001 From: Miroslav Tomasik Date: Tue, 19 Oct 2021 17:13:30 +0200 Subject: [PATCH 06/64] fix: response on canceled workflow action (#6859) (#6967) Signed-off-by: Miro Tomasik --- .../workflows-toolbar/workflows-toolbar.tsx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/ui/src/app/workflows/components/workflows-toolbar/workflows-toolbar.tsx b/ui/src/app/workflows/components/workflows-toolbar/workflows-toolbar.tsx index 6938bc15b07e..c0ab53e9cd92 100644 --- a/ui/src/app/workflows/components/workflows-toolbar/workflows-toolbar.tsx +++ b/ui/src/app/workflows/components/workflows-toolbar/workflows-toolbar.tsx @@ -53,7 +53,7 @@ export class WorkflowsToolbar extends React.Component private performActionOnSelectedWorkflows(ctx: any, title: string, action: WorkflowOperationAction): Promise { if (!confirm(`Are you sure you want to ${title.toLowerCase()} all selected workflows?`)) { - return Promise.resolve(); + return Promise.resolve(false); } const promises: Promise[] = []; this.props.selectedWorkflows.forEach((wf: Workflow) => { @@ -82,13 +82,15 @@ export class WorkflowsToolbar extends React.Component groupIsDisabled: disabled[actionName], action, groupAction: () => { - return this.performActionOnSelectedWorkflows(ctx, action.title, action.action).then(() => { - this.props.clearSelection(); - this.appContext.apis.notifications.show({ - content: `Performed '${action.title}' on selected workflows.`, - type: NotificationType.Success - }); - this.props.loadWorkflows(); + return this.performActionOnSelectedWorkflows(ctx, action.title, action.action).then(confirmed => { + if (confirmed) { + this.props.clearSelection(); + this.appContext.apis.notifications.show({ + content: `Performed '${action.title}' on selected workflows.`, + type: NotificationType.Success + }); + this.props.loadWorkflows(); + } }); }, className: action.title, From 7ab0ad42dee57f7b42e21c3a64b675d81661f753 Mon Sep 17 00:00:00 2001 From: Alex Collins Date: Wed, 17 Nov 2021 11:09:01 -0800 Subject: [PATCH 07/64] chore: make pre-commit Signed-off-by: Alex Collins --- .../workflow/v1alpha1/openapi_generated.go | 1 + .../v1alpha1/zz_generated.deepcopy.go | 1 + .../client/docs/ArchivedWorkflowServiceApi.md | 142 +----------------- ...IoArgoprojEventsV1alpha1AMQPEventSource.md | 1 - ...goprojEventsV1alpha1ArgoWorkflowTrigger.md | 1 + ...ventsV1alpha1BitbucketServerEventSource.md | 21 --- ...goprojEventsV1alpha1CalendarEventSource.md | 1 + .../IoArgoprojEventsV1alpha1CustomTrigger.md | 1 + ...IoArgoprojEventsV1alpha1DependencyGroup.md | 14 ++ ...IoArgoprojEventsV1alpha1EventSourceSpec.md | 2 +- .../IoArgoprojEventsV1alpha1GitArtifact.md | 1 + ...ArgoprojEventsV1alpha1GitlabEventSource.md | 2 - ...ArgoprojEventsV1alpha1PubSubEventSource.md | 1 + ...ArgoprojEventsV1alpha1PulsarEventSource.md | 1 - .../IoArgoprojEventsV1alpha1PulsarTrigger.md | 23 --- .../docs/IoArgoprojEventsV1alpha1RateLimit.md | 14 -- .../IoArgoprojEventsV1alpha1SensorSpec.md | 2 + ...rgoprojEventsV1alpha1StandardK8STrigger.md | 1 + .../docs/IoArgoprojEventsV1alpha1TLSConfig.md | 3 + .../docs/IoArgoprojEventsV1alpha1Trigger.md | 1 - .../IoArgoprojEventsV1alpha1TriggerSwitch.md | 14 ++ ...IoArgoprojEventsV1alpha1TriggerTemplate.md | 2 +- .../IoArgoprojEventsV1alpha1WebhookContext.md | 2 + .../IoArgoprojWorkflowV1alpha1LabelKeys.md | 14 -- .../IoArgoprojWorkflowV1alpha1LabelValues.md | 14 -- 25 files changed, 47 insertions(+), 233 deletions(-) delete mode 100644 sdks/java/client/docs/IoArgoprojEventsV1alpha1BitbucketServerEventSource.md create mode 100644 sdks/java/client/docs/IoArgoprojEventsV1alpha1DependencyGroup.md delete mode 100644 sdks/java/client/docs/IoArgoprojEventsV1alpha1PulsarTrigger.md delete mode 100644 sdks/java/client/docs/IoArgoprojEventsV1alpha1RateLimit.md create mode 100644 sdks/java/client/docs/IoArgoprojEventsV1alpha1TriggerSwitch.md delete mode 100644 sdks/java/client/docs/IoArgoprojWorkflowV1alpha1LabelKeys.md delete mode 100644 sdks/java/client/docs/IoArgoprojWorkflowV1alpha1LabelValues.md diff --git a/pkg/apis/workflow/v1alpha1/openapi_generated.go b/pkg/apis/workflow/v1alpha1/openapi_generated.go index 88469c2c2dba..70e09b67c52d 100644 --- a/pkg/apis/workflow/v1alpha1/openapi_generated.go +++ b/pkg/apis/workflow/v1alpha1/openapi_generated.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated // Code generated by openapi-gen. DO NOT EDIT. diff --git a/pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go index 23dadd4ed449..f12226e4786e 100644 --- a/pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated // Code generated by deepcopy-gen. DO NOT EDIT. diff --git a/sdks/java/client/docs/ArchivedWorkflowServiceApi.md b/sdks/java/client/docs/ArchivedWorkflowServiceApi.md index d55cba1d801a..11fd542ece0e 100644 --- a/sdks/java/client/docs/ArchivedWorkflowServiceApi.md +++ b/sdks/java/client/docs/ArchivedWorkflowServiceApi.md @@ -6,8 +6,6 @@ Method | HTTP request | Description ------------- | ------------- | ------------- [**archivedWorkflowServiceDeleteArchivedWorkflow**](ArchivedWorkflowServiceApi.md#archivedWorkflowServiceDeleteArchivedWorkflow) | **DELETE** /api/v1/archived-workflows/{uid} | [**archivedWorkflowServiceGetArchivedWorkflow**](ArchivedWorkflowServiceApi.md#archivedWorkflowServiceGetArchivedWorkflow) | **GET** /api/v1/archived-workflows/{uid} | -[**archivedWorkflowServiceListArchivedWorkflowLabelKeys**](ArchivedWorkflowServiceApi.md#archivedWorkflowServiceListArchivedWorkflowLabelKeys) | **GET** /api/v1/archived-workflows-label-keys | -[**archivedWorkflowServiceListArchivedWorkflowLabelValues**](ArchivedWorkflowServiceApi.md#archivedWorkflowServiceListArchivedWorkflowLabelValues) | **GET** /api/v1/archived-workflows-label-values | [**archivedWorkflowServiceListArchivedWorkflows**](ArchivedWorkflowServiceApi.md#archivedWorkflowServiceListArchivedWorkflows) | **GET** /api/v1/archived-workflows | @@ -133,143 +131,9 @@ No authorization required **200** | A successful response. | - | **0** | An unexpected error response. | - | - -# **archivedWorkflowServiceListArchivedWorkflowLabelKeys** -> IoArgoprojWorkflowV1alpha1LabelKeys archivedWorkflowServiceListArchivedWorkflowLabelKeys() - - - -### Example -```java -// Import classes: -import io.argoproj.workflow.ApiClient; -import io.argoproj.workflow.ApiException; -import io.argoproj.workflow.Configuration; -import io.argoproj.workflow.models.*; -import io.argoproj.workflow.apis.ArchivedWorkflowServiceApi; - -public class Example { - public static void main(String[] args) { - ApiClient defaultClient = Configuration.getDefaultApiClient(); - defaultClient.setBasePath("http://localhost:2746"); - - ArchivedWorkflowServiceApi apiInstance = new ArchivedWorkflowServiceApi(defaultClient); - try { - IoArgoprojWorkflowV1alpha1LabelKeys result = apiInstance.archivedWorkflowServiceListArchivedWorkflowLabelKeys(); - System.out.println(result); - } catch (ApiException e) { - System.err.println("Exception when calling ArchivedWorkflowServiceApi#archivedWorkflowServiceListArchivedWorkflowLabelKeys"); - System.err.println("Status code: " + e.getCode()); - System.err.println("Reason: " + e.getResponseBody()); - System.err.println("Response headers: " + e.getResponseHeaders()); - e.printStackTrace(); - } - } -} -``` - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**IoArgoprojWorkflowV1alpha1LabelKeys**](IoArgoprojWorkflowV1alpha1LabelKeys.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -### HTTP response details -| Status code | Description | Response headers | -|-------------|-------------|------------------| -**200** | A successful response. | - | -**0** | An unexpected error response. | - | - - -# **archivedWorkflowServiceListArchivedWorkflowLabelValues** -> IoArgoprojWorkflowV1alpha1LabelValues archivedWorkflowServiceListArchivedWorkflowLabelValues(listOptionsLabelSelector, listOptionsFieldSelector, listOptionsWatch, listOptionsAllowWatchBookmarks, listOptionsResourceVersion, listOptionsResourceVersionMatch, listOptionsTimeoutSeconds, listOptionsLimit, listOptionsContinue) - - - -### Example -```java -// Import classes: -import io.argoproj.workflow.ApiClient; -import io.argoproj.workflow.ApiException; -import io.argoproj.workflow.Configuration; -import io.argoproj.workflow.models.*; -import io.argoproj.workflow.apis.ArchivedWorkflowServiceApi; - -public class Example { - public static void main(String[] args) { - ApiClient defaultClient = Configuration.getDefaultApiClient(); - defaultClient.setBasePath("http://localhost:2746"); - - ArchivedWorkflowServiceApi apiInstance = new ArchivedWorkflowServiceApi(defaultClient); - String listOptionsLabelSelector = "listOptionsLabelSelector_example"; // String | A selector to restrict the list of returned objects by their labels. Defaults to everything. +optional. - String listOptionsFieldSelector = "listOptionsFieldSelector_example"; // String | A selector to restrict the list of returned objects by their fields. Defaults to everything. +optional. - Boolean listOptionsWatch = true; // Boolean | Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion. +optional. - Boolean listOptionsAllowWatchBookmarks = true; // Boolean | allowWatchBookmarks requests watch events with type \"BOOKMARK\". Servers that do not implement bookmarks may ignore this flag and bookmarks are sent at the server's discretion. Clients should not assume bookmarks are returned at any specific interval, nor may they assume the server will send any BOOKMARK event during a session. If this is not a watch, this field is ignored. If the feature gate WatchBookmarks is not enabled in apiserver, this field is ignored. +optional. - String listOptionsResourceVersion = "listOptionsResourceVersion_example"; // String | resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. Defaults to unset +optional - String listOptionsResourceVersionMatch = "listOptionsResourceVersionMatch_example"; // String | resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. Defaults to unset +optional - String listOptionsTimeoutSeconds = "listOptionsTimeoutSeconds_example"; // String | Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. +optional. - String listOptionsLimit = "listOptionsLimit_example"; // String | limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. - String listOptionsContinue = "listOptionsContinue_example"; // String | The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the \"next key\". This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. - try { - IoArgoprojWorkflowV1alpha1LabelValues result = apiInstance.archivedWorkflowServiceListArchivedWorkflowLabelValues(listOptionsLabelSelector, listOptionsFieldSelector, listOptionsWatch, listOptionsAllowWatchBookmarks, listOptionsResourceVersion, listOptionsResourceVersionMatch, listOptionsTimeoutSeconds, listOptionsLimit, listOptionsContinue); - System.out.println(result); - } catch (ApiException e) { - System.err.println("Exception when calling ArchivedWorkflowServiceApi#archivedWorkflowServiceListArchivedWorkflowLabelValues"); - System.err.println("Status code: " + e.getCode()); - System.err.println("Reason: " + e.getResponseBody()); - System.err.println("Response headers: " + e.getResponseHeaders()); - e.printStackTrace(); - } - } -} -``` - -### Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **listOptionsLabelSelector** | **String**| A selector to restrict the list of returned objects by their labels. Defaults to everything. +optional. | [optional] - **listOptionsFieldSelector** | **String**| A selector to restrict the list of returned objects by their fields. Defaults to everything. +optional. | [optional] - **listOptionsWatch** | **Boolean**| Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion. +optional. | [optional] - **listOptionsAllowWatchBookmarks** | **Boolean**| allowWatchBookmarks requests watch events with type \"BOOKMARK\". Servers that do not implement bookmarks may ignore this flag and bookmarks are sent at the server's discretion. Clients should not assume bookmarks are returned at any specific interval, nor may they assume the server will send any BOOKMARK event during a session. If this is not a watch, this field is ignored. If the feature gate WatchBookmarks is not enabled in apiserver, this field is ignored. +optional. | [optional] - **listOptionsResourceVersion** | **String**| resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. Defaults to unset +optional | [optional] - **listOptionsResourceVersionMatch** | **String**| resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details. Defaults to unset +optional | [optional] - **listOptionsTimeoutSeconds** | **String**| Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. +optional. | [optional] - **listOptionsLimit** | **String**| limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. | [optional] - **listOptionsContinue** | **String**| The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the \"next key\". This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. | [optional] - -### Return type - -[**IoArgoprojWorkflowV1alpha1LabelValues**](IoArgoprojWorkflowV1alpha1LabelValues.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -### HTTP response details -| Status code | Description | Response headers | -|-------------|-------------|------------------| -**200** | A successful response. | - | -**0** | An unexpected error response. | - | - # **archivedWorkflowServiceListArchivedWorkflows** -> IoArgoprojWorkflowV1alpha1WorkflowList archivedWorkflowServiceListArchivedWorkflows(listOptionsLabelSelector, listOptionsFieldSelector, listOptionsWatch, listOptionsAllowWatchBookmarks, listOptionsResourceVersion, listOptionsResourceVersionMatch, listOptionsTimeoutSeconds, listOptionsLimit, listOptionsContinue, namePrefix) +> IoArgoprojWorkflowV1alpha1WorkflowList archivedWorkflowServiceListArchivedWorkflows(listOptionsLabelSelector, listOptionsFieldSelector, listOptionsWatch, listOptionsAllowWatchBookmarks, listOptionsResourceVersion, listOptionsResourceVersionMatch, listOptionsTimeoutSeconds, listOptionsLimit, listOptionsContinue) @@ -297,9 +161,8 @@ public class Example { String listOptionsTimeoutSeconds = "listOptionsTimeoutSeconds_example"; // String | Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. +optional. String listOptionsLimit = "listOptionsLimit_example"; // String | limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. String listOptionsContinue = "listOptionsContinue_example"; // String | The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the \"next key\". This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. - String namePrefix = "namePrefix_example"; // String | try { - IoArgoprojWorkflowV1alpha1WorkflowList result = apiInstance.archivedWorkflowServiceListArchivedWorkflows(listOptionsLabelSelector, listOptionsFieldSelector, listOptionsWatch, listOptionsAllowWatchBookmarks, listOptionsResourceVersion, listOptionsResourceVersionMatch, listOptionsTimeoutSeconds, listOptionsLimit, listOptionsContinue, namePrefix); + IoArgoprojWorkflowV1alpha1WorkflowList result = apiInstance.archivedWorkflowServiceListArchivedWorkflows(listOptionsLabelSelector, listOptionsFieldSelector, listOptionsWatch, listOptionsAllowWatchBookmarks, listOptionsResourceVersion, listOptionsResourceVersionMatch, listOptionsTimeoutSeconds, listOptionsLimit, listOptionsContinue); System.out.println(result); } catch (ApiException e) { System.err.println("Exception when calling ArchivedWorkflowServiceApi#archivedWorkflowServiceListArchivedWorkflows"); @@ -325,7 +188,6 @@ Name | Type | Description | Notes **listOptionsTimeoutSeconds** | **String**| Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity. +optional. | [optional] **listOptionsLimit** | **String**| limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true. The server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned. | [optional] **listOptionsContinue** | **String**| The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the \"next key\". This field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications. | [optional] - **namePrefix** | **String**| | [optional] ### Return type diff --git a/sdks/java/client/docs/IoArgoprojEventsV1alpha1AMQPEventSource.md b/sdks/java/client/docs/IoArgoprojEventsV1alpha1AMQPEventSource.md index a99f78e876f0..934fcb3e8d05 100644 --- a/sdks/java/client/docs/IoArgoprojEventsV1alpha1AMQPEventSource.md +++ b/sdks/java/client/docs/IoArgoprojEventsV1alpha1AMQPEventSource.md @@ -20,7 +20,6 @@ Name | Type | Description | Notes **routingKey** | **String** | | [optional] **tls** | [**IoArgoprojEventsV1alpha1TLSConfig**](IoArgoprojEventsV1alpha1TLSConfig.md) | | [optional] **url** | **String** | | [optional] -**urlSecret** | [**io.kubernetes.client.openapi.models.V1SecretKeySelector**](io.kubernetes.client.openapi.models.V1SecretKeySelector.md) | | [optional] diff --git a/sdks/java/client/docs/IoArgoprojEventsV1alpha1ArgoWorkflowTrigger.md b/sdks/java/client/docs/IoArgoprojEventsV1alpha1ArgoWorkflowTrigger.md index 5bb3c5a40bdc..7a9b70b633ac 100644 --- a/sdks/java/client/docs/IoArgoprojEventsV1alpha1ArgoWorkflowTrigger.md +++ b/sdks/java/client/docs/IoArgoprojEventsV1alpha1ArgoWorkflowTrigger.md @@ -7,6 +7,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- +**groupVersionResource** | [**GroupVersionResource**](GroupVersionResource.md) | | [optional] **operation** | **String** | | [optional] **parameters** | [**List<IoArgoprojEventsV1alpha1TriggerParameter>**](IoArgoprojEventsV1alpha1TriggerParameter.md) | | [optional] **source** | [**IoArgoprojEventsV1alpha1ArtifactLocation**](IoArgoprojEventsV1alpha1ArtifactLocation.md) | | [optional] diff --git a/sdks/java/client/docs/IoArgoprojEventsV1alpha1BitbucketServerEventSource.md b/sdks/java/client/docs/IoArgoprojEventsV1alpha1BitbucketServerEventSource.md deleted file mode 100644 index 32c6d22adf37..000000000000 --- a/sdks/java/client/docs/IoArgoprojEventsV1alpha1BitbucketServerEventSource.md +++ /dev/null @@ -1,21 +0,0 @@ - - -# IoArgoprojEventsV1alpha1BitbucketServerEventSource - - -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**accessToken** | [**io.kubernetes.client.openapi.models.V1SecretKeySelector**](io.kubernetes.client.openapi.models.V1SecretKeySelector.md) | | [optional] -**bitbucketserverBaseURL** | **String** | | [optional] -**deleteHookOnFinish** | **Boolean** | | [optional] -**events** | **List<String>** | | [optional] -**metadata** | **Map<String, String>** | | [optional] -**projectKey** | **String** | | [optional] -**repositorySlug** | **String** | | [optional] -**webhook** | [**IoArgoprojEventsV1alpha1WebhookContext**](IoArgoprojEventsV1alpha1WebhookContext.md) | | [optional] -**webhookSecret** | [**io.kubernetes.client.openapi.models.V1SecretKeySelector**](io.kubernetes.client.openapi.models.V1SecretKeySelector.md) | | [optional] - - - diff --git a/sdks/java/client/docs/IoArgoprojEventsV1alpha1CalendarEventSource.md b/sdks/java/client/docs/IoArgoprojEventsV1alpha1CalendarEventSource.md index 188bdc282c9d..6f082c8aed9d 100644 --- a/sdks/java/client/docs/IoArgoprojEventsV1alpha1CalendarEventSource.md +++ b/sdks/java/client/docs/IoArgoprojEventsV1alpha1CalendarEventSource.md @@ -13,6 +13,7 @@ Name | Type | Description | Notes **persistence** | [**IoArgoprojEventsV1alpha1EventPersistence**](IoArgoprojEventsV1alpha1EventPersistence.md) | | [optional] **schedule** | **String** | | [optional] **timezone** | **String** | | [optional] +**userPayload** | **byte[]** | UserPayload will be sent to sensor as extra data once the event is triggered +optional Deprecated: will be removed in v1.5. Please use Metadata instead. | [optional] diff --git a/sdks/java/client/docs/IoArgoprojEventsV1alpha1CustomTrigger.md b/sdks/java/client/docs/IoArgoprojEventsV1alpha1CustomTrigger.md index cee9ce1e2eac..c67e6afc29f5 100644 --- a/sdks/java/client/docs/IoArgoprojEventsV1alpha1CustomTrigger.md +++ b/sdks/java/client/docs/IoArgoprojEventsV1alpha1CustomTrigger.md @@ -8,6 +8,7 @@ CustomTrigger refers to the specification of the custom trigger. Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- +**certFilePath** | **String** | | [optional] **certSecret** | [**io.kubernetes.client.openapi.models.V1SecretKeySelector**](io.kubernetes.client.openapi.models.V1SecretKeySelector.md) | | [optional] **parameters** | [**List<IoArgoprojEventsV1alpha1TriggerParameter>**](IoArgoprojEventsV1alpha1TriggerParameter.md) | Parameters is the list of parameters that is applied to resolved custom trigger trigger object. | [optional] **payload** | [**List<IoArgoprojEventsV1alpha1TriggerParameter>**](IoArgoprojEventsV1alpha1TriggerParameter.md) | Payload is the list of key-value extracted from an event payload to construct the request payload. | [optional] diff --git a/sdks/java/client/docs/IoArgoprojEventsV1alpha1DependencyGroup.md b/sdks/java/client/docs/IoArgoprojEventsV1alpha1DependencyGroup.md new file mode 100644 index 000000000000..ccc66bd9ab44 --- /dev/null +++ b/sdks/java/client/docs/IoArgoprojEventsV1alpha1DependencyGroup.md @@ -0,0 +1,14 @@ + + +# IoArgoprojEventsV1alpha1DependencyGroup + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**dependencies** | **List<String>** | | [optional] +**name** | **String** | | [optional] + + + diff --git a/sdks/java/client/docs/IoArgoprojEventsV1alpha1EventSourceSpec.md b/sdks/java/client/docs/IoArgoprojEventsV1alpha1EventSourceSpec.md index cef4d0e9549f..9146d67d2aaf 100644 --- a/sdks/java/client/docs/IoArgoprojEventsV1alpha1EventSourceSpec.md +++ b/sdks/java/client/docs/IoArgoprojEventsV1alpha1EventSourceSpec.md @@ -9,7 +9,6 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **amqp** | [**Map<String, IoArgoprojEventsV1alpha1AMQPEventSource>**](IoArgoprojEventsV1alpha1AMQPEventSource.md) | | [optional] **azureEventsHub** | [**Map<String, IoArgoprojEventsV1alpha1AzureEventsHubEventSource>**](IoArgoprojEventsV1alpha1AzureEventsHubEventSource.md) | | [optional] -**bitbucketserver** | [**Map<String, IoArgoprojEventsV1alpha1BitbucketServerEventSource>**](IoArgoprojEventsV1alpha1BitbucketServerEventSource.md) | | [optional] **calendar** | [**Map<String, IoArgoprojEventsV1alpha1CalendarEventSource>**](IoArgoprojEventsV1alpha1CalendarEventSource.md) | | [optional] **emitter** | [**Map<String, IoArgoprojEventsV1alpha1EmitterEventSource>**](IoArgoprojEventsV1alpha1EmitterEventSource.md) | | [optional] **eventBusName** | **String** | | [optional] @@ -26,6 +25,7 @@ Name | Type | Description | Notes **pubSub** | [**Map<String, IoArgoprojEventsV1alpha1PubSubEventSource>**](IoArgoprojEventsV1alpha1PubSubEventSource.md) | | [optional] **pulsar** | [**Map<String, IoArgoprojEventsV1alpha1PulsarEventSource>**](IoArgoprojEventsV1alpha1PulsarEventSource.md) | | [optional] **redis** | [**Map<String, IoArgoprojEventsV1alpha1RedisEventSource>**](IoArgoprojEventsV1alpha1RedisEventSource.md) | | [optional] +**replica** | **Integer** | | [optional] **replicas** | **Integer** | | [optional] **resource** | [**Map<String, IoArgoprojEventsV1alpha1ResourceEventSource>**](IoArgoprojEventsV1alpha1ResourceEventSource.md) | | [optional] **service** | [**IoArgoprojEventsV1alpha1Service**](IoArgoprojEventsV1alpha1Service.md) | | [optional] diff --git a/sdks/java/client/docs/IoArgoprojEventsV1alpha1GitArtifact.md b/sdks/java/client/docs/IoArgoprojEventsV1alpha1GitArtifact.md index 6a983e5855ee..783e04b80ea3 100644 --- a/sdks/java/client/docs/IoArgoprojEventsV1alpha1GitArtifact.md +++ b/sdks/java/client/docs/IoArgoprojEventsV1alpha1GitArtifact.md @@ -13,6 +13,7 @@ Name | Type | Description | Notes **filePath** | **String** | | [optional] **ref** | **String** | | [optional] **remote** | [**IoArgoprojEventsV1alpha1GitRemoteConfig**](IoArgoprojEventsV1alpha1GitRemoteConfig.md) | | [optional] +**sshKeyPath** | **String** | | [optional] **sshKeySecret** | [**io.kubernetes.client.openapi.models.V1SecretKeySelector**](io.kubernetes.client.openapi.models.V1SecretKeySelector.md) | | [optional] **tag** | **String** | | [optional] **url** | **String** | | [optional] diff --git a/sdks/java/client/docs/IoArgoprojEventsV1alpha1GitlabEventSource.md b/sdks/java/client/docs/IoArgoprojEventsV1alpha1GitlabEventSource.md index b6f81675c446..22f52714185b 100644 --- a/sdks/java/client/docs/IoArgoprojEventsV1alpha1GitlabEventSource.md +++ b/sdks/java/client/docs/IoArgoprojEventsV1alpha1GitlabEventSource.md @@ -14,8 +14,6 @@ Name | Type | Description | Notes **gitlabBaseURL** | **String** | | [optional] **metadata** | **Map<String, String>** | | [optional] **projectID** | **String** | | [optional] -**projects** | **List<String>** | | [optional] -**secretToken** | [**io.kubernetes.client.openapi.models.V1SecretKeySelector**](io.kubernetes.client.openapi.models.V1SecretKeySelector.md) | | [optional] **webhook** | [**IoArgoprojEventsV1alpha1WebhookContext**](IoArgoprojEventsV1alpha1WebhookContext.md) | | [optional] diff --git a/sdks/java/client/docs/IoArgoprojEventsV1alpha1PubSubEventSource.md b/sdks/java/client/docs/IoArgoprojEventsV1alpha1PubSubEventSource.md index df6e2525914d..4940563b6250 100644 --- a/sdks/java/client/docs/IoArgoprojEventsV1alpha1PubSubEventSource.md +++ b/sdks/java/client/docs/IoArgoprojEventsV1alpha1PubSubEventSource.md @@ -9,6 +9,7 @@ PubSubEventSource refers to event-source for GCP PubSub related events. Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **credentialSecret** | [**io.kubernetes.client.openapi.models.V1SecretKeySelector**](io.kubernetes.client.openapi.models.V1SecretKeySelector.md) | | [optional] +**credentialsFile** | **String** | | [optional] **deleteSubscriptionOnFinish** | **Boolean** | | [optional] **jsonBody** | **Boolean** | | [optional] **metadata** | **Map<String, String>** | | [optional] diff --git a/sdks/java/client/docs/IoArgoprojEventsV1alpha1PulsarEventSource.md b/sdks/java/client/docs/IoArgoprojEventsV1alpha1PulsarEventSource.md index 1e51e2ee0e5b..d1be22b906ae 100644 --- a/sdks/java/client/docs/IoArgoprojEventsV1alpha1PulsarEventSource.md +++ b/sdks/java/client/docs/IoArgoprojEventsV1alpha1PulsarEventSource.md @@ -7,7 +7,6 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**authTokenSecret** | [**io.kubernetes.client.openapi.models.V1SecretKeySelector**](io.kubernetes.client.openapi.models.V1SecretKeySelector.md) | | [optional] **connectionBackoff** | [**IoArgoprojEventsV1alpha1Backoff**](IoArgoprojEventsV1alpha1Backoff.md) | | [optional] **jsonBody** | **Boolean** | | [optional] **metadata** | **Map<String, String>** | | [optional] diff --git a/sdks/java/client/docs/IoArgoprojEventsV1alpha1PulsarTrigger.md b/sdks/java/client/docs/IoArgoprojEventsV1alpha1PulsarTrigger.md deleted file mode 100644 index f8f0de0c6f89..000000000000 --- a/sdks/java/client/docs/IoArgoprojEventsV1alpha1PulsarTrigger.md +++ /dev/null @@ -1,23 +0,0 @@ - - -# IoArgoprojEventsV1alpha1PulsarTrigger - -PulsarTrigger refers to the specification of the Pulsar trigger. - -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**authTokenSecret** | [**io.kubernetes.client.openapi.models.V1SecretKeySelector**](io.kubernetes.client.openapi.models.V1SecretKeySelector.md) | | [optional] -**connectionBackoff** | [**IoArgoprojEventsV1alpha1Backoff**](IoArgoprojEventsV1alpha1Backoff.md) | | [optional] -**parameters** | [**List<IoArgoprojEventsV1alpha1TriggerParameter>**](IoArgoprojEventsV1alpha1TriggerParameter.md) | Parameters is the list of parameters that is applied to resolved Kafka trigger object. | [optional] -**payload** | [**List<IoArgoprojEventsV1alpha1TriggerParameter>**](IoArgoprojEventsV1alpha1TriggerParameter.md) | Payload is the list of key-value extracted from an event payload to construct the request payload. | [optional] -**tls** | [**IoArgoprojEventsV1alpha1TLSConfig**](IoArgoprojEventsV1alpha1TLSConfig.md) | | [optional] -**tlsAllowInsecureConnection** | **Boolean** | | [optional] -**tlsTrustCertsSecret** | [**io.kubernetes.client.openapi.models.V1SecretKeySelector**](io.kubernetes.client.openapi.models.V1SecretKeySelector.md) | | [optional] -**tlsValidateHostname** | **Boolean** | | [optional] -**topic** | **String** | | [optional] -**url** | **String** | | [optional] - - - diff --git a/sdks/java/client/docs/IoArgoprojEventsV1alpha1RateLimit.md b/sdks/java/client/docs/IoArgoprojEventsV1alpha1RateLimit.md deleted file mode 100644 index 14a4fc03b1fe..000000000000 --- a/sdks/java/client/docs/IoArgoprojEventsV1alpha1RateLimit.md +++ /dev/null @@ -1,14 +0,0 @@ - - -# IoArgoprojEventsV1alpha1RateLimit - - -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**requestsPerUnit** | **Integer** | | [optional] -**unit** | **String** | | [optional] - - - diff --git a/sdks/java/client/docs/IoArgoprojEventsV1alpha1SensorSpec.md b/sdks/java/client/docs/IoArgoprojEventsV1alpha1SensorSpec.md index 7a84b307a6af..d4649a93c2ec 100644 --- a/sdks/java/client/docs/IoArgoprojEventsV1alpha1SensorSpec.md +++ b/sdks/java/client/docs/IoArgoprojEventsV1alpha1SensorSpec.md @@ -7,7 +7,9 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- +**circuit** | **String** | Circuit is a boolean expression of dependency groups Deprecated: will be removed in v1.5, use Switch in triggers instead. | [optional] **dependencies** | [**List<IoArgoprojEventsV1alpha1EventDependency>**](IoArgoprojEventsV1alpha1EventDependency.md) | Dependencies is a list of the events that this sensor is dependent on. | [optional] +**dependencyGroups** | [**List<IoArgoprojEventsV1alpha1DependencyGroup>**](IoArgoprojEventsV1alpha1DependencyGroup.md) | DependencyGroups is a list of the groups of events. | [optional] **errorOnFailedRound** | **Boolean** | ErrorOnFailedRound if set to true, marks sensor state as `error` if the previous trigger round fails. Once sensor state is set to `error`, no further triggers will be processed. | [optional] **eventBusName** | **String** | | [optional] **replicas** | **Integer** | | [optional] diff --git a/sdks/java/client/docs/IoArgoprojEventsV1alpha1StandardK8STrigger.md b/sdks/java/client/docs/IoArgoprojEventsV1alpha1StandardK8STrigger.md index 87d610b40423..f5b2a3d81480 100644 --- a/sdks/java/client/docs/IoArgoprojEventsV1alpha1StandardK8STrigger.md +++ b/sdks/java/client/docs/IoArgoprojEventsV1alpha1StandardK8STrigger.md @@ -7,6 +7,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- +**groupVersionResource** | [**GroupVersionResource**](GroupVersionResource.md) | | [optional] **liveObject** | **Boolean** | | [optional] **operation** | **String** | | [optional] **parameters** | [**List<IoArgoprojEventsV1alpha1TriggerParameter>**](IoArgoprojEventsV1alpha1TriggerParameter.md) | Parameters is the list of parameters that is applied to resolved K8s trigger object. | [optional] diff --git a/sdks/java/client/docs/IoArgoprojEventsV1alpha1TLSConfig.md b/sdks/java/client/docs/IoArgoprojEventsV1alpha1TLSConfig.md index 8c8f6396a590..79afa3fcd708 100644 --- a/sdks/java/client/docs/IoArgoprojEventsV1alpha1TLSConfig.md +++ b/sdks/java/client/docs/IoArgoprojEventsV1alpha1TLSConfig.md @@ -8,8 +8,11 @@ TLSConfig refers to TLS configuration for a client. Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- +**caCertPath** | **String** | | [optional] **caCertSecret** | [**io.kubernetes.client.openapi.models.V1SecretKeySelector**](io.kubernetes.client.openapi.models.V1SecretKeySelector.md) | | [optional] +**clientCertPath** | **String** | | [optional] **clientCertSecret** | [**io.kubernetes.client.openapi.models.V1SecretKeySelector**](io.kubernetes.client.openapi.models.V1SecretKeySelector.md) | | [optional] +**clientKeyPath** | **String** | | [optional] **clientKeySecret** | [**io.kubernetes.client.openapi.models.V1SecretKeySelector**](io.kubernetes.client.openapi.models.V1SecretKeySelector.md) | | [optional] diff --git a/sdks/java/client/docs/IoArgoprojEventsV1alpha1Trigger.md b/sdks/java/client/docs/IoArgoprojEventsV1alpha1Trigger.md index f8530403f3db..dfe30f5ede6b 100644 --- a/sdks/java/client/docs/IoArgoprojEventsV1alpha1Trigger.md +++ b/sdks/java/client/docs/IoArgoprojEventsV1alpha1Trigger.md @@ -9,7 +9,6 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **parameters** | [**List<IoArgoprojEventsV1alpha1TriggerParameter>**](IoArgoprojEventsV1alpha1TriggerParameter.md) | | [optional] **policy** | [**IoArgoprojEventsV1alpha1TriggerPolicy**](IoArgoprojEventsV1alpha1TriggerPolicy.md) | | [optional] -**rateLimit** | [**IoArgoprojEventsV1alpha1RateLimit**](IoArgoprojEventsV1alpha1RateLimit.md) | | [optional] **retryStrategy** | [**IoArgoprojEventsV1alpha1Backoff**](IoArgoprojEventsV1alpha1Backoff.md) | | [optional] **template** | [**IoArgoprojEventsV1alpha1TriggerTemplate**](IoArgoprojEventsV1alpha1TriggerTemplate.md) | | [optional] diff --git a/sdks/java/client/docs/IoArgoprojEventsV1alpha1TriggerSwitch.md b/sdks/java/client/docs/IoArgoprojEventsV1alpha1TriggerSwitch.md new file mode 100644 index 000000000000..ca0ad8cc1b1b --- /dev/null +++ b/sdks/java/client/docs/IoArgoprojEventsV1alpha1TriggerSwitch.md @@ -0,0 +1,14 @@ + + +# IoArgoprojEventsV1alpha1TriggerSwitch + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**all** | **List<String>** | | [optional] +**any** | **List<String>** | | [optional] + + + diff --git a/sdks/java/client/docs/IoArgoprojEventsV1alpha1TriggerTemplate.md b/sdks/java/client/docs/IoArgoprojEventsV1alpha1TriggerTemplate.md index a7793340eb4c..2b61314533e4 100644 --- a/sdks/java/client/docs/IoArgoprojEventsV1alpha1TriggerTemplate.md +++ b/sdks/java/client/docs/IoArgoprojEventsV1alpha1TriggerTemplate.md @@ -20,8 +20,8 @@ Name | Type | Description | Notes **name** | **String** | Name is a unique name of the action to take. | [optional] **nats** | [**IoArgoprojEventsV1alpha1NATSTrigger**](IoArgoprojEventsV1alpha1NATSTrigger.md) | | [optional] **openWhisk** | [**IoArgoprojEventsV1alpha1OpenWhiskTrigger**](IoArgoprojEventsV1alpha1OpenWhiskTrigger.md) | | [optional] -**pulsar** | [**IoArgoprojEventsV1alpha1PulsarTrigger**](IoArgoprojEventsV1alpha1PulsarTrigger.md) | | [optional] **slack** | [**IoArgoprojEventsV1alpha1SlackTrigger**](IoArgoprojEventsV1alpha1SlackTrigger.md) | | [optional] +**_switch** | [**IoArgoprojEventsV1alpha1TriggerSwitch**](IoArgoprojEventsV1alpha1TriggerSwitch.md) | | [optional] diff --git a/sdks/java/client/docs/IoArgoprojEventsV1alpha1WebhookContext.md b/sdks/java/client/docs/IoArgoprojEventsV1alpha1WebhookContext.md index 1253f90d0c1c..3fa32901d28a 100644 --- a/sdks/java/client/docs/IoArgoprojEventsV1alpha1WebhookContext.md +++ b/sdks/java/client/docs/IoArgoprojEventsV1alpha1WebhookContext.md @@ -12,7 +12,9 @@ Name | Type | Description | Notes **metadata** | **Map<String, String>** | | [optional] **method** | **String** | | [optional] **port** | **String** | Port on which HTTP server is listening for incoming events. | [optional] +**serverCertPath** | **String** | DeprecatedServerCertPath refers the file that contains the cert. | [optional] **serverCertSecret** | [**io.kubernetes.client.openapi.models.V1SecretKeySelector**](io.kubernetes.client.openapi.models.V1SecretKeySelector.md) | | [optional] +**serverKeyPath** | **String** | | [optional] **serverKeySecret** | [**io.kubernetes.client.openapi.models.V1SecretKeySelector**](io.kubernetes.client.openapi.models.V1SecretKeySelector.md) | | [optional] **url** | **String** | URL is the url of the server. | [optional] diff --git a/sdks/java/client/docs/IoArgoprojWorkflowV1alpha1LabelKeys.md b/sdks/java/client/docs/IoArgoprojWorkflowV1alpha1LabelKeys.md deleted file mode 100644 index 469663360055..000000000000 --- a/sdks/java/client/docs/IoArgoprojWorkflowV1alpha1LabelKeys.md +++ /dev/null @@ -1,14 +0,0 @@ - - -# IoArgoprojWorkflowV1alpha1LabelKeys - -LabelKeys is list of keys - -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**items** | **List<String>** | | [optional] - - - diff --git a/sdks/java/client/docs/IoArgoprojWorkflowV1alpha1LabelValues.md b/sdks/java/client/docs/IoArgoprojWorkflowV1alpha1LabelValues.md deleted file mode 100644 index 8bb8b6cc5707..000000000000 --- a/sdks/java/client/docs/IoArgoprojWorkflowV1alpha1LabelValues.md +++ /dev/null @@ -1,14 +0,0 @@ - - -# IoArgoprojWorkflowV1alpha1LabelValues - -Labels is list of workflow labels - -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**items** | **List<String>** | | [optional] - - - From d9eafeee1ce309726b32b3736086da1529487fa8 Mon Sep 17 00:00:00 2001 From: NextNiclas <74151677+NextNiclas@users.noreply.github.com> Date: Tue, 19 Oct 2021 20:32:17 +0200 Subject: [PATCH 08/64] fix: Allow self-signed Root CA for SSO. Fixes #6793 (#6961) Signed-off-by: Niclas Schnickmann --- server/auth/sso/sso.go | 15 ++++++++++----- server/auth/sso/sso_test.go | 3 ++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/server/auth/sso/sso.go b/server/auth/sso/sso.go index d41b932cd0c2..2b8cf7ed87a3 100644 --- a/server/auth/sso/sso.go +++ b/server/auth/sso/sso.go @@ -5,6 +5,7 @@ import ( "crypto" "crypto/rand" "crypto/rsa" + "crypto/tls" "crypto/x509" "fmt" "net/http" @@ -75,6 +76,7 @@ type Config struct { // customGroupClaimName will override the groups claim name CustomGroupClaimName string `json:"customGroupClaimName,omitempty"` UserInfoPath string `json:"userInfoPath,omitempty"` + InsecureSkipVerify bool `json:"insecureSkipVerify,omitempty"` } func (c Config) GetSessionExpiry() time.Duration { @@ -93,10 +95,13 @@ type providerInterface interface { Verifier(config *oidc.Config) *oidc.IDTokenVerifier } -type providerFactory func(ctx context.Context, issuer string) (providerInterface, error) +type providerFactory func(ctx context.Context, issuer string, tlsConfig *tls.Config) (providerInterface, error) -func providerFactoryOIDC(ctx context.Context, issuer string) (providerInterface, error) { - return oidc.NewProvider(ctx, issuer) +func providerFactoryOIDC(ctx context.Context, issuer string, tlsConfig *tls.Config) (providerInterface, error) { + // Create http client used by oidc provider to allow modification of underlying TLSClientConfig + httpClient := &http.Client{Transport: &http.Transport{TLSClientConfig: tlsConfig}} + oidcContext := oidc.ClientContext(ctx, httpClient) + return oidc.NewProvider(oidcContext, issuer) } func New(c Config, secretsIf corev1.SecretInterface, baseHRef string, secure bool) (Interface, error) { @@ -131,7 +136,7 @@ func newSso( providerCtx = oidc.InsecureIssuerURLContext(ctx, c.IssuerAlias) } - provider, err := factory(providerCtx, c.Issuer) + provider, err := factory(providerCtx, c.Issuer, &tls.Config{InsecureSkipVerify: c.InsecureSkipVerify}) if err != nil { return nil, err } @@ -188,7 +193,7 @@ func newSso( if err != nil { return nil, fmt.Errorf("failed to create JWT encrpytor: %w", err) } - lf := log.Fields{"redirectUrl": config.RedirectURL, "issuer": c.Issuer, "issuerAlias": "DISABLED", "clientId": c.ClientID, "scopes": config.Scopes} + lf := log.Fields{"redirectUrl": config.RedirectURL, "issuer": c.Issuer, "issuerAlias": "DISABLED", "clientId": c.ClientID, "scopes": config.Scopes, "insecureSkipVerify": c.InsecureSkipVerify} if c.IssuerAlias != "" { lf["issuerAlias"] = c.IssuerAlias } diff --git a/server/auth/sso/sso_test.go b/server/auth/sso/sso_test.go index a2aa005e6003..9b1f552a0fde 100644 --- a/server/auth/sso/sso_test.go +++ b/server/auth/sso/sso_test.go @@ -2,6 +2,7 @@ package sso import ( "context" + "crypto/tls" "testing" "time" @@ -28,7 +29,7 @@ func (fakeOidcProvider) Verifier(config *oidc.Config) *oidc.IDTokenVerifier { return nil } -func fakeOidcFactory(ctx context.Context, issuer string) (providerInterface, error) { +func fakeOidcFactory(ctx context.Context, issuer string, tlsConfig *tls.Config) (providerInterface, error) { return fakeOidcProvider{ctx, issuer}, nil } From 26afd8ec9db0cfc98a4cee9b7bcd3a211c2119c4 Mon Sep 17 00:00:00 2001 From: NextNiclas <74151677+NextNiclas@users.noreply.github.com> Date: Wed, 20 Oct 2021 17:09:24 +0200 Subject: [PATCH 09/64] fix: OAuth2 callback with self-signed Root CA. Fixes #6793 (#6978) Signed-off-by: Niclas Schnickmann --- server/auth/sso/sso.go | 23 +++++++++++++---------- server/auth/sso/sso_test.go | 3 +-- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/server/auth/sso/sso.go b/server/auth/sso/sso.go index 2b8cf7ed87a3..72e89fb1b28f 100644 --- a/server/auth/sso/sso.go +++ b/server/auth/sso/sso.go @@ -49,6 +49,7 @@ type sso struct { config *oauth2.Config issuer string idTokenVerifier *oidc.IDTokenVerifier + httpClient *http.Client baseHRef string secure bool privateKey crypto.PrivateKey @@ -95,13 +96,10 @@ type providerInterface interface { Verifier(config *oidc.Config) *oidc.IDTokenVerifier } -type providerFactory func(ctx context.Context, issuer string, tlsConfig *tls.Config) (providerInterface, error) +type providerFactory func(ctx context.Context, issuer string) (providerInterface, error) -func providerFactoryOIDC(ctx context.Context, issuer string, tlsConfig *tls.Config) (providerInterface, error) { - // Create http client used by oidc provider to allow modification of underlying TLSClientConfig - httpClient := &http.Client{Transport: &http.Transport{TLSClientConfig: tlsConfig}} - oidcContext := oidc.ClientContext(ctx, httpClient) - return oidc.NewProvider(oidcContext, issuer) +func providerFactoryOIDC(ctx context.Context, issuer string) (providerInterface, error) { + return oidc.NewProvider(ctx, issuer) } func New(c Config, secretsIf corev1.SecretInterface, baseHRef string, secure bool) (Interface, error) { @@ -129,14 +127,16 @@ func newSso( if err != nil { return nil, err } + // Create http client with TLSConfig to allow skipping of CA validation if InsecureSkipVerify is set. + httpClient := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: c.InsecureSkipVerify}}} + oidcContext := oidc.ClientContext(ctx, httpClient) // Some offspec providers like Azure, Oracle IDCS have oidc discovery url different from issuer url which causes issuerValidation to fail // This providerCtx will allow the Verifier to succeed if the alternate/alias URL is in the config - var providerCtx context.Context = context.Background() if c.IssuerAlias != "" { - providerCtx = oidc.InsecureIssuerURLContext(ctx, c.IssuerAlias) + oidcContext = oidc.InsecureIssuerURLContext(oidcContext, c.IssuerAlias) } - provider, err := factory(providerCtx, c.Issuer, &tls.Config{InsecureSkipVerify: c.InsecureSkipVerify}) + provider, err := factory(oidcContext, c.Issuer) if err != nil { return nil, err } @@ -203,6 +203,7 @@ func newSso( config: config, idTokenVerifier: idTokenVerifier, baseHRef: baseHRef, + httpClient: httpClient, secure: secure, privateKey: privateKey, encrypter: encrypter, @@ -246,7 +247,9 @@ func (s *sso) HandleCallback(w http.ResponseWriter, r *http.Request) { return } redirectOption := oauth2.SetAuthURLParam("redirect_uri", s.getRedirectUrl(r)) - oauth2Token, err := s.config.Exchange(ctx, r.URL.Query().Get("code"), redirectOption) + // Use sso.httpClient in order to respect TLSOptions + oauth2Context := context.WithValue(ctx, oauth2.HTTPClient, s.httpClient) + oauth2Token, err := s.config.Exchange(oauth2Context, r.URL.Query().Get("code"), redirectOption) if err != nil { w.WriteHeader(401) _, _ = w.Write([]byte(fmt.Sprintf("failed to exchange token: %v", err))) diff --git a/server/auth/sso/sso_test.go b/server/auth/sso/sso_test.go index 9b1f552a0fde..a2aa005e6003 100644 --- a/server/auth/sso/sso_test.go +++ b/server/auth/sso/sso_test.go @@ -2,7 +2,6 @@ package sso import ( "context" - "crypto/tls" "testing" "time" @@ -29,7 +28,7 @@ func (fakeOidcProvider) Verifier(config *oidc.Config) *oidc.IDTokenVerifier { return nil } -func fakeOidcFactory(ctx context.Context, issuer string, tlsConfig *tls.Config) (providerInterface, error) { +func fakeOidcFactory(ctx context.Context, issuer string) (providerInterface, error) { return fakeOidcProvider{ctx, issuer}, nil } From 09d07111e21ce9d01469315cc3a67ff10ed05617 Mon Sep 17 00:00:00 2001 From: Zadkiel Date: Wed, 20 Oct 2021 18:21:01 +0200 Subject: [PATCH 10/64] fix(typo): correct typo in event-dispatch error log (#6688) Signed-off-by: GitHub --- server/event/dispatch/operation.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/event/dispatch/operation.go b/server/event/dispatch/operation.go index ce9c1dacf237..47ccb7614063 100644 --- a/server/event/dispatch/operation.go +++ b/server/event/dispatch/operation.go @@ -118,7 +118,7 @@ func (o *Operation) dispatch(ctx context.Context, wfeb wfv1.WorkflowEventBinding if submit.Arguments != nil { for _, p := range submit.Arguments.Parameters { if p.ValueFrom == nil { - return nil, fmt.Errorf("malformed workflow template parameter \"%s\": validFrom is nil", p.Name) + return nil, fmt.Errorf("malformed workflow template parameter \"%s\": valueFrom is nil", p.Name) } result, err := expr.Eval(p.ValueFrom.Event, o.env) if err != nil { From 0837d0c6afc06798820a8b41f0acad35aac11143 Mon Sep 17 00:00:00 2001 From: Tianchu Zhao Date: Fri, 22 Oct 2021 03:39:13 +1100 Subject: [PATCH 11/64] fix(controller): use correct pod.name in retry/podspecpatch scenario. Fixes #7007 (#7008) Signed-off-by: Tianchu Zhao --- workflow/controller/operator.go | 4 +- workflow/controller/operator_test.go | 36 +++++++++------ workflow/controller/workflowpod.go | 2 +- workflow/controller/workflowpod_test.go | 58 +++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 16 deletions(-) diff --git a/workflow/controller/operator.go b/workflow/controller/operator.go index 9631e9493192..bfcd9aaf7ba0 100644 --- a/workflow/controller/operator.go +++ b/workflow/controller/operator.go @@ -1621,7 +1621,7 @@ func (woc *wfOperationCtx) executeTemplate(ctx context.Context, nodeName string, // Inject the pod name. If the pod has a retry strategy, the pod name will be changed and will be injected when it // is determined if resolvedTmpl.IsPodType() && woc.retryStrategy(resolvedTmpl) == nil { - localParams[common.LocalVarPodName] = woc.wf.NodeID(nodeName) + localParams[common.LocalVarPodName] = wfutil.PodName(woc.wf.Name, nodeName, resolvedTmpl.Name, woc.wf.NodeID(nodeName)) } // Merge Template defaults to template @@ -1810,7 +1810,7 @@ func (woc *wfOperationCtx) executeTemplate(ctx context.Context, nodeName string, localParams := make(map[string]string) // Change the `pod.name` variable to the new retry node name if processedTmpl.IsPodType() { - localParams[common.LocalVarPodName] = woc.wf.NodeID(nodeName) + localParams[common.LocalVarPodName] = wfutil.PodName(woc.wf.Name, nodeName, processedTmpl.Name, woc.wf.NodeID(nodeName)) } // Inject the retryAttempt number localParams[common.LocalVarRetries] = strconv.Itoa(len(retryParentNode.Children)) diff --git a/workflow/controller/operator_test.go b/workflow/controller/operator_test.go index d0b65bdb4aef..604b3612e698 100644 --- a/workflow/controller/operator_test.go +++ b/workflow/controller/operator_test.go @@ -2789,20 +2789,30 @@ spec: ` func TestResolvePodNameInRetries(t *testing.T) { - ctx := context.Background() - wf := wfv1.MustUnmarshalWorkflow(podNameInRetries) - woc := newWoc(*wf) - woc.operate(ctx) - assert.Equal(t, wfv1.WorkflowRunning, woc.wf.Status.Phase) - pods, err := woc.controller.kubeclientset.CoreV1().Pods(wf.ObjectMeta.Namespace).List(ctx, metav1.ListOptions{}) - assert.NoError(t, err) - assert.True(t, len(pods.Items) > 0, "pod was not created successfully") + tests := []struct { + podNameVersion string + wantPodName string + }{ + {"v1", "output-value-placeholders-wf-3033990984"}, + {"v2", "output-value-placeholders-wf-tell-pod-name-3033990984"}, + } + for _, tt := range tests { + os.Setenv("POD_NAMES", tt.podNameVersion) + ctx := context.Background() + wf := wfv1.MustUnmarshalWorkflow(podNameInRetries) + woc := newWoc(*wf) + woc.operate(ctx) + assert.Equal(t, wfv1.WorkflowRunning, woc.wf.Status.Phase) + pods, err := woc.controller.kubeclientset.CoreV1().Pods(wf.ObjectMeta.Namespace).List(ctx, metav1.ListOptions{}) + assert.NoError(t, err) + assert.True(t, len(pods.Items) > 0, "pod was not created successfully") - template, err := getPodTemplate(&pods.Items[0]) - assert.NoError(t, err) - parameterValue := template.Outputs.Parameters[0].Value - assert.NotNil(t, parameterValue) - assert.Equal(t, "output-value-placeholders-wf-3033990984", parameterValue.String()) + template, err := getPodTemplate(&pods.Items[0]) + assert.NoError(t, err) + parameterValue := template.Outputs.Parameters[0].Value + assert.NotNil(t, parameterValue) + assert.Equal(t, tt.wantPodName, parameterValue.String()) + } } var outputStatuses = ` diff --git a/workflow/controller/workflowpod.go b/workflow/controller/workflowpod.go index 9ebbe8a08349..112831a79d5d 100644 --- a/workflow/controller/workflowpod.go +++ b/workflow/controller/workflowpod.go @@ -377,7 +377,7 @@ func (woc *wfOperationCtx) createWorkflowPod(ctx context.Context, nodeName strin // Final substitution for workflow level PodSpecPatch localParams := make(map[string]string) if tmpl.IsPodType() { - localParams[common.LocalVarPodName] = woc.wf.NodeID(nodeName) + localParams[common.LocalVarPodName] = pod.Name } tmpl, err := common.ProcessArgs(tmpl, &wfv1.Arguments{}, woc.globalParams, localParams, false, woc.wf.Namespace, woc.controller.configMapInformer) if err != nil { diff --git a/workflow/controller/workflowpod_test.go b/workflow/controller/workflowpod_test.go index a24f7d7c1841..a2ac1d008f24 100644 --- a/workflow/controller/workflowpod_test.go +++ b/workflow/controller/workflowpod_test.go @@ -3,6 +3,7 @@ package controller import ( "context" "fmt" + "os" "path/filepath" "strconv" "testing" @@ -1223,6 +1224,10 @@ spec: image: docker/whalesay:latest command: [cowsay] args: ["hello world"] + outputs: + parameters: + - name: pod-name + value: "{{pod.name}}" ` var helloWorldWfWithWFPatch = ` @@ -1308,6 +1313,59 @@ func TestPodSpecPatch(t *testing.T) { assert.EqualError(t, err, "Failed to merge the workflow PodSpecPatch with the template PodSpecPatch due to invalid format") } +var helloWorldStepWfWithPatch = ` +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + name: hello-world +spec: + entrypoint: hello + templates: + - name: hello + steps: + - - name: hello + template: whalesay + - name: whalesay + podSpecPatch: '{"containers":[{"name":"main", "resources":{"limits":{"cpu": "800m"}}}]}' + container: + image: docker/whalesay:latest + command: [cowsay] + args: ["hello world"] + outputs: + parameters: + - name: pod-name + value: "{{pod.name}}" +` + +func TestPodSpecPatchPodName(t *testing.T) { + tests := []struct { + podNameVersion string + wantPodName string + workflowYaml string + }{ + {"v1", "hello-world", helloWorldWfWithPatch}, + {"v2", "hello-world", helloWorldWfWithPatch}, + {"v1", "hello-world-3731220306", helloWorldStepWfWithPatch}, + {"v2", "hello-world-whalesay-3731220306", helloWorldStepWfWithPatch}, + } + for _, tt := range tests { + os.Setenv("POD_NAMES", tt.podNameVersion) + ctx := context.Background() + wf := wfv1.MustUnmarshalWorkflow(tt.workflowYaml) + woc := newWoc(*wf) + woc.operate(ctx) + assert.Equal(t, wfv1.WorkflowRunning, woc.wf.Status.Phase) + pods, err := listPods(woc) + assert.NoError(t, err) + assert.True(t, len(pods.Items) > 0, "pod was not created successfully") + template, err := getPodTemplate(&pods.Items[0]) + assert.NoError(t, err) + parameterValue := template.Outputs.Parameters[0].Value + assert.NotNil(t, parameterValue) + assert.Equal(t, tt.wantPodName, parameterValue.String()) + } +} + func TestMainContainerCustomization(t *testing.T) { mainCtrSpec := &apiv1.Container{ Name: common.MainContainerName, From 7256dace6c1bb6544f7a0e79220b993c32bc3daf Mon Sep 17 00:00:00 2001 From: Ziv Levi Date: Sat, 23 Oct 2021 22:03:23 +0300 Subject: [PATCH 12/64] fix: Support RFC3339 in creationTimeStamp. Fixes #6906 (#7044) Signed-off-by: Alex Collins --- docs/variables.md | 3 ++- workflow/controller/operator.go | 1 + workflow/controller/operator_test.go | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/variables.md b/docs/variables.md index f42fdf51b626..b49e057cc6ac 100644 --- a/docs/variables.md +++ b/docs/variables.md @@ -234,7 +234,8 @@ For `Template`-level metrics: | `workflow.annotations.` | Workflow annotations | | `workflow.labels.` | Workflow labels | | `workflow.creationTimestamp` | Workflow creation timestamp formatted in RFC 3339 (e.g. `2018-08-23T05:42:49Z`) | -| `workflow.creationTimestamp.` | Creation timestamp formatted with a [strftime](http://strftime.org) format character | +| `workflow.creationTimestamp.` | Creation timestamp formatted with a [strftime](http://strftime.org) format character. | +| `workflow.creationTimestamp.RFC3339` | Creation timestamp formatted with in RFC 3339. | | `workflow.priority` | Workflow priority | | `workflow.duration` | Workflow duration estimate, may differ from actual duration by a couple of seconds | | `workflow.scheduledTime` | Scheduled runtime formatted in RFC 3339 (only available for CronWorkflows) | diff --git a/workflow/controller/operator.go b/workflow/controller/operator.go index bfcd9aaf7ba0..1c2c19b9ab06 100644 --- a/workflow/controller/operator.go +++ b/workflow/controller/operator.go @@ -515,6 +515,7 @@ func (woc *wfOperationCtx) setGlobalParameters(executionParameters wfv1.Argument woc.globalParams[cTimeVar] = strftime.Format("%"+string(char), woc.wf.ObjectMeta.CreationTimestamp.Time) } woc.globalParams[common.GlobalVarWorkflowCreationTimestamp+".s"] = strconv.FormatInt(woc.wf.ObjectMeta.CreationTimestamp.Time.Unix(), 10) + woc.globalParams[common.GlobalVarWorkflowCreationTimestamp+".RFC3339"] = woc.wf.ObjectMeta.CreationTimestamp.Format(time.RFC3339) if workflowParameters, err := json.Marshal(woc.execWf.Spec.Arguments.Parameters); err == nil { woc.globalParams[common.GlobalVarWorkflowParameters] = string(workflowParameters) diff --git a/workflow/controller/operator_test.go b/workflow/controller/operator_test.go index 604b3612e698..c5bbdfd73796 100644 --- a/workflow/controller/operator_test.go +++ b/workflow/controller/operator_test.go @@ -315,6 +315,7 @@ func TestGlobalParams(t *testing.T) { assert.Contains(t, woc.globalParams, fmt.Sprintf("%s.%s", "workflow.creationTimestamp", string(char))) } assert.Contains(t, woc.globalParams, "workflow.creationTimestamp.s") + assert.Contains(t, woc.globalParams, "workflow.creationTimestamp.RFC3339") assert.Contains(t, woc.globalParams, "workflow.duration") assert.Contains(t, woc.globalParams, "workflow.name") From f43d8b01a752829e5c6208215b767e3ab68c9dc2 Mon Sep 17 00:00:00 2001 From: Saravanan Balasubramanian <33908564+sarabala1979@users.noreply.github.com> Date: Sun, 24 Oct 2021 22:28:28 -0700 Subject: [PATCH 13/64] fix: Memozie for Step and DAG level (#7028) * fix: Memozie for Step and DAG level Signed-off-by: Alex Collins --- test/e2e/functional_test.go | 131 +++++++++++++++++++++++++++++++++++ workflow/controller/dag.go | 10 +++ workflow/controller/steps.go | 11 +++ 3 files changed, 152 insertions(+) diff --git a/test/e2e/functional_test.go b/test/e2e/functional_test.go index 39ce9dc92fd9..2d4bfcc7cbac 100644 --- a/test/e2e/functional_test.go +++ b/test/e2e/functional_test.go @@ -840,3 +840,134 @@ spec: func TestFunctionalSuite(t *testing.T) { suite.Run(t, new(FunctionalSuite)) } + +func (s *FunctionalSuite) TestStepLevelMemozie() { + s.Given(). + Workflow(`apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: steps-memozie- +spec: + entrypoint: hello-hello-hello + templates: + - name: hello-hello-hello + steps: + - - name: hello1 + template: memostep + arguments: + parameters: [{name: message, value: "hello1"}] + - - name: hello2a + template: memostep + arguments: + parameters: [{name: message, value: "hello1"}] + - name: memostep + inputs: + parameters: + - name: message + memoize: + key: "{{inputs.parameters.message}}" + maxAge: "10s" + cache: + configMap: + name: my-config-memo-step + steps: + - - name: cache + template: whalesay + arguments: + parameters: [{name: message, value: "{{inputs.parameters.message}}"}] + outputs: + parameters: + - name: output + valueFrom: + Parameter: "{{steps.cache.outputs.result}}" + - name: whalesay + inputs: + parameters: + - name: message + container: + image: argoproj/argosay:v2 + command: [echo] + args: ["{{inputs.parameters.message}}"] +`). + When(). + SubmitWorkflow(). + WaitForWorkflow(fixtures.ToBeSucceeded). + Then(). + ExpectWorkflow(func(t *testing.T, _ *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + memoHit := false + for _, node := range status.Nodes { + if node.MemoizationStatus != nil && node.MemoizationStatus.Hit { + memoHit = true + } + } + assert.True(t, memoHit) + + }) + +} + +func (s *FunctionalSuite) TestDAGLevelMemozie() { + s.Given(). + Workflow(`apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: steps-memozie- +spec: + entrypoint: hello-hello-hello + templates: + - name: hello-hello-hello + steps: + - - name: hello1 + template: memostep + arguments: + parameters: [{name: message, value: "hello1"}] + - - name: hello2a + template: memostep + arguments: + parameters: [{name: message, value: "hello1"}] + - name: memostep + inputs: + parameters: + - name: message + memoize: + key: "{{inputs.parameters.message}}" + maxAge: "10s" + cache: + configMap: + name: my-config-memo-dag + dag: + tasks: + - name: cache + template: whalesay + arguments: + parameters: [{name: message, value: "{{inputs.parameters.message}}"}] + outputs: + parameters: + - name: output + valueFrom: + Parameter: "{{tasks.cache.outputs.result}}" + - name: whalesay + inputs: + parameters: + - name: message + container: + image: argoproj/argosay:v2 + command: [echo] + args: ["{{inputs.parameters.message}}"] +`). + When(). + SubmitWorkflow(). + WaitForWorkflow(fixtures.ToBeSucceeded). + Then(). + ExpectWorkflow(func(t *testing.T, _ *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + memoHit := false + for _, node := range status.Nodes { + if node.MemoizationStatus != nil && node.MemoizationStatus.Hit { + memoHit = true + } + } + assert.True(t, memoHit) + + }) + +} diff --git a/workflow/controller/dag.go b/workflow/controller/dag.go index 8705c6eb40a9..d8d474a842fd 100644 --- a/workflow/controller/dag.go +++ b/workflow/controller/dag.go @@ -9,11 +9,13 @@ import ( "time" "github.com/antonmedv/expr" + log "github.com/sirupsen/logrus" "github.com/argoproj/argo-workflows/v3/errors" wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" "github.com/argoproj/argo-workflows/v3/util/template" "github.com/argoproj/argo-workflows/v3/workflow/common" + controllercache "github.com/argoproj/argo-workflows/v3/workflow/controller/cache" "github.com/argoproj/argo-workflows/v3/workflow/templateresolution" ) @@ -299,6 +301,14 @@ func (woc *wfOperationCtx) executeDAG(ctx context.Context, nodeName string, tmpl node = woc.wf.GetNodeByName(nodeName) node.Outputs = outputs woc.wf.Status.Nodes[node.ID] = *node + if node.MemoizationStatus != nil { + c := woc.controller.cacheFactory.GetCache(controllercache.ConfigMapCache, node.MemoizationStatus.CacheName) + err := c.Save(ctx, node.MemoizationStatus.Key, node.ID, node.Outputs) + if err != nil { + woc.log.WithFields(log.Fields{"nodeID": node.ID}).WithError(err).Error("Failed to save node outputs to cache") + node.Phase = wfv1.NodeError + } + } } woc.updateOutboundNodesForTargetTasks(dagCtx, targetTasks, nodeName) diff --git a/workflow/controller/steps.go b/workflow/controller/steps.go index 3ac112a6c8cb..d995b440ace9 100644 --- a/workflow/controller/steps.go +++ b/workflow/controller/steps.go @@ -8,11 +8,13 @@ import ( "time" "github.com/Knetic/govaluate" + log "github.com/sirupsen/logrus" "github.com/argoproj/argo-workflows/v3/errors" wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" "github.com/argoproj/argo-workflows/v3/util/template" "github.com/argoproj/argo-workflows/v3/workflow/common" + controllercache "github.com/argoproj/argo-workflows/v3/workflow/controller/cache" "github.com/argoproj/argo-workflows/v3/workflow/templateresolution" ) @@ -152,7 +154,16 @@ func (woc *wfOperationCtx) executeSteps(ctx context.Context, nodeName string, tm node.Outputs = outputs woc.addOutputsToGlobalScope(node.Outputs) woc.wf.Status.Nodes[node.ID] = *node + if node.MemoizationStatus != nil { + c := woc.controller.cacheFactory.GetCache(controllercache.ConfigMapCache, node.MemoizationStatus.CacheName) + err := c.Save(ctx, node.MemoizationStatus.Key, node.ID, node.Outputs) + if err != nil { + woc.log.WithFields(log.Fields{"nodeID": node.ID}).WithError(err).Error("Failed to save node outputs to cache") + node.Phase = wfv1.NodeError + } + } } + return woc.markNodePhase(nodeName, wfv1.NodeSucceeded), nil } From 9b4dd1e83a3362b8f561e380566a7af3ab68ba8d Mon Sep 17 00:00:00 2001 From: Alex Collins Date: Wed, 27 Oct 2021 08:58:32 -0700 Subject: [PATCH 14/64] fix(ui): Correct HTTP connection in pipeline view (#7077) Signed-off-by: Alex Collins --- .../app/pipelines/components/pipeline-details/pipeline-graph.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/app/pipelines/components/pipeline-details/pipeline-graph.ts b/ui/src/app/pipelines/components/pipeline-details/pipeline-graph.ts index d8e599888eb1..7736596f74ff 100644 --- a/ui/src/app/pipelines/components/pipeline-details/pipeline-graph.ts +++ b/ui/src/app/pipelines/components/pipeline-details/pipeline-graph.ts @@ -87,7 +87,7 @@ export const graph = (pipeline: Pipeline, steps: Step[]) => { g.nodes.set(subjectId, {genre: 'stan', icon: 'stream', label: x.stan.subject}); g.edges.set({v: subjectId, w: stepId}, {classNames}); } else if (x.http) { - const y = new URL('http://' + (x.http.serviceName || pipeline.metadata.name + '-' + step.spec.name) + '/sources/' + x.name); + const y = new URL('https://' + (x.http.serviceName || pipeline.metadata.name + '-' + step.spec.name) + '/sources/' + x.name); const subjectId = 'http/' + y; g.nodes.set(subjectId, {genre: 'http', icon: 'cloud', label: y.hostname}); g.edges.set({v: subjectId, w: stepId}, {classNames}); From 00f953286f4e3a120b5dff4dc1dbd32adf1c7237 Mon Sep 17 00:00:00 2001 From: Simon Behar Date: Wed, 27 Oct 2021 14:10:59 -0400 Subject: [PATCH 15/64] fix: Ensure HTTP templates have children assigned (#7082) Signed-off-by: Simon Behar --- workflow/controller/dag_test.go | 82 +++++++++++++++++++++++++++++++++ workflow/controller/operator.go | 2 +- 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/workflow/controller/dag_test.go b/workflow/controller/dag_test.go index d51571feb4f7..6e96d3435dda 100644 --- a/workflow/controller/dag_test.go +++ b/workflow/controller/dag_test.go @@ -3320,3 +3320,85 @@ func TestDAGReferTaskAggregatedOutputs(t *testing.T) { } } } + +var dagHttpChildrenAssigned = `apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + name: http-template-nv52d +spec: + entrypoint: main + templates: + - dag: + tasks: + - arguments: + parameters: + - name: url + value: https://raw.githubusercontent.com/argoproj/argo-workflows/4e450e250168e6b4d51a126b784e90b11a0162bc/pkg/apis/workflow/v1alpha1/generated.swagger.json + name: good1 + template: http + - arguments: + parameters: + - name: url + value: https://raw.githubusercontent.com/argoproj/argo-workflows/4e450e250168e6b4d51a126b784e90b11a0162bc/pkg/apis/workflow/v1alpha1/generated.swagger.json + dependencies: + - good1 + name: good2 + template: http + name: main + - http: + url: '{{inputs.parameters.url}}' + inputs: + parameters: + - name: url + name: http +status: + nodes: + http-template-nv52d: + children: + - http-template-nv52d-444770636 + displayName: http-template-nv52d + id: http-template-nv52d + name: http-template-nv52d + outboundNodes: + - http-template-nv52d-478325874 + phase: Running + startedAt: "2021-10-27T13:46:08Z" + templateName: main + templateScope: local/http-template-nv52d + type: DAG + http-template-nv52d-444770636: + boundaryID: http-template-nv52d + children: + - http-template-nv52d-495103493 + displayName: good1 + finishedAt: null + id: http-template-nv52d-444770636 + name: http-template-nv52d.good1 + phase: Succeeded + startedAt: "2021-10-27T13:46:08Z" + templateName: http + templateScope: local/http-template-nv52d + type: HTTP + phase: Running + startedAt: "2021-10-27T13:46:08Z" +` + +func TestDagHttpChildrenAssigned(t *testing.T) { + wf := wfv1.MustUnmarshalWorkflow(dagHttpChildrenAssigned) + cancel, controller := newController(wf) + defer cancel() + + ctx := context.Background() + woc := newWorkflowOperationCtx(wf, controller) + woc.operate(ctx) + + dagNode := woc.wf.Status.Nodes.FindByDisplayName("good2") + assert.NotNil(t, dagNode) + + dagNode = woc.wf.Status.Nodes.FindByDisplayName("good1") + if assert.NotNil(t, dagNode) { + if assert.Len(t, dagNode.Children, 1) { + assert.Equal(t, "http-template-nv52d-495103493", dagNode.Children[0]) + } + } +} diff --git a/workflow/controller/operator.go b/workflow/controller/operator.go index 1c2c19b9ab06..37cb8eb9834d 100644 --- a/workflow/controller/operator.go +++ b/workflow/controller/operator.go @@ -2391,7 +2391,7 @@ func (woc *wfOperationCtx) executeContainer(ctx context.Context, nodeName string func (woc *wfOperationCtx) getOutboundNodes(nodeID string) []string { node := woc.wf.Status.Nodes[nodeID] switch node.Type { - case wfv1.NodeTypeSkipped, wfv1.NodeTypeSuspend: + case wfv1.NodeTypeSkipped, wfv1.NodeTypeSuspend, wfv1.NodeTypeHTTP: return []string{node.ID} case wfv1.NodeTypePod: From ccc8d839c2da3c561bb7f5c078cd26c17ce9a9c5 Mon Sep 17 00:00:00 2001 From: Simon Behar Date: Wed, 27 Oct 2021 14:11:34 -0400 Subject: [PATCH 16/64] fix: Ensure HTTP reconciliation occurs for onExit nodes (#7084) * fix: Ensure HTTP reconciliation occurs for onExit nodes Signed-off-by: Simon Behar * tests Signed-off-by: Simon Behar * fixes Signed-off-by: Simon Behar * minor Signed-off-by: Simon Behar --- workflow/controller/agent.go | 2 - workflow/controller/exit_handler_test.go | 61 +++++++++++++++++++++++ workflow/controller/http_template.go | 36 +++++++++++++ workflow/controller/http_template_test.go | 41 +++++++++++++++ workflow/controller/operator.go | 20 +++----- workflow/controller/taskset.go | 19 +++---- workflow/controller/taskset_test.go | 4 +- 7 files changed, 158 insertions(+), 25 deletions(-) create mode 100644 workflow/controller/http_template_test.go diff --git a/workflow/controller/agent.go b/workflow/controller/agent.go index a207ed931d49..459c512e9f98 100644 --- a/workflow/controller/agent.go +++ b/workflow/controller/agent.go @@ -69,11 +69,9 @@ func (woc *wfOperationCtx) createAgentPod(ctx context.Context) (*apiv1.Pod, erro podName := woc.getAgentPodName() obj, exists, err := woc.controller.podInformer.GetStore().Get(cache.ExplicitKey(woc.wf.Namespace + "/" + podName)) - if err != nil { return nil, fmt.Errorf("failed to get pod from informer store: %w", err) } - if exists { existing, ok := obj.(*apiv1.Pod) if ok { diff --git a/workflow/controller/exit_handler_test.go b/workflow/controller/exit_handler_test.go index 9e39042dbaa2..294d34a00b95 100644 --- a/workflow/controller/exit_handler_test.go +++ b/workflow/controller/exit_handler_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/assert" apiv1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" ) @@ -687,3 +688,63 @@ func TestDagOnExitAndRetryStrategy(t *testing.T) { assert.Equal(t, wfv1.WorkflowSucceeded, woc.wf.Status.Phase) } + +var testWorkflowOnExitHttpReconciliation = `apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + name: hello-world-sx6lw +spec: + entrypoint: whalesay + onExit: exit-handler + templates: + - container: + args: + - hello world + command: + - cowsay + image: docker/whalesay:latest + name: whalesay + - http: + url: https://example.com + name: exit-handler +status: + nodes: + hello-world-sx6lw: + displayName: hello-world-sx6lw + finishedAt: "2021-10-27T14:38:30Z" + hostNodeName: k3d-k3s-default-server-0 + id: hello-world-sx6lw + name: hello-world-sx6lw + phase: Succeeded + progress: 1/1 + resourcesDuration: + cpu: 2 + memory: 1 + startedAt: "2021-10-27T14:38:27Z" + templateName: whalesay + templateScope: local/hello-world-sx6lw + type: Pod + phase: Running + startedAt: "2021-10-27T14:38:27Z" +` + +func TestWorkflowOnExitHttpReconciliation(t *testing.T) { + wf := wfv1.MustUnmarshalWorkflow(testWorkflowOnExitHttpReconciliation) + cancel, controller := newController(wf) + defer cancel() + + ctx := context.Background() + woc := newWorkflowOperationCtx(wf, controller) + + taskSets, err := woc.controller.wfclientset.ArgoprojV1alpha1().WorkflowTaskSets("").List(ctx, v1.ListOptions{}) + if assert.NoError(t, err) { + assert.Len(t, taskSets.Items, 0) + } + woc.operate(ctx) + + assert.Len(t, woc.wf.Status.Nodes, 2) + taskSets, err = woc.controller.wfclientset.ArgoprojV1alpha1().WorkflowTaskSets("").List(ctx, v1.ListOptions{}) + if assert.NoError(t, err) { + assert.Len(t, taskSets.Items, 1) + } +} diff --git a/workflow/controller/http_template.go b/workflow/controller/http_template.go index 65ffbca85754..6a545c5afdee 100644 --- a/workflow/controller/http_template.go +++ b/workflow/controller/http_template.go @@ -1,6 +1,8 @@ package controller import ( + "context" + wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" ) @@ -12,3 +14,37 @@ func (woc *wfOperationCtx) executeHTTPTemplate(nodeName string, templateScope st } return node } + +func (woc *wfOperationCtx) httpReconciliation(ctx context.Context) { + err := woc.reconcileTaskSet(ctx) + if err != nil { + woc.log.WithError(err).Error("error in workflowtaskset reconciliation") + return + } + + err = woc.reconcileAgentPod(ctx) + if err != nil { + woc.log.WithError(err).Error("error in agent pod reconciliation") + woc.markWorkflowError(ctx, err) + return + } +} + +func (woc *wfOperationCtx) nodeRequiresHttpReconciliation(nodeName string) bool { + node := woc.wf.GetNodeByName(nodeName) + if node == nil { + return false + } + // If this node is of type HTTP, it will need an HTTP reconciliation + if node.Type == wfv1.NodeTypeHTTP { + return true + } + for _, child := range node.Children { + // If any of the node's children need an HTTP reconciliation, the parent node will also need one + if woc.nodeRequiresHttpReconciliation(child) { + return true + } + } + // If neither of the children need one -- or if there are no children -- no HTTP reconciliation is needed. + return false +} diff --git a/workflow/controller/http_template_test.go b/workflow/controller/http_template_test.go new file mode 100644 index 000000000000..9fc8f84d86ff --- /dev/null +++ b/workflow/controller/http_template_test.go @@ -0,0 +1,41 @@ +package controller + +import ( + "testing" + + "github.com/stretchr/testify/assert" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" +) + +func TestNodeRequiresHttpReconciliation(t *testing.T) { + woc := &wfOperationCtx{ + wf: &v1alpha1.Workflow{ + ObjectMeta: v1.ObjectMeta{ + Name: "test-wf", + }, + Status: v1alpha1.WorkflowStatus{ + Nodes: v1alpha1.Nodes{ + "test-wf-1996333140": v1alpha1.NodeStatus{ + Name: "not-needed", + Type: v1alpha1.NodeTypePod, + }, + "test-wf-3939368189": v1alpha1.NodeStatus{ + Name: "parent", + Type: v1alpha1.NodeTypeSteps, + Children: []string{"child-http"}, + }, + "test-wf-1430055856": v1alpha1.NodeStatus{ + Name: "child-http", + Type: v1alpha1.NodeTypeHTTP, + }, + }, + }, + }, + } + + assert.False(t, woc.nodeRequiresHttpReconciliation("not-needed")) + assert.True(t, woc.nodeRequiresHttpReconciliation("child-http")) + assert.True(t, woc.nodeRequiresHttpReconciliation("parent")) +} diff --git a/workflow/controller/operator.go b/workflow/controller/operator.go index 37cb8eb9834d..35ef9aa618e6 100644 --- a/workflow/controller/operator.go +++ b/workflow/controller/operator.go @@ -352,18 +352,8 @@ func (woc *wfOperationCtx) operate(ctx context.Context) { return } - err = woc.taskSetReconciliation(ctx) - if err != nil { - woc.log.WithError(err).Error("error in workflowtaskset reconciliation") - return - } - - err = woc.reconcileAgentPod(ctx) - if err != nil { - woc.log.WithError(err).Error("error in agent pod reconciliation") - woc.markWorkflowError(ctx, err) - return - } + // Reconcile TaskSet and Agent for HTTP templates + woc.httpReconciliation(ctx) if node == nil || !node.Fulfilled() { // node can be nil if a workflow created immediately in a parallelism == 0 state @@ -423,6 +413,12 @@ func (woc *wfOperationCtx) operate(ctx context.Context) { } return } + + // If the onExit node (or any child of the onExit node) requires HTTP reconciliation, do it here + if onExitNode != nil && woc.nodeRequiresHttpReconciliation(onExitNode.Name) { + woc.httpReconciliation(ctx) + } + if onExitNode == nil || !onExitNode.Fulfilled() { return } diff --git a/workflow/controller/taskset.go b/workflow/controller/taskset.go index 0def937824bd..18a7d52fa736 100644 --- a/workflow/controller/taskset.go +++ b/workflow/controller/taskset.go @@ -69,32 +69,33 @@ func (woc *wfOperationCtx) completeTaskSet(ctx context.Context) error { } func (woc *wfOperationCtx) getWorkflowTaskSet() (*wfv1.WorkflowTaskSet, error) { - taskSet, exist, err := woc.controller.wfTaskSetInformer.Informer().GetIndexer().GetByKey(woc.wf.Namespace + "/" + woc.wf.Name) + taskSet, exists, err := woc.controller.wfTaskSetInformer.Informer().GetIndexer().GetByKey(woc.wf.Namespace + "/" + woc.wf.Name) if err != nil { return nil, err } - if !exist { + if !exists { return nil, nil } - return taskSet.(*wfv1.WorkflowTaskSet), nil } -func (woc *wfOperationCtx) taskSetReconciliation(ctx context.Context) error { - workflowTaskset, err := woc.getWorkflowTaskSet() +func (woc *wfOperationCtx) reconcileTaskSet(ctx context.Context) error { + workflowTaskSet, err := woc.getWorkflowTaskSet() if err != nil { return err } woc.log.WithField("workflow", woc.wf.Name).WithField("namespace", woc.wf.Namespace).Infof("TaskSet Reconciliation") - if workflowTaskset != nil && len(workflowTaskset.Status.Nodes) > 0 { - for nodeID, taskResult := range workflowTaskset.Status.Nodes { + if workflowTaskSet != nil && len(workflowTaskSet.Status.Nodes) > 0 { + for nodeID, taskResult := range workflowTaskSet.Status.Nodes { node := woc.wf.Status.Nodes[nodeID] + node.Outputs = taskResult.Outputs.DeepCopy() node.Phase = taskResult.Phase node.Message = taskResult.Message - woc.wf.Status.Nodes[nodeID] = node node.FinishedAt = metav1.Now() + + woc.wf.Status.Nodes[nodeID] = node woc.updated = true } } @@ -105,6 +106,7 @@ func (woc *wfOperationCtx) createTaskSet(ctx context.Context) error { if len(woc.taskSet) == 0 { return nil } + key := fmt.Sprintf("%s/%s", woc.wf.Namespace, woc.wf.Name) log.WithField("workflow", woc.wf.Name).WithField("namespace", woc.wf.Namespace).WithField("TaskSet", key).Infof("Creating TaskSet") taskSet := wfv1.WorkflowTaskSet{ @@ -143,7 +145,6 @@ func (woc *wfOperationCtx) createTaskSet(ctx context.Context) error { log.WithError(err).WithField("workflow", woc.wf.Name).WithField("namespace", woc.wf.Namespace).Error("Failed to patch WorkflowTaskSet") return fmt.Errorf("failed to patch TaskSet. %v", err) } - } else if err != nil { log.WithError(err).WithField("workflow", woc.wf.Name).WithField("namespace", woc.wf.Namespace).Error("Failed to create WorkflowTaskSet") return err diff --git a/workflow/controller/taskset_test.go b/workflow/controller/taskset_test.go index 6b1ff83945ae..32a14bc2949e 100644 --- a/workflow/controller/taskset_test.go +++ b/workflow/controller/taskset_test.go @@ -317,9 +317,9 @@ func TestNonHTTPTemplateScenario(t *testing.T) { wf := wfv1.MustUnmarshalWorkflow(helloWorldWf) woc := newWorkflowOperationCtx(wf, controller) ctx := context.Background() - t.Run("taskSetReconciliation", func(t *testing.T) { + t.Run("reconcileTaskSet", func(t *testing.T) { woc.operate(ctx) - err := woc.taskSetReconciliation(ctx) + err := woc.reconcileTaskSet(ctx) assert.NoError(t, err) }) t.Run("completeTaskSet", func(t *testing.T) { From 508027b3521ef2b51293aa1dc58a911c753d148c Mon Sep 17 00:00:00 2001 From: Saravanan Balasubramanian <33908564+sarabala1979@users.noreply.github.com> Date: Sun, 31 Oct 2021 20:09:27 -0700 Subject: [PATCH 17/64] fix: Daemon step in running state, but dependents don't start (#7107) * fix: Daemon step in running state, but dependents don't start Signed-off-by: Saravanan Balasubramanian * update Signed-off-by: Saravanan Balasubramanian * updated Signed-off-by: Saravanan Balasubramanian --- workflow/controller/operator.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/workflow/controller/operator.go b/workflow/controller/operator.go index 35ef9aa618e6..f559dd5984fc 100644 --- a/workflow/controller/operator.go +++ b/workflow/controller/operator.go @@ -2035,6 +2035,21 @@ func (woc *wfOperationCtx) findTemplate(pod *apiv1.Pod) *wfv1.Template { if node == nil { return nil // I don't expect this to happen in production, just in tests } + return woc.GetNodeTemplate(node) +} + +func (woc *wfOperationCtx) GetNodeTemplate(node *wfv1.NodeStatus) *wfv1.Template { + if node.TemplateRef != nil { + tmplCtx, err := woc.createTemplateContext(node.GetTemplateScope()) + if err != nil { + woc.markNodeError(node.Name, err) + } + tmpl, err := tmplCtx.GetTemplateFromRef(node.TemplateRef) + if err != nil { + woc.markNodeError(node.Name, err) + } + return tmpl + } return woc.wf.GetTemplateByName(node.TemplateName) } From c1553dfd73e3734b6dbdb4fdb5828df1e6fff792 Mon Sep 17 00:00:00 2001 From: Kyle Hanks Date: Mon, 1 Nov 2021 08:35:27 -0700 Subject: [PATCH 18/64] fix: typo in node-field-selector.md (#7116) Signed-off-by: Kyle Hanks --- USERS.md | 1 + docs/node-field-selector.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/USERS.md b/USERS.md index a69f6539862a..f2c7f35b7ab4 100644 --- a/USERS.md +++ b/USERS.md @@ -147,6 +147,7 @@ Currently, the following organizations are **officially** using Argo Workflows: 1. [WooliesX](https://wooliesx.com.au/) 1. [Woolworths Group](https://www.woolworthsgroup.com.au/) 1. [Workiva](https://www.workiva.com/) +1. [Voyager](https://investvoyager.com/) 1. [Zhihu](https://www.zhihu.com/) ### Projects Using Argo diff --git a/docs/node-field-selector.md b/docs/node-field-selector.md index 5465c06f2e52..086f5cf04e2c 100644 --- a/docs/node-field-selector.md +++ b/docs/node-field-selector.md @@ -61,7 +61,7 @@ Consider the following workflow: Here we have two steps with the same `displayName`: `wait-approval`. To select one to suspend, we need to use their `name`, either `appr-promotion-ffsv4.app1.wait-approval` or `appr-promotion-ffsv4.app3.wait-approval`. If it is not clear -what the full name of a done is, it can be found using `kubectl`: +what the full name of a node is, it can be found using `kubectl`: ``` $ kubectl get wf appr-promotion-ffsv4 -o yaml From a4390dd9a9bbd1280774fe10cf455d655a4ea873 Mon Sep 17 00:00:00 2001 From: Simon Behar Date: Wed, 3 Nov 2021 10:35:10 -0400 Subject: [PATCH 19/64] fix: Respect template.HTTP.timeoutSeconds (#7136) Signed-off-by: Simon Behar --- workflow/executor/agent.go | 5 ++++- workflow/executor/http/http.go | 14 ++++++++------ workflow/executor/http/http_test.go | 19 ++++++++++++++----- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/workflow/executor/agent.go b/workflow/executor/agent.go index 1b4def9c9ce9..8f8cab934104 100644 --- a/workflow/executor/agent.go +++ b/workflow/executor/agent.go @@ -108,6 +108,9 @@ func (ae *AgentExecutor) Agent(ctx context.Context) error { } func (ae *AgentExecutor) executeHTTPTemplate(ctx context.Context, tmpl wfv1.Template) (*wfv1.Outputs, error) { + if tmpl.HTTP == nil { + return nil, fmt.Errorf("attempting to execute template that is not of type HTTP") + } httpTemplate := tmpl.HTTP request, err := http.NewRequest(httpTemplate.Method, httpTemplate.URL, bytes.NewBufferString(httpTemplate.Body)) if err != nil { @@ -125,7 +128,7 @@ func (ae *AgentExecutor) executeHTTPTemplate(ctx context.Context, tmpl wfv1.Temp } request.Header.Add(header.Name, value) } - response, err := argohttp.SendHttpRequest(request) + response, err := argohttp.SendHttpRequest(request, httpTemplate.TimeoutSeconds) if err != nil { return nil, err } diff --git a/workflow/executor/http/http.go b/workflow/executor/http/http.go index 32225c876345..9c775cff57b3 100644 --- a/workflow/executor/http/http.go +++ b/workflow/executor/http/http.go @@ -4,20 +4,23 @@ import ( "fmt" "io/ioutil" "net/http" + "time" log "github.com/sirupsen/logrus" ) -func SendHttpRequest(request *http.Request) (string, error) { - out, err := http.DefaultClient.Do(request) - +func SendHttpRequest(request *http.Request, timeout *int64) (string, error) { + httpClient := http.DefaultClient + if timeout != nil { + httpClient.Timeout = time.Duration(*timeout) * time.Second + } + out, err := httpClient.Do(request) if err != nil { return "", err } - // Close the connection defer out.Body.Close() - log.WithFields(log.Fields{"url": request.URL, "status": out.Status}).Info("HTTP request made") + log.WithFields(log.Fields{"url": request.URL, "status": out.Status}).Info("HTTP Request Sent") data, err := ioutil.ReadAll(out.Body) if err != nil { return "", err @@ -27,5 +30,4 @@ func SendHttpRequest(request *http.Request) (string, error) { } return string(data), nil - } diff --git a/workflow/executor/http/http_test.go b/workflow/executor/http/http_test.go index febab81fd241..d59797196bc7 100644 --- a/workflow/executor/http/http_test.go +++ b/workflow/executor/http/http_test.go @@ -6,22 +6,31 @@ import ( "testing" "github.com/stretchr/testify/assert" + "k8s.io/utils/pointer" ) func TestSendHttpRequest(t *testing.T) { t.Run("SuccessfulRequest", func(t *testing.T) { - request, err := http.NewRequest(http.MethodGet, "http://www.google.com", bytes.NewBuffer([]byte{})) + request, err := http.NewRequest(http.MethodGet, "http://httpstat.us/200", bytes.NewBuffer([]byte{})) assert.NoError(t, err) - response, err := SendHttpRequest(request) + _, err = SendHttpRequest(request, nil) assert.NoError(t, err) - assert.NotEmpty(t, response) }) t.Run("NotFoundRequest", func(t *testing.T) { - request, err := http.NewRequest(http.MethodGet, "http://www.notfound.com/test", bytes.NewBuffer([]byte{})) + request, err := http.NewRequest(http.MethodGet, "http://httpstat.us/404", bytes.NewBuffer([]byte{})) assert.NoError(t, err) - response, err := SendHttpRequest(request) + response, err := SendHttpRequest(request, nil) assert.Error(t, err) assert.Empty(t, response) assert.Equal(t, "404 Not Found", err.Error()) }) + t.Run("TimeoutRequest", func(t *testing.T) { + // Request sleeps for 4 seconds, but timeout is 2 + request, err := http.NewRequest(http.MethodGet, "http://httpstat.us/200?sleep=4000", bytes.NewBuffer([]byte{})) + assert.NoError(t, err) + response, err := SendHttpRequest(request, pointer.Int64Ptr(2)) + assert.Error(t, err) + assert.Empty(t, response) + assert.Equal(t, `Get "http://httpstat.us/200?sleep=4000": context deadline exceeded (Client.Timeout exceeded while awaiting headers)`, err.Error()) + }) } From bdcca4e175ee71e402e567d857209f7ddce79d9a Mon Sep 17 00:00:00 2001 From: Simon Behar Date: Wed, 3 Nov 2021 12:26:55 -0400 Subject: [PATCH 20/64] fix: Return error when YAML submission is invalid (#7135) Signed-off-by: Simon Behar --- test/e2e/cli_test.go | 9 +++++++++ test/e2e/smoke/basic-invalid.yaml | 11 +++++++++++ workflow/common/parse.go | 14 +++++++++----- 3 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 test/e2e/smoke/basic-invalid.yaml diff --git a/test/e2e/cli_test.go b/test/e2e/cli_test.go index dacd10dfccde..630f2d02f10b 100644 --- a/test/e2e/cli_test.go +++ b/test/e2e/cli_test.go @@ -203,6 +203,15 @@ func (s *CLISuite) TestSubmitDryRun() { }) } +func (s *CLISuite) TestSubmitInvalidWf() { + s.Given(). + RunCli([]string{"submit", "smoke/basic-invalid.yaml", "-l", "workflows.argoproj.io/test=true"}, func(t *testing.T, output string, err error) { + if assert.Error(t, err) { + assert.Contains(t, output, "yaml file at index 0 is not valid:") + } + }) +} + func (s *CLISuite) TestSubmitServerDryRun() { s.Given(). RunCli([]string{"submit", "smoke/basic.yaml", "--server-dry-run", "-o", "yaml", "-l", "workflows.argoproj.io/test=true"}, func(t *testing.T, output string, err error) { diff --git a/test/e2e/smoke/basic-invalid.yaml b/test/e2e/smoke/basic-invalid.yaml new file mode 100644 index 000000000000..5f47f1ade61f --- /dev/null +++ b/test/e2e/smoke/basic-invalid.yaml @@ -0,0 +1,11 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: basic- +spec: + entrypoint: run-workflow + templates: + - name: run-workflow + container: + image: argoproj/argosay:v2 + args: [echo, ":( no hello because:"]-this-is-invalid-yaml \ No newline at end of file diff --git a/workflow/common/parse.go b/workflow/common/parse.go index 56836ca8fd56..29d5de552e95 100644 --- a/workflow/common/parse.go +++ b/workflow/common/parse.go @@ -22,7 +22,7 @@ type ParseResult struct { } func ParseObjects(body []byte, strict bool) []ParseResult { - res := []ParseResult{} + var res []ParseResult if jsonpkg.IsJSON(body) { un := &unstructured.Unstructured{} err := jsonpkg.Unmarshal(body, un) @@ -34,15 +34,19 @@ func ParseObjects(body []byte, strict bool) []ParseResult { return append(res, ParseResult{v, err}) } - for _, text := range yamlSeparator.Split(string(body), -1) { + for i, text := range yamlSeparator.Split(string(body), -1) { if strings.TrimSpace(text) == "" { continue } un := &unstructured.Unstructured{} err := yaml.Unmarshal([]byte(text), un) - if un.GetKind() != "" && err != nil { - // only return an error if this is a kubernetes object, otherwise, ignore - res = append(res, ParseResult{nil, err}) + if err != nil { + // Only return an error if this is a kubernetes object, otherwise, print the error + if un.GetKind() != "" { + res = append(res, ParseResult{nil, err}) + } else { + log.Errorf("yaml file at index %d is not valid: %s", i, err) + } continue } v, err := toWorkflowTypeYAML([]byte(text), un.GetKind(), strict) From 7ea35fa1fd0fa739f16b5978a52a521fafb90d4e Mon Sep 17 00:00:00 2001 From: Alex Collins Date: Thu, 4 Nov 2021 12:52:50 -0700 Subject: [PATCH 21/64] fix(ui): Correctly show zero-state when CRDs not installed. Fixes #7001 (#7169) Signed-off-by: Alex Collins --- .../event-source-list/event-source-list.tsx | 14 ++++++++------ .../components/pipeline-list/pipeline-list.tsx | 11 +++++++---- .../sensors/components/sensor-list/sensor-list.tsx | 14 ++++++++------ 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/ui/src/app/event-sources/components/event-source-list/event-source-list.tsx b/ui/src/app/event-sources/components/event-source-list/event-source-list.tsx index b449eb9817b7..065a42e20f72 100644 --- a/ui/src/app/event-sources/components/event-source-list/event-source-list.tsx +++ b/ui/src/app/event-sources/components/event-source-list/event-source-list.tsx @@ -3,8 +3,7 @@ import * as classNames from 'classnames'; import * as React from 'react'; import {useContext, useEffect, useState} from 'react'; import {Link, RouteComponentProps} from 'react-router-dom'; -import {EventSource} from '../../../../models'; -import {kubernetes} from '../../../../models'; +import {EventSource, kubernetes} from '../../../../models'; import {ID} from '../../../event-flow/components/event-flow-details/id'; import {Utils as EventsUtils} from '../../../sensors/components/utils'; import {uiUrl} from '../../../shared/base'; @@ -80,6 +79,9 @@ export const EventSourceList = ({match, location, history}: RouteComponentProps< return {value, ...x}; })(); + const loading = !error && !eventSources; + const zeroState = (eventSources || []).length === 0; + return ( ] }}> - {!eventSources ? ( - - ) : eventSources.length === 0 ? ( + {loading && } + {zeroState && (

An event source defines what events can be used to trigger actions. Typical event sources are calender (to create events on schedule) GitHub or GitLab (to @@ -111,7 +112,8 @@ export const EventSourceList = ({match, location, history}: RouteComponentProps<

{learnMore}.

- ) : ( + )} + {eventSources && eventSources.length > 0 && ( <>
diff --git a/ui/src/app/pipelines/components/pipeline-list/pipeline-list.tsx b/ui/src/app/pipelines/components/pipeline-list/pipeline-list.tsx index bdcbc597186d..aada836b49c1 100644 --- a/ui/src/app/pipelines/components/pipeline-list/pipeline-list.tsx +++ b/ui/src/app/pipelines/components/pipeline-list/pipeline-list.tsx @@ -46,6 +46,9 @@ export const PipelineList = ({match, history}: RouteComponentProps) => { return () => lw.stop(); }, [namespace]); + const loading = !error && !pipelines; + const zeroState = (pipelines || []).length === 0; + return ( ) => { tools: [] }}> - {!pipelines ? ( - - ) : pipelines.length === 0 ? ( + {loading && } + {zeroState && (

Argo Dataflow is a Kubernetes native platform for executing large parallel data-processing pipelines.

@@ -74,7 +76,8 @@ export const PipelineList = ({match, history}: RouteComponentProps) => { Learn more

- ) : ( + )} + {pipelines && pipelines.length > 0 && ( <>
diff --git a/ui/src/app/sensors/components/sensor-list/sensor-list.tsx b/ui/src/app/sensors/components/sensor-list/sensor-list.tsx index 42600d25e3f6..90a6b008b6dc 100644 --- a/ui/src/app/sensors/components/sensor-list/sensor-list.tsx +++ b/ui/src/app/sensors/components/sensor-list/sensor-list.tsx @@ -3,8 +3,7 @@ import * as classNames from 'classnames'; import * as React from 'react'; import {useContext, useEffect, useState} from 'react'; import {Link, RouteComponentProps} from 'react-router-dom'; -import {Sensor} from '../../../../models'; -import {kubernetes} from '../../../../models'; +import {kubernetes, Sensor} from '../../../../models'; import {ID} from '../../../event-flow/components/event-flow-details/id'; import {uiUrl} from '../../../shared/base'; import {ErrorNotice} from '../../../shared/components/error-notice'; @@ -76,6 +75,9 @@ export const SensorList = ({match, location, history}: RouteComponentProps) return {value, ...x}; })(); + const loading = !error && !sensors; + const zeroState = (sensors || []).length === 0; + return ( ) tools: [] }}> - {!sensors ? ( - - ) : sensors.length === 0 ? ( + {loading && } + {zeroState && (

A sensor defines what actions to trigger when certain events occur. Typical events are a Git push, a file dropped into a bucket, or a message on a queue or @@ -107,7 +108,8 @@ export const SensorList = ({match, location, history}: RouteComponentProps)

{learnMore}.

- ) : ( + )} + {sensors && sensors.length > 0 && ( <>
From e65d9d4a983670c70707d283573d06a68971f6b4 Mon Sep 17 00:00:00 2001 From: kennytrytek Date: Tue, 9 Nov 2021 13:11:35 -0600 Subject: [PATCH 22/64] fix: allow wf templates without parameter values (Fixes #6044) (#7124) * fix: allow wf templates without parameter values Signed-off-by: Kenny Trytek --- .../cluster_workflow_template_server.go | 6 +-- .../cluster_workflow_template_server_test.go | 53 ++++++++++++++----- server/workflow/workflow_server.go | 2 +- server/workflow/workflow_server_test.go | 21 ++++++-- .../workflow_template_server.go | 6 +-- .../workflow_template_server_test.go | 12 +++++ workflow/util/util.go | 4 +- workflow/validate/validate.go | 44 +++++++++------ workflow/validate/validate_test.go | 36 ++++++++----- 9 files changed, 130 insertions(+), 54 deletions(-) diff --git a/server/clusterworkflowtemplate/cluster_workflow_template_server.go b/server/clusterworkflowtemplate/cluster_workflow_template_server.go index 8a114089ef11..3966361e1fc4 100644 --- a/server/clusterworkflowtemplate/cluster_workflow_template_server.go +++ b/server/clusterworkflowtemplate/cluster_workflow_template_server.go @@ -32,7 +32,7 @@ func (cwts *ClusterWorkflowTemplateServer) CreateClusterWorkflowTemplate(ctx con cwts.instanceIDService.Label(req.Template) creator.Label(ctx, req.Template) cwftmplGetter := templateresolution.WrapClusterWorkflowTemplateInterface(wfClient.ArgoprojV1alpha1().ClusterWorkflowTemplates()) - _, err := validate.ValidateClusterWorkflowTemplate(nil, cwftmplGetter, req.Template) + _, err := validate.ValidateClusterWorkflowTemplate(nil, cwftmplGetter, req.Template, validate.ValidateOpts{}) if err != nil { return nil, err } @@ -97,7 +97,7 @@ func (cwts *ClusterWorkflowTemplateServer) LintClusterWorkflowTemplate(ctx conte wfClient := auth.GetWfClient(ctx) cwftmplGetter := templateresolution.WrapClusterWorkflowTemplateInterface(wfClient.ArgoprojV1alpha1().ClusterWorkflowTemplates()) - _, err := validate.ValidateClusterWorkflowTemplate(nil, cwftmplGetter, req.Template) + _, err := validate.ValidateClusterWorkflowTemplate(nil, cwftmplGetter, req.Template, validate.ValidateOpts{Lint: true}) if err != nil { return nil, err } @@ -116,7 +116,7 @@ func (cwts *ClusterWorkflowTemplateServer) UpdateClusterWorkflowTemplate(ctx con wfClient := auth.GetWfClient(ctx) cwftmplGetter := templateresolution.WrapClusterWorkflowTemplateInterface(wfClient.ArgoprojV1alpha1().ClusterWorkflowTemplates()) - _, err = validate.ValidateClusterWorkflowTemplate(nil, cwftmplGetter, req.Template) + _, err = validate.ValidateClusterWorkflowTemplate(nil, cwftmplGetter, req.Template, validate.ValidateOpts{}) if err != nil { return nil, err } diff --git a/server/clusterworkflowtemplate/cluster_workflow_template_server_test.go b/server/clusterworkflowtemplate/cluster_workflow_template_server_test.go index b77dc8764ebd..aad9e00d9b95 100644 --- a/server/clusterworkflowtemplate/cluster_workflow_template_server_test.go +++ b/server/clusterworkflowtemplate/cluster_workflow_template_server_test.go @@ -154,18 +154,33 @@ func getClusterWorkflowTemplateServer() (clusterwftmplpkg.ClusterWorkflowTemplat func TestWorkflowTemplateServer_CreateClusterWorkflowTemplate(t *testing.T) { server, ctx := getClusterWorkflowTemplateServer() - cwftReq := clusterwftmplpkg.ClusterWorkflowTemplateCreateRequest{ - Template: unlabelled.DeepCopy(), - } - cwftReq.Template.Name = "foo" - assert.NotContains(t, cwftReq.Template.Labels, common.LabelKeyControllerInstanceID) - cwftRsp, err := server.CreateClusterWorkflowTemplate(ctx, &cwftReq) - if assert.NoError(t, err) { - assert.NotNil(t, cwftRsp) - // ensure the label is added - assert.Contains(t, cwftRsp.Labels, common.LabelKeyControllerInstanceID) - assert.Contains(t, cwftRsp.Labels, common.LabelKeyCreator) - } + t.Run("Without parameter values", func(t *testing.T) { + tmpl := unlabelled.DeepCopy() + tmpl.Name = "foo-without-param-values" + tmpl.Spec.Arguments.Parameters[0].Value = nil + req := clusterwftmplpkg.ClusterWorkflowTemplateCreateRequest{ + Template: tmpl, + } + resp, err := server.CreateClusterWorkflowTemplate(ctx, &req) + if assert.NoError(t, err) { + assert.Equal(t, "message", resp.Spec.Arguments.Parameters[0].Name) + assert.Nil(t, resp.Spec.Arguments.Parameters[0].Value) + } + }) + t.Run("With parameter values", func(t *testing.T) { + cwftReq := clusterwftmplpkg.ClusterWorkflowTemplateCreateRequest{ + Template: unlabelled.DeepCopy(), + } + cwftReq.Template.Name = "foo-with-param-values" + assert.NotContains(t, cwftReq.Template.Labels, common.LabelKeyControllerInstanceID) + cwftRsp, err := server.CreateClusterWorkflowTemplate(ctx, &cwftReq) + if assert.NoError(t, err) { + assert.NotNil(t, cwftRsp) + // ensure the label is added + assert.Contains(t, cwftRsp.Labels, common.LabelKeyControllerInstanceID) + assert.Contains(t, cwftRsp.Labels, common.LabelKeyCreator) + } + }) } func TestWorkflowTemplateServer_GetClusterWorkflowTemplate(t *testing.T) { @@ -228,6 +243,20 @@ func TestWorkflowTemplateServer_LintClusterWorkflowTemplate(t *testing.T) { assert.Contains(t, resp.Labels, common.LabelKeyCreator) } }) + + t.Run("Without param values", func(t *testing.T) { + tmpl := unlabelled.DeepCopy() + tmpl.Name = "foo-without-param-values" + tmpl.Spec.Arguments.Parameters[0].Value = nil + req := clusterwftmplpkg.ClusterWorkflowTemplateLintRequest{ + Template: tmpl, + } + resp, err := server.LintClusterWorkflowTemplate(ctx, &req) + if assert.NoError(t, err) { + assert.Equal(t, "message", resp.Spec.Arguments.Parameters[0].Name) + assert.Nil(t, resp.Spec.Arguments.Parameters[0].Value) + } + }) } func TestWorkflowTemplateServer_UpdateClusterWorkflowTemplate(t *testing.T) { diff --git a/server/workflow/workflow_server.go b/server/workflow/workflow_server.go index 4a6ffc2e450b..499e3af1a845 100644 --- a/server/workflow/workflow_server.go +++ b/server/workflow/workflow_server.go @@ -609,7 +609,7 @@ func (s *workflowServer) SubmitWorkflow(ctx context.Context, req *workflowpkg.Wo wftmplGetter := templateresolution.WrapWorkflowTemplateInterface(wfClient.ArgoprojV1alpha1().WorkflowTemplates(req.Namespace)) cwftmplGetter := templateresolution.WrapClusterWorkflowTemplateInterface(wfClient.ArgoprojV1alpha1().ClusterWorkflowTemplates()) - _, err = validate.ValidateWorkflow(wftmplGetter, cwftmplGetter, wf, validate.ValidateOpts{}) + _, err = validate.ValidateWorkflow(wftmplGetter, cwftmplGetter, wf, validate.ValidateOpts{Submit: true}) if err != nil { return nil, err } diff --git a/server/workflow/workflow_server_test.go b/server/workflow/workflow_server_test.go index e70870ed646d..58edfccff279 100644 --- a/server/workflow/workflow_server_test.go +++ b/server/workflow/workflow_server_test.go @@ -447,8 +447,7 @@ const workflowtmpl = ` "arguments": { "parameters": [ { - "name": "message", - "value": "hello world" + "name": "message" } ] }, @@ -880,12 +879,26 @@ func TestPodLogs(t *testing.T) { func TestSubmitWorkflowFromResource(t *testing.T) { server, ctx := getWorkflowServer() - t.Run("SubmitFromWorkflowTemplate", func(t *testing.T) { - wf, err := server.SubmitWorkflow(ctx, &workflowpkg.WorkflowSubmitRequest{ + t.Run("SubmitFromWorkflowTemplate fails if missing parameters", func(t *testing.T) { + _, err := server.SubmitWorkflow(ctx, &workflowpkg.WorkflowSubmitRequest{ Namespace: "workflows", ResourceKind: "workflowtemplate", ResourceName: "workflow-template-whalesay-template", }) + assert.EqualError(t, err, "spec.arguments.message.value is required") + }) + t.Run("SubmitFromWorkflowTemplate", func(t *testing.T) { + opts := v1alpha1.SubmitOpts{ + Parameters: []string{ + "message=hello", + }, + } + wf, err := server.SubmitWorkflow(ctx, &workflowpkg.WorkflowSubmitRequest{ + Namespace: "workflows", + ResourceKind: "workflowtemplate", + ResourceName: "workflow-template-whalesay-template", + SubmitOptions: &opts, + }) if assert.NoError(t, err) { assert.NotNil(t, wf) assert.Contains(t, wf.Labels, common.LabelKeyControllerInstanceID) diff --git a/server/workflowtemplate/workflow_template_server.go b/server/workflowtemplate/workflow_template_server.go index 6d1f39605740..94bb996a43ec 100644 --- a/server/workflowtemplate/workflow_template_server.go +++ b/server/workflowtemplate/workflow_template_server.go @@ -33,7 +33,7 @@ func (wts *WorkflowTemplateServer) CreateWorkflowTemplate(ctx context.Context, r creator.Label(ctx, req.Template) wftmplGetter := templateresolution.WrapWorkflowTemplateInterface(wfClient.ArgoprojV1alpha1().WorkflowTemplates(req.Namespace)) cwftmplGetter := templateresolution.WrapClusterWorkflowTemplateInterface(wfClient.ArgoprojV1alpha1().ClusterWorkflowTemplates()) - _, err := validate.ValidateWorkflowTemplate(wftmplGetter, cwftmplGetter, req.Template) + _, err := validate.ValidateWorkflowTemplate(wftmplGetter, cwftmplGetter, req.Template, validate.ValidateOpts{}) if err != nil { return nil, err } @@ -93,7 +93,7 @@ func (wts *WorkflowTemplateServer) LintWorkflowTemplate(ctx context.Context, req creator.Label(ctx, req.Template) wftmplGetter := templateresolution.WrapWorkflowTemplateInterface(wfClient.ArgoprojV1alpha1().WorkflowTemplates(req.Namespace)) cwftmplGetter := templateresolution.WrapClusterWorkflowTemplateInterface(wfClient.ArgoprojV1alpha1().ClusterWorkflowTemplates()) - _, err := validate.ValidateWorkflowTemplate(wftmplGetter, cwftmplGetter, req.Template) + _, err := validate.ValidateWorkflowTemplate(wftmplGetter, cwftmplGetter, req.Template, validate.ValidateOpts{Lint: true}) if err != nil { return nil, err } @@ -111,7 +111,7 @@ func (wts *WorkflowTemplateServer) UpdateWorkflowTemplate(ctx context.Context, r wfClient := auth.GetWfClient(ctx) wftmplGetter := templateresolution.WrapWorkflowTemplateInterface(wfClient.ArgoprojV1alpha1().WorkflowTemplates(req.Namespace)) cwftmplGetter := templateresolution.WrapClusterWorkflowTemplateInterface(wfClient.ArgoprojV1alpha1().ClusterWorkflowTemplates()) - _, err = validate.ValidateWorkflowTemplate(wftmplGetter, cwftmplGetter, req.Template) + _, err = validate.ValidateWorkflowTemplate(wftmplGetter, cwftmplGetter, req.Template, validate.ValidateOpts{}) if err != nil { return nil, err } diff --git a/server/workflowtemplate/workflow_template_server_test.go b/server/workflowtemplate/workflow_template_server_test.go index 44c650e059c3..f6a600f70126 100644 --- a/server/workflowtemplate/workflow_template_server_test.go +++ b/server/workflowtemplate/workflow_template_server_test.go @@ -172,6 +172,18 @@ func getWorkflowTemplateServer() (workflowtemplatepkg.WorkflowTemplateServiceSer func TestWorkflowTemplateServer_CreateWorkflowTemplate(t *testing.T) { server, ctx := getWorkflowTemplateServer() + t.Run("Without parameter values", func(t *testing.T) { + var wftReq workflowtemplatepkg.WorkflowTemplateCreateRequest + v1alpha1.MustUnmarshal(wftStr1, &wftReq) + wftReq.Template.Name = "foo-without-param-values" + wftReq.Template.Spec.Arguments.Parameters[0].Value = nil + wftRsp, err := server.CreateWorkflowTemplate(ctx, &wftReq) + if assert.NoError(t, err) { + assert.NotNil(t, wftRsp) + assert.Equal(t, "message", wftRsp.Spec.Arguments.Parameters[0].Name) + assert.Nil(t, wftRsp.Spec.Arguments.Parameters[0].Value) + } + }) t.Run("Labelled", func(t *testing.T) { var wftReq workflowtemplatepkg.WorkflowTemplateCreateRequest v1alpha1.MustUnmarshal(wftStr1, &wftReq) diff --git a/workflow/util/util.go b/workflow/util/util.go index 62451bad7169..483a2d7bfcd6 100644 --- a/workflow/util/util.go +++ b/workflow/util/util.go @@ -169,7 +169,7 @@ func IsWorkflowCompleted(wf *wfv1.Workflow) bool { return false } -// SubmitWorkflow validates and submit a single workflow and override some of the fields of the workflow +// SubmitWorkflow validates and submits a single workflow and overrides some of the fields of the workflow func SubmitWorkflow(ctx context.Context, wfIf v1alpha1.WorkflowInterface, wfClientset wfclientset.Interface, namespace string, wf *wfv1.Workflow, opts *wfv1.SubmitOpts) (*wfv1.Workflow, error) { err := ApplySubmitOpts(wf, opts) if err != nil { @@ -178,7 +178,7 @@ func SubmitWorkflow(ctx context.Context, wfIf v1alpha1.WorkflowInterface, wfClie wftmplGetter := templateresolution.WrapWorkflowTemplateInterface(wfClientset.ArgoprojV1alpha1().WorkflowTemplates(namespace)) cwftmplGetter := templateresolution.WrapClusterWorkflowTemplateInterface(wfClientset.ArgoprojV1alpha1().ClusterWorkflowTemplates()) - _, err = validate.ValidateWorkflow(wftmplGetter, cwftmplGetter, wf, validate.ValidateOpts{}) + _, err = validate.ValidateWorkflow(wftmplGetter, cwftmplGetter, wf, validate.ValidateOpts{Submit: true}) if err != nil { return nil, err } diff --git a/workflow/validate/validate.go b/workflow/validate/validate.go index ec08ee760b29..0a28be565d9c 100644 --- a/workflow/validate/validate.go +++ b/workflow/validate/validate.go @@ -33,6 +33,7 @@ type ValidateOpts struct { // skip some validations which is permissible during linting but not submission (e.g. missing // input parameters to the workflow) Lint bool + // ContainerRuntimeExecutor will trigger additional validation checks specific to different // types of executors. For example, the inability of kubelet/k8s executors to copy artifacts // out of the base image layer. If unspecified, will use docker executor validation @@ -44,6 +45,10 @@ type ValidateOpts struct { // WorkflowTemplateValidation indicates that the current context is validating a WorkflowTemplate or ClusterWorkflowTemplate WorkflowTemplateValidation bool + + // Submit indicates that the current operation is a workflow submission. This will impose + // more stringent requirements (e.g. require input values for all spec arguments) + Submit bool } // templateValidationCtx is the context for validating a workflow spec @@ -149,13 +154,12 @@ func ValidateWorkflow(wftmplGetter templateresolution.WorkflowTemplateNamespaced if err != nil { return nil, errors.Errorf(errors.CodeBadRequest, "spec.templates%s", err.Error()) } - if ctx.Lint { - // if we are just linting we don't care if spec.arguments.parameters.XXX doesn't have an - // explicit value. workflows without a default value is a desired use case - err = validateArgumentsFieldNames("spec.arguments.", wfArgs) - } else { - err = validateArguments("spec.arguments.", wfArgs) - } + + // if we are linting, we don't care if spec.arguments.parameters.XXX doesn't have an + // explicit value. Workflow templates without a default value are also a desired use + // case, since values will be provided during workflow submission. + allowEmptyValues := ctx.Lint || (ctx.WorkflowTemplateValidation && !ctx.Submit) + err = validateArguments("spec.arguments.", wfArgs, allowEmptyValues) if err != nil { return nil, err } @@ -239,7 +243,7 @@ func ValidateWorkflowTemplateRefFields(wfSpec wfv1.WorkflowSpec) error { } // ValidateWorkflowTemplate accepts a workflow template and performs validation against it. -func ValidateWorkflowTemplate(wftmplGetter templateresolution.WorkflowTemplateNamespacedGetter, cwftmplGetter templateresolution.ClusterWorkflowTemplateGetter, wftmpl *wfv1.WorkflowTemplate) (*wfv1.Conditions, error) { +func ValidateWorkflowTemplate(wftmplGetter templateresolution.WorkflowTemplateNamespacedGetter, cwftmplGetter templateresolution.ClusterWorkflowTemplateGetter, wftmpl *wfv1.WorkflowTemplate, opts ValidateOpts) (*wfv1.Conditions, error) { if len(wftmpl.Name) > maxCharsInObjectName { return nil, fmt.Errorf("workflow template name %q must not be more than 63 characters long (currently %d)", wftmpl.Name, len(wftmpl.Name)) } @@ -251,11 +255,13 @@ func ValidateWorkflowTemplate(wftmplGetter templateresolution.WorkflowTemplateNa }, Spec: wftmpl.Spec.WorkflowSpec, } - return ValidateWorkflow(wftmplGetter, cwftmplGetter, wf, ValidateOpts{IgnoreEntrypoint: wf.Spec.Entrypoint == "", WorkflowTemplateValidation: true}) + opts.IgnoreEntrypoint = wf.Spec.Entrypoint == "" + opts.WorkflowTemplateValidation = true + return ValidateWorkflow(wftmplGetter, cwftmplGetter, wf, opts) } // ValidateClusterWorkflowTemplate accepts a cluster workflow template and performs validation against it. -func ValidateClusterWorkflowTemplate(wftmplGetter templateresolution.WorkflowTemplateNamespacedGetter, cwftmplGetter templateresolution.ClusterWorkflowTemplateGetter, cwftmpl *wfv1.ClusterWorkflowTemplate) (*wfv1.Conditions, error) { +func ValidateClusterWorkflowTemplate(wftmplGetter templateresolution.WorkflowTemplateNamespacedGetter, cwftmplGetter templateresolution.ClusterWorkflowTemplateGetter, cwftmpl *wfv1.ClusterWorkflowTemplate, opts ValidateOpts) (*wfv1.Conditions, error) { if len(cwftmpl.Name) > maxCharsInObjectName { return nil, fmt.Errorf("cluster workflow template name %q must not be more than 63 characters long (currently %d)", cwftmpl.Name, len(cwftmpl.Name)) } @@ -267,7 +273,9 @@ func ValidateClusterWorkflowTemplate(wftmplGetter templateresolution.WorkflowTem }, Spec: cwftmpl.Spec.WorkflowSpec, } - return ValidateWorkflow(wftmplGetter, cwftmplGetter, wf, ValidateOpts{IgnoreEntrypoint: wf.Spec.Entrypoint == "", WorkflowTemplateValidation: true}) + opts.IgnoreEntrypoint = wf.Spec.Entrypoint == "" + opts.WorkflowTemplateValidation = true + return ValidateWorkflow(wftmplGetter, cwftmplGetter, wf, opts) } // ValidateCronWorkflow validates a CronWorkflow @@ -680,12 +688,12 @@ func (ctx *templateValidationCtx) validateLeaf(scope map[string]interface{}, tmp return nil } -func validateArguments(prefix string, arguments wfv1.Arguments) error { +func validateArguments(prefix string, arguments wfv1.Arguments, allowEmptyValues bool) error { err := validateArgumentsFieldNames(prefix, arguments) if err != nil { return err } - return validateArgumentsValues(prefix, arguments) + return validateArgumentsValues(prefix, arguments, allowEmptyValues) } func validateArgumentsFieldNames(prefix string, arguments wfv1.Arguments) error { @@ -703,10 +711,12 @@ func validateArgumentsFieldNames(prefix string, arguments wfv1.Arguments) error } // validateArgumentsValues ensures that all arguments have parameter values or artifact locations -func validateArgumentsValues(prefix string, arguments wfv1.Arguments) error { +func validateArgumentsValues(prefix string, arguments wfv1.Arguments, allowEmptyValues bool) error { for _, param := range arguments.Parameters { if param.ValueFrom == nil && param.Value == nil { - return errors.Errorf(errors.CodeBadRequest, "%s%s.value is required", prefix, param.Name) + if !allowEmptyValues { + return errors.Errorf(errors.CodeBadRequest, "%s%s.value is required", prefix, param.Name) + } } if param.Enum != nil { if len(param.Enum) == 0 { @@ -761,7 +771,7 @@ func (ctx *templateValidationCtx) validateSteps(scope map[string]interface{}, tm if err != nil { return errors.Errorf(errors.CodeBadRequest, "templates.%s.steps[%d].%s %s", tmpl.Name, i, step.Name, err.Error()) } - err = validateArguments(fmt.Sprintf("templates.%s.steps[%d].%s.arguments.", tmpl.Name, i, step.Name), step.Arguments) + err = validateArguments(fmt.Sprintf("templates.%s.steps[%d].%s.arguments.", tmpl.Name, i, step.Name), step.Arguments, false) if err != nil { return err } @@ -1265,7 +1275,7 @@ func (ctx *templateValidationCtx) validateDAG(scope map[string]interface{}, tmpl if err != nil { return errors.Errorf(errors.CodeBadRequest, "templates.%s.tasks.%s %s", tmpl.Name, task.Name, err.Error()) } - err = validateArguments(fmt.Sprintf("templates.%s.tasks.%s.arguments.", tmpl.Name, task.Name), task.Arguments) + err = validateArguments(fmt.Sprintf("templates.%s.tasks.%s.arguments.", tmpl.Name, task.Name), task.Arguments, false) if err != nil { return err } diff --git a/workflow/validate/validate_test.go b/workflow/validate/validate_test.go index 997d360bf5d3..4f0cea651a74 100644 --- a/workflow/validate/validate_test.go +++ b/workflow/validate/validate_test.go @@ -45,9 +45,9 @@ func validateWithOptions(yamlStr string, opts ValidateOpts) (*wfv1.Conditions, e // validateWorkflowTemplate is a test helper to accept WorkflowTemplate YAML as a string and return // its validation result. -func validateWorkflowTemplate(yamlStr string) error { +func validateWorkflowTemplate(yamlStr string, opts ValidateOpts) error { wftmpl := unmarshalWftmpl(yamlStr) - _, err := ValidateWorkflowTemplate(wftmplGetter, cwftmplGetter, wftmpl) + _, err := ValidateWorkflowTemplate(wftmplGetter, cwftmplGetter, wftmpl, opts) return err } @@ -1671,7 +1671,7 @@ spec: ` func TestWorkflowTemplate(t *testing.T) { - err := validateWorkflowTemplate(templateRefTarget) + err := validateWorkflowTemplate(templateRefTarget, ValidateOpts{}) assert.NoError(t, err) } @@ -2298,7 +2298,7 @@ spec: ` func TestWorkflowTemplateWithEntrypoint(t *testing.T) { - err := validateWorkflowTemplate(wfTemplateWithEntrypoint) + err := validateWorkflowTemplate(wfTemplateWithEntrypoint, ValidateOpts{}) assert.NoError(t, err) } @@ -2567,7 +2567,7 @@ spec: ` func TestWorkflowTemplateLabels(t *testing.T) { - err := validateWorkflowTemplate(testWorkflowTemplateLabels) + err := validateWorkflowTemplate(testWorkflowTemplateLabels, ValidateOpts{}) assert.NoError(t, err) } @@ -2733,17 +2733,29 @@ spec: ` func TestWorkflowTemplateWithEnumValue(t *testing.T) { - err := validateWorkflowTemplate(workflowTeamplateWithEnumValues) + err := validateWorkflowTemplate(workflowTeamplateWithEnumValues, ValidateOpts{}) + assert.NoError(t, err) + err = validateWorkflowTemplate(workflowTeamplateWithEnumValues, ValidateOpts{Lint: true}) + assert.NoError(t, err) + err = validateWorkflowTemplate(workflowTeamplateWithEnumValues, ValidateOpts{Submit: true}) assert.NoError(t, err) } func TestWorkflowTemplateWithEmptyEnumList(t *testing.T) { - err := validateWorkflowTemplate(workflowTemplateWithEmptyEnumList) + err := validateWorkflowTemplate(workflowTemplateWithEmptyEnumList, ValidateOpts{}) + assert.EqualError(t, err, "spec.arguments.message.enum should contain at least one value") + err = validateWorkflowTemplate(workflowTemplateWithEmptyEnumList, ValidateOpts{Lint: true}) + assert.EqualError(t, err, "spec.arguments.message.enum should contain at least one value") + err = validateWorkflowTemplate(workflowTemplateWithEmptyEnumList, ValidateOpts{Submit: true}) assert.EqualError(t, err, "spec.arguments.message.enum should contain at least one value") } func TestWorkflowTemplateWithArgumentValueNotFromEnumList(t *testing.T) { - err := validateWorkflowTemplate(workflowTemplateWithArgumentValueNotFromEnumList) + err := validateWorkflowTemplate(workflowTemplateWithArgumentValueNotFromEnumList, ValidateOpts{}) + assert.EqualError(t, err, "spec.arguments.message.value should be present in spec.arguments.message.enum list") + err = validateWorkflowTemplate(workflowTemplateWithArgumentValueNotFromEnumList, ValidateOpts{Lint: true}) + assert.EqualError(t, err, "spec.arguments.message.value should be present in spec.arguments.message.enum list") + err = validateWorkflowTemplate(workflowTemplateWithArgumentValueNotFromEnumList, ValidateOpts{Submit: true}) assert.EqualError(t, err, "spec.arguments.message.value should be present in spec.arguments.message.enum list") } @@ -2787,7 +2799,7 @@ spec: ` func TestValidActiveDeadlineSecondsArgoVariable(t *testing.T) { - err := validateWorkflowTemplate(validActiveDeadlineSecondsArgoVariable) + err := validateWorkflowTemplate(validActiveDeadlineSecondsArgoVariable, ValidateOpts{}) assert.NoError(t, err) } @@ -2797,11 +2809,11 @@ func TestMaxLengthName(t *testing.T) { assert.EqualError(t, err, "workflow name \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\" must not be more than 63 characters long (currently 70)") wftmpl := &wfv1.WorkflowTemplate{ObjectMeta: metav1.ObjectMeta{Name: strings.Repeat("a", 70)}} - _, err = ValidateWorkflowTemplate(wftmplGetter, cwftmplGetter, wftmpl) + _, err = ValidateWorkflowTemplate(wftmplGetter, cwftmplGetter, wftmpl, ValidateOpts{}) assert.EqualError(t, err, "workflow template name \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\" must not be more than 63 characters long (currently 70)") cwftmpl := &wfv1.ClusterWorkflowTemplate{ObjectMeta: metav1.ObjectMeta{Name: strings.Repeat("a", 70)}} - _, err = ValidateClusterWorkflowTemplate(wftmplGetter, cwftmplGetter, cwftmpl) + _, err = ValidateClusterWorkflowTemplate(wftmplGetter, cwftmplGetter, cwftmpl, ValidateOpts{}) assert.EqualError(t, err, "cluster workflow template name \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\" must not be more than 63 characters long (currently 70)") cwf := &wfv1.CronWorkflow{ObjectMeta: metav1.ObjectMeta{Name: strings.Repeat("a", 60)}} @@ -2904,7 +2916,7 @@ spec: invalidContainerSetTemplateWithOutputParams, } for _, manifest := range invalidManifests { - err := validateWorkflowTemplate(manifest) + err := validateWorkflowTemplate(manifest, ValidateOpts{}) if assert.NotNil(t, err) { assert.Contains(t, err.Error(), "containerSet.containers must have a container named \"main\" for input or output") } From 02b4c31c41e3b509188057d31735b1f3684488f5 Mon Sep 17 00:00:00 2001 From: Mathew Wicks Date: Fri, 12 Nov 2021 01:44:23 +1100 Subject: [PATCH 23/64] fix: ci sleep command syntax for macOS 12 (#7203) Signed-off-by: Mathew Wicks --- hack/port-forward.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hack/port-forward.sh b/hack/port-forward.sh index 2978e0c88af8..8fbb64f379e1 100755 --- a/hack/port-forward.sh +++ b/hack/port-forward.sh @@ -9,7 +9,7 @@ pf() { ./hack/free-port.sh $port echo "port-forward $resource $port" kubectl -n argo port-forward "svc/$resource" "$port:$dest_port" > /dev/null & - until lsof -i ":$port" > /dev/null ; do sleep 1s ; done + until lsof -i ":$port" > /dev/null ; do sleep 1 ; done } wait-for() { From ee6939048ab2b15103ece77b0d74afd6f0d3e691 Mon Sep 17 00:00:00 2001 From: Guillaume Fillon <648780+zirkome@users.noreply.github.com> Date: Mon, 15 Nov 2021 16:52:53 +0000 Subject: [PATCH 24/64] fix: Fix ANSI color sequences escaping (#7211) Signed-off-by: Guillaume Fillon --- .../workflow-logs-viewer/workflow-logs-viewer.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ui/src/app/workflows/components/workflow-logs-viewer/workflow-logs-viewer.tsx b/ui/src/app/workflows/components/workflow-logs-viewer/workflow-logs-viewer.tsx index 13118764ef57..b8a50e30366e 100644 --- a/ui/src/app/workflows/components/workflow-logs-viewer/workflow-logs-viewer.tsx +++ b/ui/src/app/workflows/components/workflow-logs-viewer/workflow-logs-viewer.tsx @@ -39,7 +39,12 @@ export const WorkflowLogsViewer = ({workflow, nodeId, initialPodName, container, .getContainerLogs(workflow, podName, selectedContainer, grep, archived) .map(e => (!podName ? e.podName + ': ' : '') + e.content + '\n') // this next line highlights the search term in bold with a yellow background, white text - .map(x => x.replace(new RegExp(grep, 'g'), y => '\u001b[1m\u001b[43;1m\u001b[37m' + y + '\u001b[0m')) + .map(x => { + if (grep !== '') { + return x.replace(new RegExp(grep, 'g'), y => '\u001b[1m\u001b[43;1m\u001b[37m' + y + '\u001b[0m'); + } + return x; + }) .publishReplay() .refCount(); const subscription = source.subscribe( From bf72557b53792cf23ce3ee4cbec779bb7e420ba8 Mon Sep 17 00:00:00 2001 From: Rob Herley Date: Wed, 17 Nov 2021 12:04:27 -0500 Subject: [PATCH 25/64] fix: add gh ecdsa and ed25519 to known hosts (#7226) Signed-off-by: Rob Herley --- hack/ssh_known_hosts | 2 ++ hack/update-ssh-known-hosts.sh | 2 ++ 2 files changed, 4 insertions(+) diff --git a/hack/ssh_known_hosts b/hack/ssh_known_hosts index 31a7bae3fce5..a89bb62154a5 100644 --- a/hack/ssh_known_hosts +++ b/hack/ssh_known_hosts @@ -1,5 +1,7 @@ # This file was automatically generated. DO NOT EDIT bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw== +github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= +github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ== gitlab.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY= gitlab.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf diff --git a/hack/update-ssh-known-hosts.sh b/hack/update-ssh-known-hosts.sh index aa74c6489add..d90467f765c1 100755 --- a/hack/update-ssh-known-hosts.sh +++ b/hack/update-ssh-known-hosts.sh @@ -15,6 +15,8 @@ chmod 0644 $KNOWN_HOSTS_FILE # - ssh.dev.azure.com, vs-ssh.visualstudio.com: https://docs.microsoft.com/en-us/azure/devops/repos/git/use-ssh-keys-to-authenticate?view=azure-devops diff - <(ssh-keygen -l -f $KNOWN_HOSTS_FILE | sort -k 3) < Date: Wed, 3 Nov 2021 08:46:42 -0700 Subject: [PATCH 26/64] chore: run builds using `ubuntu-latest` Signed-off-by: Alex Collins --- .github/workflows/ci-build.yaml | 10 +++++----- .github/workflows/gh-pages.yaml | 2 +- .github/workflows/release.yaml | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci-build.yaml b/.github/workflows/ci-build.yaml index 9cdf8d652ff7..24937357b033 100644 --- a/.github/workflows/ci-build.yaml +++ b/.github/workflows/ci-build.yaml @@ -12,7 +12,7 @@ on: jobs: tests: name: Unit Tests - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest # 5m30 timeout-minutes: 8 steps: @@ -36,7 +36,7 @@ jobs: e2e-tests: name: E2E Tests - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest timeout-minutes: 20 env: KUBECONFIG: /home/runner/.kubeconfig @@ -122,7 +122,7 @@ jobs: codegen: name: Codegen - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest needs: [ tests ] timeout-minutes: 9 env: @@ -169,7 +169,7 @@ jobs: lint: name: Lint - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest needs: [ tests, codegen ] timeout-minutes: 6 env: @@ -183,7 +183,7 @@ jobs: ui: name: UI - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest timeout-minutes: 6 env: NODE_OPTIONS: --max-old-space-size=4096 diff --git a/.github/workflows/gh-pages.yaml b/.github/workflows/gh-pages.yaml index b1b87ea6f373..dd396fa887a6 100644 --- a/.github/workflows/gh-pages.yaml +++ b/.github/workflows/gh-pages.yaml @@ -8,7 +8,7 @@ on: jobs: deploy: if: github.repository == 'argoproj/argo-workflows' - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup Python diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 4db697f02799..118f56bc9714 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -16,7 +16,7 @@ jobs: build-linux-amd64: name: Build & push linux/amd64 if: github.repository == 'argoproj/argo-workflows' - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest strategy: matrix: platform: [ linux/amd64 ] @@ -82,7 +82,7 @@ jobs: build-linux-arm64: name: Build & push linux/arm64 if: github.repository == 'argoproj/argo-workflows' - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest strategy: matrix: platform: [ linux/arm64 ] @@ -193,7 +193,7 @@ jobs: push-images: name: Push manifest with all images if: github.repository == 'argoproj/argo-workflows' - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest needs: [ build-linux-amd64, build-linux-arm64, build-windows ] steps: - uses: actions/checkout@v2 @@ -242,7 +242,7 @@ jobs: test-images-linux-amd64: name: Try pulling linux/amd64 if: github.repository == 'argoproj/argo-workflows' - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest needs: [ push-images ] strategy: matrix: @@ -313,7 +313,7 @@ jobs: done publish-release: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest if: github.repository == 'argoproj/argo-workflows' needs: [ push-images, test-images-linux-amd64, test-images-windows ] env: From 24ffd36bfc417fe382a1e015b0ec4d89b2a12280 Mon Sep 17 00:00:00 2001 From: NextNiclas <74151677+NextNiclas@users.noreply.github.com> Date: Tue, 19 Oct 2021 20:32:17 +0200 Subject: [PATCH 27/64] fix: Allow self-signed Root CA for SSO. Fixes #6793 (#6961) Signed-off-by: Niclas Schnickmann --- server/auth/sso/sso.go | 12 ++++++++---- server/auth/sso/sso_test.go | 3 ++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/server/auth/sso/sso.go b/server/auth/sso/sso.go index 72e89fb1b28f..686b5f2a5fa0 100644 --- a/server/auth/sso/sso.go +++ b/server/auth/sso/sso.go @@ -96,10 +96,13 @@ type providerInterface interface { Verifier(config *oidc.Config) *oidc.IDTokenVerifier } -type providerFactory func(ctx context.Context, issuer string) (providerInterface, error) +type providerFactory func(ctx context.Context, issuer string, tlsConfig *tls.Config) (providerInterface, error) -func providerFactoryOIDC(ctx context.Context, issuer string) (providerInterface, error) { - return oidc.NewProvider(ctx, issuer) +func providerFactoryOIDC(ctx context.Context, issuer string, tlsConfig *tls.Config) (providerInterface, error) { + // Create http client used by oidc provider to allow modification of underlying TLSClientConfig + httpClient := &http.Client{Transport: &http.Transport{TLSClientConfig: tlsConfig}} + oidcContext := oidc.ClientContext(ctx, httpClient) + return oidc.NewProvider(oidcContext, issuer) } func New(c Config, secretsIf corev1.SecretInterface, baseHRef string, secure bool) (Interface, error) { @@ -136,7 +139,8 @@ func newSso( oidcContext = oidc.InsecureIssuerURLContext(oidcContext, c.IssuerAlias) } - provider, err := factory(oidcContext, c.Issuer) + provider, err := factory(oidcContext, c.Issuer, &tls.Config{InsecureSkipVerify: c.InsecureSkipVerify}) + if err != nil { return nil, err } diff --git a/server/auth/sso/sso_test.go b/server/auth/sso/sso_test.go index a2aa005e6003..9b1f552a0fde 100644 --- a/server/auth/sso/sso_test.go +++ b/server/auth/sso/sso_test.go @@ -2,6 +2,7 @@ package sso import ( "context" + "crypto/tls" "testing" "time" @@ -28,7 +29,7 @@ func (fakeOidcProvider) Verifier(config *oidc.Config) *oidc.IDTokenVerifier { return nil } -func fakeOidcFactory(ctx context.Context, issuer string) (providerInterface, error) { +func fakeOidcFactory(ctx context.Context, issuer string, tlsConfig *tls.Config) (providerInterface, error) { return fakeOidcProvider{ctx, issuer}, nil } From 6b7e074f149085f9fc2da48656777301e87e8aae Mon Sep 17 00:00:00 2001 From: Peter Evers Date: Mon, 18 Oct 2021 20:28:37 +0200 Subject: [PATCH 28/64] fix(docs): fix data transformation example (#6901) Signed-off-by: Peter Evers --- docs/fields.md | 2 ++ examples/data-transformations.yaml | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/docs/fields.md b/docs/fields.md index d9ab62c660cf..c438023b9781 100644 --- a/docs/fields.md +++ b/docs/fields.md @@ -2185,6 +2185,8 @@ Outputs hold parameters, artifacts, and results from a step - [`dag-conditional-parameters.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/dag-conditional-parameters.yaml) +- [`data-transformations.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/data-transformations.yaml) + - [`exit-handler-with-artifacts.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/exit-handler-with-artifacts.yaml) - [`exit-handler-with-param.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/exit-handler-with-param.yaml) diff --git a/examples/data-transformations.yaml b/examples/data-transformations.yaml index 7c0921ac499f..9abb3ff43805 100644 --- a/examples/data-transformations.yaml +++ b/examples/data-transformations.yaml @@ -42,6 +42,10 @@ spec: transformation: - expression: "filter(data, {# endsWith \"main.log\"})" + outputs: + artifacts: + - name: file + path: /file - name: process-logs inputs: From fbb51ac2002b896ea3320802b814adb4c3d0d5e4 Mon Sep 17 00:00:00 2001 From: Arthur Sudre Date: Mon, 18 Oct 2021 21:36:33 +0200 Subject: [PATCH 29/64] fix: multi-steps workflow (#6957) --- examples/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/README.md b/examples/README.md index c81bea74448f..04c4b114c8d4 100644 --- a/examples/README.md +++ b/examples/README.md @@ -235,12 +235,12 @@ spec: parameters: - name: message value: "hello2a" - - name: hello2b # single dash => run in parallel with previous step - template: whalesay - arguments: - parameters: - - name: message - value: "hello2b" + - name: hello2b # single dash => run in parallel with previous step + template: whalesay + arguments: + parameters: + - name: message + value: "hello2b" # This is the same template as from the previous example - name: whalesay From 94fe92f12a21af225c0d44fa7b20a6b335edaadf Mon Sep 17 00:00:00 2001 From: NextNiclas <74151677+NextNiclas@users.noreply.github.com> Date: Wed, 20 Oct 2021 17:09:24 +0200 Subject: [PATCH 30/64] fix: OAuth2 callback with self-signed Root CA. Fixes #6793 (#6978) Signed-off-by: Niclas Schnickmann --- server/auth/sso/sso.go | 12 ++++-------- server/auth/sso/sso_test.go | 3 +-- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/server/auth/sso/sso.go b/server/auth/sso/sso.go index 686b5f2a5fa0..72e89fb1b28f 100644 --- a/server/auth/sso/sso.go +++ b/server/auth/sso/sso.go @@ -96,13 +96,10 @@ type providerInterface interface { Verifier(config *oidc.Config) *oidc.IDTokenVerifier } -type providerFactory func(ctx context.Context, issuer string, tlsConfig *tls.Config) (providerInterface, error) +type providerFactory func(ctx context.Context, issuer string) (providerInterface, error) -func providerFactoryOIDC(ctx context.Context, issuer string, tlsConfig *tls.Config) (providerInterface, error) { - // Create http client used by oidc provider to allow modification of underlying TLSClientConfig - httpClient := &http.Client{Transport: &http.Transport{TLSClientConfig: tlsConfig}} - oidcContext := oidc.ClientContext(ctx, httpClient) - return oidc.NewProvider(oidcContext, issuer) +func providerFactoryOIDC(ctx context.Context, issuer string) (providerInterface, error) { + return oidc.NewProvider(ctx, issuer) } func New(c Config, secretsIf corev1.SecretInterface, baseHRef string, secure bool) (Interface, error) { @@ -139,8 +136,7 @@ func newSso( oidcContext = oidc.InsecureIssuerURLContext(oidcContext, c.IssuerAlias) } - provider, err := factory(oidcContext, c.Issuer, &tls.Config{InsecureSkipVerify: c.InsecureSkipVerify}) - + provider, err := factory(oidcContext, c.Issuer) if err != nil { return nil, err } diff --git a/server/auth/sso/sso_test.go b/server/auth/sso/sso_test.go index 9b1f552a0fde..a2aa005e6003 100644 --- a/server/auth/sso/sso_test.go +++ b/server/auth/sso/sso_test.go @@ -2,7 +2,6 @@ package sso import ( "context" - "crypto/tls" "testing" "time" @@ -29,7 +28,7 @@ func (fakeOidcProvider) Verifier(config *oidc.Config) *oidc.IDTokenVerifier { return nil } -func fakeOidcFactory(ctx context.Context, issuer string, tlsConfig *tls.Config) (providerInterface, error) { +func fakeOidcFactory(ctx context.Context, issuer string) (providerInterface, error) { return fakeOidcProvider{ctx, issuer}, nil } From c9e9bc570e36be1748540568601dfdee6778e5f5 Mon Sep 17 00:00:00 2001 From: William Van Hevelingen Date: Fri, 22 Oct 2021 12:22:13 -0700 Subject: [PATCH 31/64] docs: Add contributor meeting information and fix slack channel (#7031) Signed-off-by: William Van Hevelingen --- docs/CONTRIBUTING.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index ff5d5c27cc75..fc3c3aebd3e1 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -8,13 +8,19 @@ Please [raise an issue in Github](https://github.com/argoproj/argo-workflows/iss See [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). +## Contributor Meetings + +A weekly opportunity for committers and maintainers of Workflows, Events, and Dataflow to discuss their current work and talk +about what’s next. Feel free to join us! For Contributor Meeting information, minutes and recordings +please [see here](https://bit.ly/argo-data-weekly). + ## How To Contribute We're always looking for contributors. * Documentation - something missing or unclear? Please submit a pull request! * Code contribution - investigate a [help wanted issue](https://github.com/argoproj/argo-workflows/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22+label%3A%22good+first+issue%22), or anything labelled with "good first issue"? -* Join the #argo-devs channel on [our Slack](https://argoproj.github.io/community/join-slack). +* Join the `#argo-contributors` channel on [our Slack](https://argoproj.github.io/community/join-slack). ### Running Locally From fa0772fd936364d915514da4ea1217c0e3639af1 Mon Sep 17 00:00:00 2001 From: Tianchu Zhao Date: Tue, 26 Oct 2021 23:17:28 +1100 Subject: [PATCH 32/64] docs(cli): fix cron delete flag description (#7058) --- cmd/argo/commands/cron/delete.go | 2 +- docs/cli/argo_cron_delete.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/argo/commands/cron/delete.go b/cmd/argo/commands/cron/delete.go index 5e55e73b418b..9e3bf4790ade 100644 --- a/cmd/argo/commands/cron/delete.go +++ b/cmd/argo/commands/cron/delete.go @@ -38,6 +38,6 @@ func NewDeleteCommand() *cobra.Command { }, } - command.Flags().BoolVar(&all, "all", false, "Delete all workflow templates") + command.Flags().BoolVar(&all, "all", false, "Delete all cron workflows") return command } diff --git a/docs/cli/argo_cron_delete.md b/docs/cli/argo_cron_delete.md index 76a8ef9772ef..ea41fd86c6cc 100644 --- a/docs/cli/argo_cron_delete.md +++ b/docs/cli/argo_cron_delete.md @@ -9,7 +9,7 @@ argo cron delete [CRON_WORKFLOW... | --all] [flags] ### Options ``` - --all Delete all workflow templates + --all Delete all cron workflows -h, --help help for delete ``` From cae69e62b37a6f8256a9cab53d793fc5102ebfe4 Mon Sep 17 00:00:00 2001 From: Tianchu Zhao Date: Wed, 27 Oct 2021 02:34:05 +1100 Subject: [PATCH 33/64] fix: Unit test TestNewOperation order of pipeline execution maybe different to order of submit (#7069) Signed-off-by: Tianchu Zhao --- server/event/dispatch/operation_test.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/server/event/dispatch/operation_test.go b/server/event/dispatch/operation_test.go index 5279ca51d8d0..e6b01d07bbe1 100644 --- a/server/event/dispatch/operation_test.go +++ b/server/event/dispatch/operation_test.go @@ -3,6 +3,7 @@ package dispatch import ( "context" "encoding/json" + "sort" "testing" "github.com/stretchr/testify/assert" @@ -150,16 +151,24 @@ func TestNewOperation(t *testing.T) { assert.NoError(t, err) operation.Dispatch(ctx) - expectedParamValues := []string{"bar", "bar", `{"bar":"baz"}`} + expectedParamValues := []string{ + "bar", + "bar", + `{"bar":"baz"}`, + } + var paramValues []string // assert list, err := client.ArgoprojV1alpha1().Workflows("my-ns").List(ctx, metav1.ListOptions{}) if assert.NoError(t, err) && assert.Len(t, list.Items, 3) { - for i, wf := range list.Items { + for _, wf := range list.Items { assert.Equal(t, "my-instanceid", wf.Labels[common.LabelKeyControllerInstanceID]) assert.Equal(t, "my-sub", wf.Labels[common.LabelKeyCreator]) assert.Contains(t, wf.Labels, common.LabelKeyWorkflowEventBinding) - assert.Equal(t, []wfv1.Parameter{{Name: "my-param", Value: wfv1.AnyStringPtr(expectedParamValues[i])}}, wf.Spec.Arguments.Parameters) + assert.Contains(t, "my-param", wf.Spec.Arguments.Parameters[0].Name) + paramValues = append(paramValues, string(*wf.Spec.Arguments.Parameters[0].Value)) } + sort.Strings(paramValues) + assert.Equal(t, expectedParamValues, paramValues) } assert.Equal(t, "Warning WorkflowEventBindingError failed to dispatch event: failed to evaluate workflow template expression: unexpected token EOF (1:1)", <-recorder.Events) assert.Equal(t, "Warning WorkflowEventBindingError failed to dispatch event: failed to get workflow template: workflowtemplates.argoproj.io \"not-found\" not found", <-recorder.Events) From a0ac28893b63a73f6d875b4087fc04f420595815 Mon Sep 17 00:00:00 2001 From: Ziv Levi Date: Tue, 26 Oct 2021 19:03:38 +0300 Subject: [PATCH 34/64] fix: add outputs.parameters scope to script/containerSet templates. Fixes #6439 (#7045) Signed-off-by: ziv-codefresh --- workflow/validate/validate.go | 1 + workflow/validate/validate_test.go | 128 +++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) diff --git a/workflow/validate/validate.go b/workflow/validate/validate.go index 0a28be565d9c..512ad19a5597 100644 --- a/workflow/validate/validate.go +++ b/workflow/validate/validate.go @@ -904,6 +904,7 @@ func (ctx *templateValidationCtx) addOutputsToScope(tmpl *wfv1.Template, prefix case wfv1.TemplateTypeScript, wfv1.TemplateTypeContainerSet: scope[fmt.Sprintf("%s.outputs.result", prefix)] = true scope[fmt.Sprintf("%s.exitCode", prefix)] = true + scope[fmt.Sprintf("%s.outputs.parameters", prefix)] = true default: scope[fmt.Sprintf("%s.outputs.parameters", prefix)] = true } diff --git a/workflow/validate/validate_test.go b/workflow/validate/validate_test.go index 4f0cea651a74..657a64e47b5a 100644 --- a/workflow/validate/validate_test.go +++ b/workflow/validate/validate_test.go @@ -3006,3 +3006,131 @@ spec: _, err := validate(wf) assert.NoError(t, err) } + +var templateReferenceWorkflowConfigMapRefArgument = ` +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: arguments-parameters-from-configmap- +spec: + entrypoint: whalesay + serviceAccountName: argo + arguments: + parameters: + - name: message + valueFrom: + configMapKeyRef: + name: simple-parameters + key: msg + templates: + - name: whalesay + inputs: + parameters: + - name: message + container: + image: docker/whalesay:latest + command: [cowsay] + args: ["{{inputs.parameters.message}}"] +` + +func TestTemplateReferenceWorkflowConfigMapRefArgument(t *testing.T) { + _, err := validate(templateReferenceWorkflowConfigMapRefArgument) + assert.NoError(t, err) +} + +var stepsOutputParametersForScript = ` +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: parameter-aggregation- +spec: + entrypoint: parameter-aggregation + templates: + - name: parameter-aggregation + steps: + - - name: echo-num + template: echo-num + arguments: + parameters: + - name: num + value: "{{item}}" + withItems: [1, 2, 3, 4] + - - name: echo-num-from-param + template: echo-num + arguments: + parameters: + - name: num + value: "{{item.num}}" + withParam: "{{steps.echo-num.outputs.parameters}}" + + - name: echo-num + inputs: + parameters: + - name: num + script: + image: argoproj/argosay:v1 + command: [sh, -x] + source: | + sleep 1 + echo {{inputs.parameters.num}} > /tmp/num + outputs: + parameters: + - name: num + valueFrom: + path: /tmp/num +` + +func TestStepsOutputParametersForScript(t *testing.T) { + _, err := validate(stepsOutputParametersForScript) + assert.NoError(t, err) +} + +var stepsOutputParametersForContainerSet = ` +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: parameter-aggregation- +spec: + entrypoint: parameter-aggregation + templates: + - name: parameter-aggregation + steps: + - - name: echo-num + template: echo-num + arguments: + parameters: + - name: num + value: "{{item}}" + withItems: [1, 2, 3, 4] + - - name: echo-num-from-param + template: echo-num + arguments: + parameters: + - name: num + value: "{{item.num}}" + withParam: "{{steps.echo-num.outputs.parameters}}" + + - name: echo-num + inputs: + parameters: + - name: num + containerSet: + containers: + - name: main + image: 'docker/whalesay:latest' + command: + - sh + - '-c' + args: + - 'sleep 1; echo {{inputs.parameters.num}} > /tmp/num' + outputs: + parameters: + - name: num + valueFrom: + path: /tmp/num +` + +func TestStepsOutputParametersForContainerSet(t *testing.T) { + _, err := validate(stepsOutputParametersForContainerSet) + assert.NoError(t, err) +} From d802030e799fa9f96671ce0e04a30cc54188acf4 Mon Sep 17 00:00:00 2001 From: Alex Collins Date: Wed, 27 Oct 2021 10:04:24 -0700 Subject: [PATCH 35/64] ci: fix SDK publishing Signed-off-by: Alex Collins --- .github/workflows/sdks.yaml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/.github/workflows/sdks.yaml b/.github/workflows/sdks.yaml index 30f0cdb94ae1..c9653335c2f9 100644 --- a/.github/workflows/sdks.yaml +++ b/.github/workflows/sdks.yaml @@ -3,10 +3,8 @@ on: push: tags: - v* - - 'v3.2.*' - - 'v3.1.*' branches: - - dev-* + - master jobs: sdk: if: github.repository == 'argoproj/argo-workflows' @@ -21,9 +19,3 @@ jobs: - run: make --directory sdks/${{matrix.name}} publish -B env: JAVA_SDK_MAVEN_PASSWORD: ${{ secrets.GITHUB_TOKEN }} - - uses: peter-evans/create-pull-request@v3 - with: - title: 'chore: updated ${{matrix.name}} SDK' - commit-message: 'chore: updated ${{matrix.name}} SDK' - branch: create-pull-request/sdk/${{matrix.name}} - signoff: true From 926108028cea2e0ef305c24c86b9e685a0ac9c5e Mon Sep 17 00:00:00 2001 From: Jonathan Date: Thu, 28 Oct 2021 11:31:31 -0500 Subject: [PATCH 36/64] fix: Format issue on WorkflowEventBinding parameters. Fixes #7042 (#7087) Signed-off-by: Jonathan Robertson --- pkg/apis/workflow/v1alpha1/item.go | 2 +- pkg/apis/workflow/v1alpha1/item_test.go | 1 + server/event/dispatch/operation_test.go | 19 +++++++++++++++++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/pkg/apis/workflow/v1alpha1/item.go b/pkg/apis/workflow/v1alpha1/item.go index a006682828ab..35e53c31fdb2 100644 --- a/pkg/apis/workflow/v1alpha1/item.go +++ b/pkg/apis/workflow/v1alpha1/item.go @@ -72,7 +72,7 @@ func (i *Item) String() string { } func (i Item) Format(s fmt.State, _ rune) { - _, _ = fmt.Fprintf(s, i.String()) //nolint + _, _ = fmt.Fprintf(s, "%s", i.String()) //nolint } func (i Item) MarshalJSON() ([]byte, error) { diff --git a/pkg/apis/workflow/v1alpha1/item_test.go b/pkg/apis/workflow/v1alpha1/item_test.go index a08ce6d7adb3..5b523ec94f11 100644 --- a/pkg/apis/workflow/v1alpha1/item_test.go +++ b/pkg/apis/workflow/v1alpha1/item_test.go @@ -15,6 +15,7 @@ func TestItem(t *testing.T) { "3.141": Number, "true": Bool, "\"hello\"": String, + "\"hell%test%o\"": String, "{\"val\":\"123\"}": Map, "[\"1\",\"2\",\"3\",\"4\",\"5\"]": List, } { diff --git a/server/event/dispatch/operation_test.go b/server/event/dispatch/operation_test.go index e6b01d07bbe1..7e79276cb44c 100644 --- a/server/event/dispatch/operation_test.go +++ b/server/event/dispatch/operation_test.go @@ -52,6 +52,9 @@ func TestNewOperation(t *testing.T) { &wfv1.WorkflowTemplate{ ObjectMeta: metav1.ObjectMeta{Name: "my-wft-3", Namespace: "my-ns"}, }, + &wfv1.WorkflowTemplate{ + ObjectMeta: metav1.ObjectMeta{Name: "my-wft-4", Namespace: "my-ns", Labels: map[string]string{common.LabelKeyControllerInstanceID: "my-instanceid"}}, + }, ) ctx := context.WithValue(context.WithValue(context.Background(), auth.WfKey, client), auth.ClaimsKey, &types.Claims{Claims: jwt.Claims{Subject: "my-sub"}}) recorder := record.NewFakeRecorder(6) @@ -147,11 +150,23 @@ func TestNewOperation(t *testing.T) { }, }, }, - }, "my-ns", "my-discriminator", &wfv1.Item{Value: json.RawMessage(`{"foo": {"bar": "baz"}}`)}) + // test a bind with a payload and fmt expression + { + ObjectMeta: metav1.ObjectMeta{Name: "my-wfeb-8", Namespace: "my-ns"}, + Spec: wfv1.WorkflowEventBindingSpec{ + Event: wfv1.Event{Selector: "true"}, + Submit: &wfv1.Submit{ + WorkflowTemplateRef: wfv1.WorkflowTemplateRef{Name: "my-wft-4"}, + Arguments: &wfv1.Arguments{Parameters: []wfv1.Parameter{{Name: "my-param", ValueFrom: &wfv1.ValueFrom{Event: "payload.formatted"}}}}, + }, + }, + }, + }, "my-ns", "my-discriminator", &wfv1.Item{Value: json.RawMessage(`{"foo": {"bar": "baz"}, "formatted": "My%Test%"}`)}) assert.NoError(t, err) operation.Dispatch(ctx) expectedParamValues := []string{ + `My%Test%`, "bar", "bar", `{"bar":"baz"}`, @@ -159,7 +174,7 @@ func TestNewOperation(t *testing.T) { var paramValues []string // assert list, err := client.ArgoprojV1alpha1().Workflows("my-ns").List(ctx, metav1.ListOptions{}) - if assert.NoError(t, err) && assert.Len(t, list.Items, 3) { + if assert.NoError(t, err) && assert.Len(t, list.Items, 4) { for _, wf := range list.Items { assert.Equal(t, "my-instanceid", wf.Labels[common.LabelKeyControllerInstanceID]) assert.Equal(t, "my-sub", wf.Labels[common.LabelKeyCreator]) From 30e34ada8cab77c56e3917144a29b96fb070a06d Mon Sep 17 00:00:00 2001 From: Alex Collins Date: Thu, 28 Oct 2021 13:02:19 -0700 Subject: [PATCH 37/64] fix: prevent bad commit messages, fix broken builds (#7086) Signed-off-by: Alex Collins --- .github/pull_request_template.md | 22 +++++++++++++++------- .github/workflows/ci-build.yaml | 31 +++++++++++++++++++++++++------ Makefile | 25 ++++++++++++++++++------- docs/releases.md | 9 +++++---- hack/git/hooks/commit-msg | 14 ++++++++++++++ 5 files changed, 77 insertions(+), 24 deletions(-) create mode 100755 hack/git/hooks/commit-msg diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 56e93483c234..0d60bf282af4 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,9 +1,17 @@ -Tips: +Don't bother creating a PR until you've done this: + +* [ ] Run `make pre-commit -B` to fix codegen, lint, and commit message problems. + +Create your PR as a draft. + -* Maybe add you organization to [USERS.md](https://github.com/argoproj/argo-workflows/blob/master/USERS.md). -* Your PR needs to pass the required checks before it can be approved. If the check is not required (e.g. E2E tests) it does not need to pass -* Sign-off your commits to pass the DCO check: `git commit --signoff`. -* Run `make pre-commit -B` to fix codegen or lint problems. +* Your PR needs to pass the required checks before it can be approved. If the check is not required (e.g. E2E tests) it + does not need to pass. +* Once required tests have passed, you can make it "Ready for review". * Say how how you tested your changes. If you changed the UI, attach screenshots. -* If changes were requested, and you've made them, then dismis the review to get it looked at again. -* You can ask for help! + +Tips: + +* If changes were requested, and you've made them, then dismiss the review to get it looked at again. +* Add you organization to [USERS.md](https://github.com/argoproj/argo-workflows/blob/master/USERS.md) if you like. +* You can ask for help! diff --git a/.github/workflows/ci-build.yaml b/.github/workflows/ci-build.yaml index 24937357b033..34645d89b43f 100644 --- a/.github/workflows/ci-build.yaml +++ b/.github/workflows/ci-build.yaml @@ -32,7 +32,9 @@ jobs: - run: make server/static/files.go STATIC_FILES=false - run: go build -v ./... - run: make test STATIC_FILES=false GOTEST='go test -covermode=atomic -coverprofile=coverage.out' + # engineers just ignore this in PRs, so lets not even run it - run: bash <(curl -s https://codecov.io/bash) + if: github.ref == 'refs/heads/master' e2e-tests: name: E2E Tests @@ -91,9 +93,27 @@ jobs: with: path: /home/runner/go/bin key: go-bin-v1-${{ hashFiles('**/go.mod') }} + - name: Cache Docker layers + uses: actions/cache@v2 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + - uses: docker/setup-buildx-action@v1 - run: mkdir -p /tmp/log/argo-e2e + # we never want to pull images by accident on CI after we built them + # so imagePullPolicy=Never + # but, we can pull it if we don't need it + - run: docker pull quay.io/argoproj/argoexec:latest + if: ${{!(matrix.test == 'test-executor' || matrix.test == 'test-functional')}} + - name: make argoexec-image + if: ${{matrix.test == 'test-executor' || matrix.test == 'test-functional'}} + # retry this once, as it can be flakey + run: | + make argoexec-image STATIC_FILES=false || make argoexec-image STATIC_FILES=false + docker image prune -f - name: Install and start K3S - timeout-minutes: 3 run: | curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.21.2+k3s1 INSTALL_K3S_CHANNEL=stable INSTALL_K3S_EXEC=--docker K3S_KUBECONFIG_MODE=644 sh - until kubectl --kubeconfig=/etc/rancher/k3s/k3s.yaml cluster-info ; do sleep 10s ; done @@ -110,21 +130,20 @@ jobs: echo '127.0.0.1 mysql' | sudo tee -a /etc/hosts - run: make install controller cli $(go env GOPATH)/bin/goreman PROFILE=${{matrix.profile}} E2E_EXECUTOR=${{matrix.containerRuntimeExecutor}} AUTH_MODE=client STATIC_FILES=false LOG_LEVEL=info - run: make start PROFILE=${{matrix.profile}} E2E_EXECUTOR=${{matrix.containerRuntimeExecutor}} AUTH_MODE=client STATIC_FILES=false LOG_LEVEL=info UI=false > /tmp/log/argo-e2e/argo.log 2>&1 & - timeout-minutes: 4 - - name: make argoexec-image - run: make argoexec-image STATIC_FILES=false - run: make wait timeout-minutes: 4 - run: make ${{matrix.test}} E2E_TIMEOUT=1m STATIC_FILES=false - name: cat argo.log if: ${{ failure() }} run: cat /tmp/log/argo-e2e/argo.log - + - name: MinIO logs + if: ${{ failure() }} + run: kubectl -n argo logs deploy/minio codegen: name: Codegen runs-on: ubuntu-latest needs: [ tests ] - timeout-minutes: 9 + timeout-minutes: 15 env: GOPATH: /home/runner/go PROTOC_ZIP: protoc-3.11.1-linux-x86_64.zip diff --git a/Makefile b/Makefile index f7821ab4db42..4010229cc676 100644 --- a/Makefile +++ b/Makefile @@ -219,7 +219,13 @@ argoexec-image: %-image: [ ! -e dist/$* ] || mv dist/$* . - docker buildx build -t $(IMAGE_NAMESPACE)/$*:$(VERSION) --target $* --output=type=docker . + docker buildx install + docker build \ + -t $(IMAGE_NAMESPACE)/$*:$(VERSION) \ + --target $* \ + --cache-from "type=local,src=/tmp/.buildx-cache" \ + --cache-to "type=local,dest=/tmp/.buildx-cache" \ + --output=type=docker . [ ! -e $* ] || mv $* dist/ docker run --rm -t $(IMAGE_NAMESPACE)/$*:$(VERSION) version if [ $(K3D) = true ]; then k3d image import $(IMAGE_NAMESPACE)/$*:$(VERSION); fi @@ -396,7 +402,7 @@ test: server/static/files.go dist/argosay env KUBECONFIG=/dev/null $(GOTEST) ./... .PHONY: install -install: +install: githooks kubectl get ns $(KUBE_NAMESPACE) || kubectl create ns $(KUBE_NAMESPACE) kubectl config set-context --current --namespace=$(KUBE_NAMESPACE) @echo "installing PROFILE=$(PROFILE), E2E_EXECUTOR=$(E2E_EXECUTOR)" @@ -571,14 +577,19 @@ validate-examples: api/jsonschema/schema.json # pre-push +<<<<<<< HEAD .PHONY: pre-commit pre-commit: codegen lint test start +======= +.git/hooks/commit-msg: hack/git/hooks/commit-msg + cp -v hack/git/hooks/commit-msg .git/hooks/commit-msg +>>>>>>> 0fb104481... build: prevent bad commit messages, fix broken builds (#7086) -ifeq ($(GIT_BRANCH),master) -LOG_OPTS := '-n10' -else -LOG_OPTS := 'origin/master..' -endif +.PHONY: githooks +githooks: .git/hooks/commit-msg + +.PHONY: pre-commit +pre-commit: githooks codegen lint release-notes: /dev/null version=$(VERSION) envsubst < hack/release-notes.md > release-notes diff --git a/docs/releases.md b/docs/releases.md index 479f0c745643..3c3ec7b00e8d 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -17,12 +17,13 @@ Both the `argo-server` and `argocli` should be the same version as the controlle # Release Cycle +For **stable**, use the latest patch version. For **unstable**, we build and tag `latest` images for every commit to master. -New major versions are released roughly every 3 months. Release candidates for each major release are typically available -for 6 weeks before the release becomes generally available. +New minor versions are released roughly every 3 months. Release candidates for each major release are typically available +for 4-6 weeks before the release becomes generally available. -Otherwise, we typically release once a week: +Otherwise, we typically release weekly: -* Patch fixes for the current stable version. These are tagged `stable`. +* Patch fixes for the current stable version. * The next release candidate, if we are currently in a release-cycle. diff --git a/hack/git/hooks/commit-msg b/hack/git/hooks/commit-msg new file mode 100755 index 000000000000..5ea0ef6e5b4d --- /dev/null +++ b/hack/git/hooks/commit-msg @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu + +grep -q 'Signed-off-by: ' "$1" || { + echo >&2 'Commits must be signed-off: https://probot.github.io/apps/dco/' + exit 1 +} + +grep -qE '^(?:feat|fix|docs|style|refactor|perf|test|chore)\(?(?:\w+|\s|\-|_)?\)?:\s\w+' "$1" || grep -q 'Merge' "$1" || { + echo >&2 'Commit message must be semantic: https://github.com/zeke/semantic-pull-requests' + exit 1 +} + +echo 'Your commit message is acceptable' \ No newline at end of file From f5f6899f531126a18f5f42201156c995630fdf1b Mon Sep 17 00:00:00 2001 From: "J.P. Zivalich" Date: Fri, 29 Oct 2021 11:09:19 -0400 Subject: [PATCH 38/64] fix: Add pod name format annotation. Fixes #6962 and #6989 (#6982) --- .../archived-workflow-details.tsx | 12 +++-- ui/src/app/shared/annotations.ts | 1 + ui/src/app/shared/pod-name.test.ts | 9 +++- ui/src/app/shared/pod-name.ts | 26 +++++++++- .../app/shared/services/workflows-service.ts | 12 ++--- .../workflow-details/workflow-details.tsx | 11 +++- .../workflow-logs-viewer.tsx | 16 ++++-- .../workflow-node-info/workflow-node-info.tsx | 12 ++++- workflow/common/common.go | 3 ++ workflow/controller/operator.go | 15 ++++++ workflow/controller/operator_test.go | 30 ++++++++++- workflow/util/pod_name.go | 52 +++++++++++++++---- 12 files changed, 167 insertions(+), 32 deletions(-) create mode 100644 ui/src/app/shared/annotations.ts diff --git a/ui/src/app/archived-workflows/components/archived-workflow-details/archived-workflow-details.tsx b/ui/src/app/archived-workflows/components/archived-workflow-details/archived-workflow-details.tsx index 1d27137b011e..f357ecda9f88 100644 --- a/ui/src/app/archived-workflows/components/archived-workflow-details/archived-workflow-details.tsx +++ b/ui/src/app/archived-workflows/components/archived-workflow-details/archived-workflow-details.tsx @@ -12,7 +12,8 @@ import {ResourceEditor} from '../../../shared/components/resource-editor/resourc import {services} from '../../../shared/services'; import {WorkflowArtifacts} from '../../../workflows/components/workflow-artifacts'; -import {getPodName} from '../../../shared/pod-name'; +import {ANNOTATION_KEY_POD_NAME_VERSION} from '../../../shared/annotations'; +import {getPodName, getTemplateNameFromNode} from '../../../shared/pod-name'; import {WorkflowResourcePanel} from '../../../workflows/components/workflow-details/workflow-resource-panel'; import {WorkflowLogsViewer} from '../../../workflows/components/workflow-logs-viewer/workflow-logs-viewer'; import {WorkflowNodeInfo} from '../../../workflows/components/workflow-node-info/workflow-node-info'; @@ -252,8 +253,13 @@ export class ArchivedWorkflowDetails extends BasePage, private get podName() { if (this.nodeId && this.state.workflow) { const workflowName = this.state.workflow.metadata.name; - const {name, templateName} = this.node; - return getPodName(workflowName, name, templateName, this.nodeId); + let annotations: {[name: string]: string} = {}; + if (typeof this.state.workflow.metadata.annotations !== 'undefined') { + annotations = this.state.workflow.metadata.annotations; + } + const version = annotations[ANNOTATION_KEY_POD_NAME_VERSION]; + const templateName = getTemplateNameFromNode(this.node); + return getPodName(workflowName, this.node.name, templateName, this.nodeId, version); } } diff --git a/ui/src/app/shared/annotations.ts b/ui/src/app/shared/annotations.ts new file mode 100644 index 000000000000..95e7e033000c --- /dev/null +++ b/ui/src/app/shared/annotations.ts @@ -0,0 +1 @@ +export const ANNOTATION_KEY_POD_NAME_VERSION = 'workflows.argoproj.io/pod-name-format'; diff --git a/ui/src/app/shared/pod-name.test.ts b/ui/src/app/shared/pod-name.test.ts index b9dd4ae19468..6aed683c5f44 100644 --- a/ui/src/app/shared/pod-name.test.ts +++ b/ui/src/app/shared/pod-name.test.ts @@ -1,4 +1,4 @@ -import {createFNVHash, ensurePodNamePrefixLength, getPodName, k8sNamingHashLength, maxK8sResourceNameLength} from './pod-name'; +import {createFNVHash, ensurePodNamePrefixLength, getPodName, k8sNamingHashLength, maxK8sResourceNameLength, POD_NAME_V1, POD_NAME_V2} from './pod-name'; describe('pod names', () => { test('createFNVHash', () => { @@ -27,6 +27,11 @@ describe('pod names', () => { }); test('getPodName', () => { - expect(getPodName(shortWfName, nodeName, shortTemplateName, nodeID)).toEqual(nodeID); + expect(getPodName(shortWfName, nodeName, shortTemplateName, nodeID, POD_NAME_V2)).toEqual('wfname-templatename-1454367246'); + expect(getPodName(shortWfName, nodeName, shortTemplateName, nodeID, POD_NAME_V1)).toEqual(nodeID); + expect(getPodName(shortWfName, nodeName, shortTemplateName, nodeID, '')).toEqual(nodeID); + + const name = getPodName(longWfName, nodeName, longTemplateName, nodeID, POD_NAME_V2); + expect(name.length).toEqual(maxK8sResourceNameLength); }); }); diff --git a/ui/src/app/shared/pod-name.ts b/ui/src/app/shared/pod-name.ts index d10dd54f8bdd..09dd2f94fda9 100644 --- a/ui/src/app/shared/pod-name.ts +++ b/ui/src/app/shared/pod-name.ts @@ -1,8 +1,24 @@ +import {NodeStatus} from '../../models'; + +export const POD_NAME_V1 = 'v1'; +export const POD_NAME_V2 = 'v2'; + export const maxK8sResourceNameLength = 253; export const k8sNamingHashLength = 10; // getPodName returns a deterministic pod name -export const getPodName = (workflowName: string, nodeName: string, templateName: string, nodeID: string): string => { +export const getPodName = (workflowName: string, nodeName: string, templateName: string, nodeID: string, version: string): string => { + if (version === POD_NAME_V2) { + if (workflowName === nodeName) { + return workflowName; + } + + const prefix = ensurePodNamePrefixLength(`${workflowName}-${templateName}`); + + const hash = createFNVHash(nodeName); + return `${prefix}-${hash}`; + } + return nodeID; }; @@ -29,3 +45,11 @@ export const createFNVHash = (input: string): number => { return hashint >>> 0; }; + +export const getTemplateNameFromNode = (node: NodeStatus): string => { + if (node.templateName && node.templateName !== '') { + return node.templateName; + } + + return node.templateRef.template; +}; diff --git a/ui/src/app/shared/services/workflows-service.ts b/ui/src/app/shared/services/workflows-service.ts index e2a02e77201e..f1aaf6d2cd06 100644 --- a/ui/src/app/shared/services/workflows-service.ts +++ b/ui/src/app/shared/services/workflows-service.ts @@ -135,10 +135,10 @@ export class WorkflowsService { .then(res => res.body as Workflow); } - public getContainerLogsFromCluster(workflow: Workflow, nodeId: string, container: string, grep: string): Observable { + public getContainerLogsFromCluster(workflow: Workflow, podName: string, container: string, grep: string): Observable { const namespace = workflow.metadata.namespace; const name = workflow.metadata.name; - const podLogsURL = `api/v1/workflows/${namespace}/${name}/log?logOptions.container=${container}&grep=${grep}&logOptions.follow=true${nodeId ? `&podName=${nodeId}` : ''}`; + const podLogsURL = `api/v1/workflows/${namespace}/${name}/log?logOptions.container=${container}&grep=${grep}&logOptions.follow=true${podName ? `&podName=${podName}` : ''}`; return requests .loadEventSource(podLogsURL) .filter(line => !!line) @@ -149,9 +149,9 @@ export class WorkflowsService { // that the connection to the server was interrupted while the node is still pending or running, this is not // correct since we actually want the EventSource to re-connect and continue streaming logs. In the event // that the pod has completed, then we want to allow the unsubscribe to happen since no additional logs exist. - return Observable.fromPromise(this.isWorkflowNodePendingOrRunning(workflow, nodeId)).switchMap(isPendingOrRunning => { + return Observable.fromPromise(this.isWorkflowNodePendingOrRunning(workflow, podName)).switchMap(isPendingOrRunning => { if (isPendingOrRunning) { - return this.getContainerLogsFromCluster(workflow, nodeId, container, grep); + return this.getContainerLogsFromCluster(workflow, podName, container, grep); } // If our workflow is completed, then simply complete the Observable since nothing else @@ -186,7 +186,7 @@ export class WorkflowsService { .filter(x => !!x.content.match(grep)); } - public getContainerLogs(workflow: Workflow, nodeId: string, container: string, grep: string, archived: boolean): Observable { + public getContainerLogs(workflow: Workflow, podName: string, nodeId: string, container: string, grep: string, archived: boolean): Observable { const getLogsFromArtifact = () => this.getContainerLogsFromArtifact(workflow, nodeId, container, grep, archived); // If our workflow is archived, don't even bother inspecting the cluster for logs since it's likely @@ -199,7 +199,7 @@ export class WorkflowsService { if (!isPendingOrRunning && this.hasArtifactLogs(workflow, nodeId, container) && container === 'main') { return getLogsFromArtifact(); } - return this.getContainerLogsFromCluster(workflow, nodeId, container, grep).catch(getLogsFromArtifact); + return this.getContainerLogsFromCluster(workflow, podName, container, grep).catch(getLogsFromArtifact); }); } diff --git a/ui/src/app/workflows/components/workflow-details/workflow-details.tsx b/ui/src/app/workflows/components/workflow-details/workflow-details.tsx index f1858156509e..8a4a978b96ac 100644 --- a/ui/src/app/workflows/components/workflow-details/workflow-details.tsx +++ b/ui/src/app/workflows/components/workflow-details/workflow-details.tsx @@ -4,6 +4,7 @@ import * as React from 'react'; import {useContext, useEffect, useState} from 'react'; import {RouteComponentProps} from 'react-router'; import {execSpec, Link, NodeStatus, Workflow} from '../../../../models'; +import {ANNOTATION_KEY_POD_NAME_VERSION} from '../../../shared/annotations'; import {uiUrl} from '../../../shared/base'; import {CostOptimisationNudge} from '../../../shared/components/cost-optimisation-nudge'; import {ErrorNotice} from '../../../shared/components/error-notice'; @@ -13,7 +14,7 @@ import {SecurityNudge} from '../../../shared/components/security-nudge'; import {hasWarningConditionBadge} from '../../../shared/conditions-panel'; import {Context} from '../../../shared/context'; import {historyUrl} from '../../../shared/history'; -import {getPodName} from '../../../shared/pod-name'; +import {getPodName, getTemplateNameFromNode} from '../../../shared/pod-name'; import {RetryWatch} from '../../../shared/retry-watch'; import {services} from '../../../shared/services'; import {useQueryParams} from '../../../shared/use-query-params'; @@ -226,7 +227,13 @@ export const WorkflowDetails = ({history, location, match}: RouteComponentProps< }; const ensurePodName = (wf: Workflow, node: NodeStatus, nodeID: string): string => { if (workflow && node) { - return getPodName(wf.metadata.name, node.name, node.templateName, node.id); + let annotations: {[name: string]: string} = {}; + if (typeof workflow.metadata.annotations !== 'undefined') { + annotations = workflow.metadata.annotations; + } + const version = annotations[ANNOTATION_KEY_POD_NAME_VERSION]; + const templateName = getTemplateNameFromNode(node); + return getPodName(wf.metadata.name, node.name, templateName, node.id, version); } return nodeID; diff --git a/ui/src/app/workflows/components/workflow-logs-viewer/workflow-logs-viewer.tsx b/ui/src/app/workflows/components/workflow-logs-viewer/workflow-logs-viewer.tsx index b8a50e30366e..71d9d10fd20b 100644 --- a/ui/src/app/workflows/components/workflow-logs-viewer/workflow-logs-viewer.tsx +++ b/ui/src/app/workflows/components/workflow-logs-viewer/workflow-logs-viewer.tsx @@ -5,10 +5,11 @@ import {Autocomplete} from 'argo-ui'; import {Observable} from 'rxjs'; import * as models from '../../../../models'; import {execSpec} from '../../../../models'; +import {ANNOTATION_KEY_POD_NAME_VERSION} from '../../../shared/annotations'; import {ErrorNotice} from '../../../shared/components/error-notice'; import {InfoIcon, WarningIcon} from '../../../shared/components/fa-icons'; import {Links} from '../../../shared/components/links'; -import {getPodName} from '../../../shared/pod-name'; +import {getPodName, getTemplateNameFromNode} from '../../../shared/pod-name'; import {services} from '../../../shared/services'; import {FullHeightLogsViewer} from './full-height-logs-viewer'; @@ -36,7 +37,7 @@ export const WorkflowLogsViewer = ({workflow, nodeId, initialPodName, container, setError(null); setLoaded(false); const source = services.workflows - .getContainerLogs(workflow, podName, selectedContainer, grep, archived) + .getContainerLogs(workflow, podName, nodeId, selectedContainer, grep, archived) .map(e => (!podName ? e.podName + ': ' : '') + e.content + '\n') // this next line highlights the search term in bold with a yellow background, white text .map(x => { @@ -63,12 +64,19 @@ export const WorkflowLogsViewer = ({workflow, nodeId, initialPodName, container, return () => clearTimeout(x); }, [filter]); + let annotations: {[name: string]: string} = {}; + if (typeof workflow.metadata.annotations !== 'undefined') { + annotations = workflow.metadata.annotations; + } + const podNameVersion = annotations[ANNOTATION_KEY_POD_NAME_VERSION]; + const podNames = [{value: '', label: 'All'}].concat( Object.values(workflow.status.nodes || {}) .filter(x => x.type === 'Pod') .map(targetNode => { - const {name, id, templateName, displayName} = targetNode; - const targetPodName = getPodName(workflow.metadata.name, name, templateName, id); + const {name, id, displayName} = targetNode; + const templateName = getTemplateNameFromNode(targetNode); + const targetPodName = getPodName(workflow.metadata.name, name, templateName, id, podNameVersion); return {value: targetPodName, label: (displayName || name) + ' (' + targetPodName + ')'}; }) ); diff --git a/ui/src/app/workflows/components/workflow-node-info/workflow-node-info.tsx b/ui/src/app/workflows/components/workflow-node-info/workflow-node-info.tsx index 48be1b314a43..7f4474d12769 100644 --- a/ui/src/app/workflows/components/workflow-node-info/workflow-node-info.tsx +++ b/ui/src/app/workflows/components/workflow-node-info/workflow-node-info.tsx @@ -4,6 +4,7 @@ import * as React from 'react'; import * as models from '../../../../models'; import {Artifact, NodeStatus, Workflow} from '../../../../models'; +import {ANNOTATION_KEY_POD_NAME_VERSION} from '../../../shared/annotations'; import {Button} from '../../../shared/components/button'; import {ClipboardText} from '../../../shared/components/clipboard-text'; import {DropDownButton} from '../../../shared/components/drop-down-button'; @@ -12,7 +13,7 @@ import {InlineTable} from '../../../shared/components/inline-table/inline-table' import {Links} from '../../../shared/components/links'; import {Phase} from '../../../shared/components/phase'; import {Timestamp} from '../../../shared/components/timestamp'; -import {getPodName} from '../../../shared/pod-name'; +import {getPodName, getTemplateNameFromNode} from '../../../shared/pod-name'; import {ResourcesDuration} from '../../../shared/resources-duration'; import {services} from '../../../shared/services'; import {getResolvedTemplates} from '../../../shared/template-resolution'; @@ -81,7 +82,14 @@ const AttributeRows = (props: {attributes: {title: string; value: any}[]}) => ( const WorkflowNodeSummary = (props: Props) => { const {workflow, node} = props; - const podName = getPodName(workflow.metadata.name, node.name, node.templateName, node.id); + let annotations: {[name: string]: string} = {}; + if (typeof workflow.metadata.annotations !== 'undefined') { + annotations = workflow.metadata.annotations; + } + const version = annotations[ANNOTATION_KEY_POD_NAME_VERSION]; + const templateName = getTemplateNameFromNode(node); + + const podName = getPodName(workflow.metadata.name, node.name, templateName, node.id, version); const attributes = [ {title: 'NAME', value: }, diff --git a/workflow/common/common.go b/workflow/common/common.go index 1b12141a7498..e006830cc5ba 100644 --- a/workflow/common/common.go +++ b/workflow/common/common.go @@ -39,6 +39,9 @@ const ( // AnnotationKeyWorkflowUID is the uid of the workflow AnnotationKeyWorkflowUID = workflow.WorkflowFullName + "/workflow-uid" + // AnnotationKeyPodNameVersion stores the pod naming convention version + AnnotationKeyPodNameVersion = workflow.WorkflowFullName + "/pod-name-format" + // LabelKeyControllerInstanceID is the label the controller will carry forward to workflows/pod labels // for the purposes of workflow segregation LabelKeyControllerInstanceID = workflow.WorkflowFullName + "/controller-instanceid" diff --git a/workflow/controller/operator.go b/workflow/controller/operator.go index f559dd5984fc..bb1892d80aa3 100644 --- a/workflow/controller/operator.go +++ b/workflow/controller/operator.go @@ -142,6 +142,7 @@ func newWorkflowOperationCtx(wf *wfv1.Workflow, wfc *WorkflowController) *wfOper // You can use DeepCopy() to make a deep copy of original object and modify this copy // Or create a copy manually for better performance wfCopy := wf.DeepCopyObject().(*wfv1.Workflow) + woc := wfOperationCtx{ wf: wfCopy, orig: wf, @@ -263,6 +264,8 @@ func (woc *wfOperationCtx) operate(ctx context.Context) { if woc.wf.Status.Phase == wfv1.WorkflowUnknown { woc.markWorkflowRunning(ctx) + setWfPodNamesAnnotation(woc.wf) + err := woc.createPDBResource(ctx) if err != nil { msg := fmt.Sprintf("Unable to create PDB resource for workflow, %s error: %s", woc.wf.Name, err) @@ -3532,3 +3535,15 @@ func (woc *wfOperationCtx) substituteGlobalVariables() error { } return nil } + +// setWfPodNamesAnnotation sets an annotation on a workflow with the pod naming +// convention version +func setWfPodNamesAnnotation(wf *wfv1.Workflow) { + podNameVersion := wfutil.GetPodNameVersion() + + if wf.Annotations == nil { + wf.Annotations = map[string]string{} + } + + wf.Annotations[common.AnnotationKeyPodNameVersion] = podNameVersion.String() +} diff --git a/workflow/controller/operator_test.go b/workflow/controller/operator_test.go index c5bbdfd73796..90401ee4028a 100644 --- a/workflow/controller/operator_test.go +++ b/workflow/controller/operator_test.go @@ -2798,7 +2798,7 @@ func TestResolvePodNameInRetries(t *testing.T) { {"v2", "output-value-placeholders-wf-tell-pod-name-3033990984"}, } for _, tt := range tests { - os.Setenv("POD_NAMES", tt.podNameVersion) + _ = os.Setenv("POD_NAMES", tt.podNameVersion) ctx := context.Background() wf := wfv1.MustUnmarshalWorkflow(podNameInRetries) woc := newWoc(*wf) @@ -7618,3 +7618,31 @@ func TestExitHandlerWithRetryNodeParam(t *testing.T) { onExitNode := woc.wf.GetNodeByName("exit-handler-with-param-xbh52[0].step-1.onExit") assert.Equal(t, "hello world", onExitNode.Inputs.Parameters[0].Value.String()) } + +func TestSetWFPodNamesAnnotation(t *testing.T) { + defer func() { + _ = os.Unsetenv("POD_NAMES") + }() + + tests := []struct { + podNameVersion string + }{ + {"v1"}, + {"v2"}, + } + + for _, tt := range tests { + _ = os.Setenv("POD_NAMES", tt.podNameVersion) + + wf := wfv1.MustUnmarshalWorkflow(exitHandlerWithRetryNodeParam) + cancel, controller := newController(wf) + defer cancel() + + ctx := context.Background() + woc := newWorkflowOperationCtx(wf, controller) + + woc.operate(ctx) + annotations := woc.wf.ObjectMeta.GetAnnotations() + assert.Equal(t, annotations[common.AnnotationKeyPodNameVersion], tt.podNameVersion) + } +} diff --git a/workflow/util/pod_name.go b/workflow/util/pod_name.go index b993332dd8ac..cac26c5433f7 100644 --- a/workflow/util/pod_name.go +++ b/workflow/util/pod_name.go @@ -11,22 +11,52 @@ const ( k8sNamingHashLength = 10 ) +// PodNameVersion stores which type of pod names should be used. +// v1 represents the node id. +// v2 is the combination of a node id and template name. +type PodNameVersion string + +const ( + // PodNameV1 is the v1 name that uses node ids for pod names + PodNameV1 PodNameVersion = "v1" + // PodNameV2 is the v2 name that uses node id combined with + // the template name + PodNameV2 PodNameVersion = "v2" +) + +// String stringifies the pod name version +func (v PodNameVersion) String() string { + return string(v) +} + +// GetPodNameVersion returns the pod name version to be used +func GetPodNameVersion() PodNameVersion { + switch os.Getenv("POD_NAMES") { + case "v2": + return PodNameV2 + case "v1": + return PodNameV1 + default: + return PodNameV1 + } +} + // PodName return a deterministic pod name func PodName(workflowName, nodeName, templateName, nodeID string) string { - if os.Getenv("POD_NAMES") == "v2" { - if workflowName == nodeName { - return workflowName - } - - prefix := fmt.Sprintf("%s-%s", workflowName, templateName) - prefix = ensurePodNamePrefixLength(prefix) + if GetPodNameVersion() == PodNameV1 { + return nodeID + } - h := fnv.New32a() - _, _ = h.Write([]byte(nodeName)) - return fmt.Sprintf("%s-%v", prefix, h.Sum32()) + if workflowName == nodeName { + return workflowName } - return nodeID + prefix := fmt.Sprintf("%s-%s", workflowName, templateName) + prefix = ensurePodNamePrefixLength(prefix) + + h := fnv.New32a() + _, _ = h.Write([]byte(nodeName)) + return fmt.Sprintf("%s-%v", prefix, h.Sum32()) } func ensurePodNamePrefixLength(prefix string) string { From 03a13148a363bbdaa06e69715e268db644179eab Mon Sep 17 00:00:00 2001 From: Sebastiaan Tammer Date: Mon, 1 Nov 2021 16:34:55 +0100 Subject: [PATCH 39/64] docs: fixed a typo in security.md (#7117) Signed-off-by: Sebastiaan Tammer --- docs/security.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/security.md b/docs/security.md index b132eaa53fb4..44f88d57ecb2 100644 --- a/docs/security.md +++ b/docs/security.md @@ -75,7 +75,7 @@ Argo Workflows requires various levels of network access depending on configurat The argo server is commonly exposed to end-users to provide users with a user interface for visualizing and managing their workflows. It must also be exposed if leveraging [webhooks](webhooks.md) to trigger workflows. Both of these use cases require that the argo-server Service to be exposed for ingress traffic (e.g. with an Ingress object or load balancer). Note that the Argo UI is also available to be accessed by running the server locally (i.e. `argo server`) using local kubeconfig credentials, and visiting the UI over https://localhost:2746. -The argo server additionally has a feature to allow downloading of artifacts through the user interface. This feature requires that the argo-server be given egress access to the underlying artifact provider (e.g. S3, GCS, MinIO, Arfactory) in order to download and stream the artifact. +The argo server additionally has a feature to allow downloading of artifacts through the user interface. This feature requires that the argo-server be given egress access to the underlying artifact provider (e.g. S3, GCS, MinIO, Artifactory) in order to download and stream the artifact. ### Workflow Controller From 49b3f0cb2733dec438d8340f439467b7661b8bc2 Mon Sep 17 00:00:00 2001 From: Tianchu Zhao Date: Wed, 3 Nov 2021 10:09:57 +1100 Subject: [PATCH 40/64] fix(controller): default volume/mount to emissary (#7125) Signed-off-by: Tianchu Zhao --- .../controller/container_set_template_test.go | 15 ++++----------- workflow/controller/workflowpod.go | 8 ++++---- workflow/controller/workflowpod_test.go | 2 ++ workflow/validate/validate_test.go | 4 ++-- 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/workflow/controller/container_set_template_test.go b/workflow/controller/container_set_template_test.go index 9493e4083cbf..46042a1bc4df 100644 --- a/workflow/controller/container_set_template_test.go +++ b/workflow/controller/container_set_template_test.go @@ -42,9 +42,8 @@ spec: pod, err := getPod(woc, "pod") assert.NoError(t, err) - socket := corev1.HostPathSocket assert.ElementsMatch(t, []corev1.Volume{ - {Name: "docker-sock", VolumeSource: corev1.VolumeSource{HostPath: &corev1.HostPathVolumeSource{Path: "/var/run/docker.sock", Type: &socket}}}, + {Name: "var-run-argo", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, {Name: "workspace", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, }, pod.Spec.Volumes) @@ -54,9 +53,7 @@ spec: for _, c := range pod.Spec.Containers { switch c.Name { case common.WaitContainerName: - assert.ElementsMatch(t, []corev1.VolumeMount{ - {Name: "docker-sock", MountPath: "/var/run/docker.sock", ReadOnly: true}, - }, c.VolumeMounts) + assert.ElementsMatch(t, []corev1.VolumeMount{}, c.VolumeMounts) case "ctr-0": assert.ElementsMatch(t, []corev1.VolumeMount{ {Name: "workspace", MountPath: "/workspace"}, @@ -108,9 +105,8 @@ spec: pod, err := getPod(woc, "pod") assert.NoError(t, err) - socket := corev1.HostPathSocket assert.ElementsMatch(t, []corev1.Volume{ - {Name: "docker-sock", VolumeSource: corev1.VolumeSource{HostPath: &corev1.HostPathVolumeSource{Path: "/var/run/docker.sock", Type: &socket}}}, + {Name: "var-run-argo", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, {Name: "workspace", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, {Name: "input-artifacts", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, }, pod.Spec.Volumes) @@ -128,7 +124,6 @@ spec: switch c.Name { case common.WaitContainerName: assert.ElementsMatch(t, []corev1.VolumeMount{ - {Name: "docker-sock", MountPath: "/var/run/docker.sock", ReadOnly: true}, {Name: "workspace", MountPath: "/mainctrfs/workspace"}, {Name: "input-artifacts", MountPath: "/mainctrfs/in/in-0", SubPath: "in-0"}, }, c.VolumeMounts) @@ -184,9 +179,8 @@ spec: pod, err := getPod(woc, "pod") assert.NoError(t, err) - socket := corev1.HostPathSocket assert.ElementsMatch(t, []corev1.Volume{ - {Name: "docker-sock", VolumeSource: corev1.VolumeSource{HostPath: &corev1.HostPathVolumeSource{Path: "/var/run/docker.sock", Type: &socket}}}, + {Name: "var-run-argo", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, {Name: "workspace", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, }, pod.Spec.Volumes) @@ -197,7 +191,6 @@ spec: switch c.Name { case common.WaitContainerName: assert.ElementsMatch(t, []corev1.VolumeMount{ - {Name: "docker-sock", MountPath: "/var/run/docker.sock", ReadOnly: true}, {Name: "workspace", MountPath: "/mainctrfs/workspace"}, }, c.VolumeMounts) case "main": diff --git a/workflow/controller/workflowpod.go b/workflow/controller/workflowpod.go index 112831a79d5d..08b6eedeff11 100644 --- a/workflow/controller/workflowpod.go +++ b/workflow/controller/workflowpod.go @@ -535,7 +535,7 @@ func (woc *wfOperationCtx) newWaitContainer(tmpl *wfv1.Template) *apiv1.Containe // in order to SIGTERM/SIGKILL the pid ctr.SecurityContext.Privileged = pointer.BoolPtr(true) } - case "", common.ContainerRuntimeExecutorDocker: + case common.ContainerRuntimeExecutorDocker: ctr.VolumeMounts = append(ctr.VolumeMounts, woc.getVolumeMountDockerSock(tmpl)) } return ctr @@ -638,10 +638,10 @@ func (woc *wfOperationCtx) createVolumes(tmpl *wfv1.Template) []apiv1.Volume { } switch woc.getContainerRuntimeExecutor() { case common.ContainerRuntimeExecutorKubelet, common.ContainerRuntimeExecutorK8sAPI, common.ContainerRuntimeExecutorPNS: - case common.ContainerRuntimeExecutorEmissary: - volumes = append(volumes, volumeVarArgo) - default: + case common.ContainerRuntimeExecutorDocker: volumes = append(volumes, woc.getVolumeDockerSock(tmpl)) + default: + volumes = append(volumes, volumeVarArgo) } volumes = append(volumes, tmpl.Volumes...) return volumes diff --git a/workflow/controller/workflowpod_test.go b/workflow/controller/workflowpod_test.go index a2ac1d008f24..c6a0c05b1e8a 100644 --- a/workflow/controller/workflowpod_test.go +++ b/workflow/controller/workflowpod_test.go @@ -1526,6 +1526,7 @@ spec: func TestHybridWfVolumesWindows(t *testing.T) { wf := wfv1.MustUnmarshalWorkflow(helloWindowsWf) woc := newWoc(*wf) + woc.controller.Config.ContainerRuntimeExecutor = common.ContainerRuntimeExecutorDocker ctx := context.Background() mainCtr := woc.execWf.Spec.Templates[0].Container @@ -1586,6 +1587,7 @@ func TestWindowsUNCPathsAreRemoved(t *testing.T) { func TestHybridWfVolumesLinux(t *testing.T) { wf := wfv1.MustUnmarshalWorkflow(helloLinuxWf) woc := newWoc(*wf) + woc.controller.Config.ContainerRuntimeExecutor = common.ContainerRuntimeExecutorDocker ctx := context.Background() mainCtr := woc.execWf.Spec.Templates[0].Container diff --git a/workflow/validate/validate_test.go b/workflow/validate/validate_test.go index 657a64e47b5a..4486bc2c0aa7 100644 --- a/workflow/validate/validate_test.go +++ b/workflow/validate/validate_test.go @@ -1626,7 +1626,7 @@ func TestBaseImageOutputVerify(t *testing.T) { wfNonPathOutputParam := unmarshalWf(nonPathOutputParameter) var err error - for _, executor := range []string{common.ContainerRuntimeExecutorK8sAPI, common.ContainerRuntimeExecutorKubelet, common.ContainerRuntimeExecutorPNS, common.ContainerRuntimeExecutorDocker, ""} { + for _, executor := range []string{common.ContainerRuntimeExecutorK8sAPI, common.ContainerRuntimeExecutorKubelet, common.ContainerRuntimeExecutorPNS, common.ContainerRuntimeExecutorDocker, common.ContainerRuntimeExecutorDocker, common.ContainerRuntimeExecutorEmissary, ""} { switch executor { case common.ContainerRuntimeExecutorK8sAPI, common.ContainerRuntimeExecutorKubelet: _, err = ValidateWorkflow(wftmplGetter, cwftmplGetter, wfBaseOutArt, ValidateOpts{ContainerRuntimeExecutor: executor}) @@ -1644,7 +1644,7 @@ func TestBaseImageOutputVerify(t *testing.T) { assert.NoError(t, err) _, err = ValidateWorkflow(wftmplGetter, cwftmplGetter, wfBaseWithEmptyDirOutArt, ValidateOpts{ContainerRuntimeExecutor: executor}) assert.Error(t, err) - case common.ContainerRuntimeExecutorDocker, "": + case common.ContainerRuntimeExecutorDocker, common.ContainerRuntimeExecutorEmissary, "": _, err = ValidateWorkflow(wftmplGetter, cwftmplGetter, wfBaseOutArt, ValidateOpts{ContainerRuntimeExecutor: executor}) assert.NoError(t, err) _, err = ValidateWorkflow(wftmplGetter, cwftmplGetter, wfBaseOutParam, ValidateOpts{ContainerRuntimeExecutor: executor}) From 274c5f990dd16b8f2523706549b07c40d60a3fab Mon Sep 17 00:00:00 2001 From: Simon Behar Date: Wed, 3 Nov 2021 13:56:07 -0400 Subject: [PATCH 41/64] fix: Reorder CI checks so required checks run first (#7142) Signed-off-by: Simon Behar --- .github/workflows/ci-build.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-build.yaml b/.github/workflows/ci-build.yaml index 34645d89b43f..47ae79c79cfa 100644 --- a/.github/workflows/ci-build.yaml +++ b/.github/workflows/ci-build.yaml @@ -56,12 +56,15 @@ jobs: containerRuntimeExecutor: emissary profile: minimal - test: test-executor - containerRuntimeExecutor: docker + containerRuntimeExecutor: emissary profile: minimal - - test: test-examples + - test: test-functional containerRuntimeExecutor: emissary profile: minimal - test: test-executor + containerRuntimeExecutor: docker + profile: minimal + - test: test-examples containerRuntimeExecutor: emissary profile: minimal - test: test-executor @@ -73,9 +76,6 @@ jobs: - test: test-executor containerRuntimeExecutor: pns profile: minimal - - test: test-functional - containerRuntimeExecutor: emissary - profile: minimal steps: - uses: actions/checkout@v2 - uses: actions/setup-go@v2 From 728a1ff67364986cdfe2146dc3179d9705ee26ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Val=C3=A9r=20Orlovsk=C3=BD?= <11498571+valorl@users.noreply.github.com> Date: Thu, 4 Nov 2021 14:02:43 +0100 Subject: [PATCH 42/64] fix: Relative submodules in git artifacts. Fixes #7141 (#7162) Upgrades src-d/go-git v4 to go-git/go-git v5.3.0. See https://github.com/go-git/go-git/pull/195. Signed-off-by: valorl <11498571+valorl@users.noreply.github.com> --- go.mod | 113 +++++++++++++++++++++++++++++++++- go.sum | 86 ++++---------------------- workflow/artifacts/git/git.go | 12 ++-- 3 files changed, 131 insertions(+), 80 deletions(-) diff --git a/go.mod b/go.mod index 855ec3ac8652..dbc8d292d36a 100644 --- a/go.mod +++ b/go.mod @@ -70,7 +70,6 @@ require ( gopkg.in/jcmturner/gokrb5.v5 v5.3.0 gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect gopkg.in/square/go-jose.v2 v2.5.1 - gopkg.in/src-d/go-git.v4 v4.13.1 k8s.io/api v0.21.5 k8s.io/apimachinery v0.21.5 k8s.io/client-go v0.21.5 @@ -82,3 +81,115 @@ require ( sigs.k8s.io/yaml v1.2.0 upper.io/db.v3 v3.6.3+incompatible ) + +require github.com/go-git/go-git/v5 v5.3.0 + +require ( + cloud.google.com/go v0.81.0 // indirect + github.com/Azure/go-autorest v14.2.0+incompatible // indirect + github.com/Azure/go-autorest/autorest v0.11.18 // indirect + github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect + github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect + github.com/Azure/go-autorest/logger v0.2.1 // indirect + github.com/Azure/go-autorest/tracing v0.6.0 // indirect + github.com/Masterminds/goutils v1.1.1 // indirect + github.com/Masterminds/semver/v3 v3.1.1 // indirect + github.com/Microsoft/go-winio v0.4.16 // indirect + github.com/PuerkitoBio/purell v1.1.1 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect + github.com/ajg/form v1.5.1 // indirect + github.com/andybalholm/brotli v1.0.1 // indirect + github.com/awalterschulze/gographviz v0.0.0-20200901124122-0eecad45bd71 // indirect + github.com/aws/aws-sdk-go v1.33.16 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dustin/go-humanize v1.0.0 // indirect + github.com/emirpasic/gods v1.12.0 // indirect + github.com/felixge/httpsnoop v1.0.1 // indirect + github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect + github.com/fsnotify/fsnotify v1.4.9 // indirect + github.com/go-git/gcfg v1.5.0 // indirect + github.com/go-git/go-billy/v5 v5.1.0 // indirect + github.com/go-logr/logr v0.4.0 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/swag v0.19.13 // indirect + github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect + github.com/google/go-cmp v0.5.6 // indirect + github.com/google/go-querystring v1.0.0 // indirect + github.com/google/gofuzz v1.1.0 // indirect + github.com/google/uuid v1.1.2 // indirect + github.com/googleapis/gax-go/v2 v2.0.5 // indirect + github.com/googleapis/gnostic v0.5.1 // indirect + github.com/hashicorp/go-uuid v1.0.2 // indirect + github.com/hashicorp/golang-lru v0.5.4 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/huandu/xstrings v1.3.2 // indirect + github.com/imdario/mergo v0.3.12 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect + github.com/jcmturner/gofork v1.0.0 // indirect + github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.11 // indirect + github.com/jstemmer/go-junit-report v0.9.1 // indirect + github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect + github.com/klauspost/cpuid v1.2.3 // indirect + github.com/lib/pq v1.9.0 // indirect + github.com/magiconair/properties v1.8.5 // indirect + github.com/mailru/easyjson v0.7.6 // indirect + github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect + github.com/minio/md5-simd v1.1.0 // indirect + github.com/minio/sha256-simd v0.1.1 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-homedir v1.1.0 // indirect + github.com/mitchellh/mapstructure v1.4.1 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect + github.com/moby/spdystream v0.2.0 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.1 // indirect + github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852 // indirect + github.com/onsi/ginkgo v1.16.4 // indirect + github.com/onsi/gomega v1.13.0 // indirect + github.com/pelletier/go-toml v1.9.3 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/prometheus/procfs v0.6.0 // indirect + github.com/russross/blackfriday/v2 v2.0.1 // indirect + github.com/sergi/go-diff v1.1.0 // indirect + github.com/shopspring/decimal v1.2.0 // indirect + github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect + github.com/spf13/afero v1.6.0 // indirect + github.com/spf13/cast v1.3.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/stretchr/objx v0.2.0 // indirect + github.com/subosito/gotenv v1.2.0 // indirect + github.com/tidwall/match v1.0.3 // indirect + github.com/tidwall/pretty v1.1.0 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/xanzy/ssh-agent v0.3.0 // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 // indirect + github.com/yudai/gojsondiff v1.0.0 // indirect + github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect + go.opencensus.io v0.23.0 // indirect + golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect + golang.org/x/mod v0.4.2 // indirect + golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect + golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect + golang.org/x/text v0.3.6 // indirect + golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.27.1 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/ini.v1 v1.62.0 // indirect + gopkg.in/jcmturner/aescts.v1 v1.0.1 // indirect + gopkg.in/jcmturner/dnsutils.v1 v1.0.1 // indirect + gopkg.in/jcmturner/rpc.v0 v0.0.2 // indirect + gopkg.in/warnings.v0 v0.1.2 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + moul.io/http2curl v1.0.1-0.20190925090545-5cd742060b0e // indirect + sigs.k8s.io/controller-runtime v0.7.0 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect +) diff --git a/go.sum b/go.sum index f317d39cd335..ad448b7fea37 100644 --- a/go.sum +++ b/go.sum @@ -352,10 +352,14 @@ github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-billy/v5 v5.1.0 h1:4pl5BV4o7ZG/lterP4S6WzJ6xr49Ba5ET9ygheTYahk= github.com/go-git/go-billy/v5 v5.1.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbKy9zOy4aAKrJ5pibIRpVO2BXnK1Tlcg+caKI7Ox5M= github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= +github.com/go-git/go-git/v5 v5.3.0 h1:8WKMtJR2j8RntEXR/uvTKagfEt4GYlwQ7mntE4+0GWc= github.com/go-git/go-git/v5 v5.3.0/go.mod h1:xdX4bWJ48aOrdhnl2XqHYstHbbp6+LFS4r4X+lNVprw= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -464,6 +468,7 @@ github.com/go-swagger/go-swagger v0.25.0 h1:FxhyrWWV8V/A9P6GtI5szWordAdbb6Y0nqdY github.com/go-swagger/go-swagger v0.25.0/go.mod h1:9639ioXrPX9E6BbnbaDklGXjNz7upAXoNBwL4Ok11Vk= github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013 h1:l9rI6sNaZgNC0LnF3MiE+qTmyBA/tZAg1rtyrGbUMK0= github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013/go.mod h1:b65mBPzqzZWxOZGxSWrqs4GInLIn+u99Q9q7p+GKni0= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= @@ -731,7 +736,6 @@ github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q github.com/karrick/godirwalk v1.7.8/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46shStcFDJ34= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= -github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= @@ -763,7 +767,6 @@ github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -887,6 +890,7 @@ github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE github.com/nsqio/go-nsq v1.0.8/go.mod h1:vKq36oyeVXgsS5Q8YEO7WghqidAVXQlcFxzQbQTuDEY= github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= @@ -902,6 +906,8 @@ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4= github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -910,6 +916,7 @@ github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoT github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= @@ -925,7 +932,6 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/getopt v0.0.0-20180729010549-6fdd0a2c7117/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= @@ -1071,8 +1077,6 @@ github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/y github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= -github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= -github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= @@ -1127,8 +1131,6 @@ github.com/valyala/gozstd v1.7.0/go.mod h1:y5Ew47GLlP37EkTB+B4s7r6A5rdaeB7ftbl9z github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= github.com/xanzy/go-gitlab v0.33.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= -github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= -github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/scram v1.0.3/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= @@ -1136,23 +1138,16 @@ github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHM github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xdg/stringprep v1.0.3/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yahoo/athenz v1.8.55/go.mod h1:G7LLFUH7Z/r4QAB7FfudfuA7Am/eCzO1GlzBhDL6Kv0= -github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= -github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= -github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= -github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1172,7 +1167,6 @@ go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qL go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.3.0/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= go.mongodb.org/mongo-driver v1.3.4/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= -go.mongodb.org/mongo-driver v1.3.5 h1:S0ZOruh4YGHjD7JoN7mIsTrNjnQbOjrmgrx6l6pZN7I= go.mongodb.org/mongo-driver v1.3.5/go.mod h1:Ual6Gkco7ZGQw8wE1t4tLnvBsf6yVSM60qW6TgOeJ5c= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -1182,7 +1176,6 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1235,7 +1228,6 @@ golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1265,7 +1257,6 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -1278,7 +1269,6 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1337,7 +1327,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1351,7 +1341,6 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602 h1:0Ja1LBD+yisY6RWM/BH7TJVXWsSjs2VwBSmvSX4HdBc= golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1364,7 +1353,6 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1380,7 +1368,6 @@ golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190124100055-b90733256f2e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1437,6 +1424,7 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1450,11 +1438,9 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1464,14 +1450,12 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1502,7 +1486,6 @@ golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190808195139-e713427fea3f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1547,16 +1530,15 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.1.0/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= @@ -1586,7 +1568,6 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= -google.golang.org/api v0.44.0 h1:URs6qR1lAxDsqWITsQXI4ZkGiYJ5dHtRNiCpfs2OeKA= google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1596,7 +1577,6 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1640,7 +1620,6 @@ google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1666,9 +1645,7 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5 google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc/examples v0.0.0-20201226181154-53788aa5dcb4 h1:tfxAh8kBsG9GdCdaDiSCA1qqpd8lMOqgEebUyqTtnH8= google.golang.org/grpc/examples v0.0.0-20201226181154-53788aa5dcb4/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1681,59 +1658,40 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= -gopkg.in/go-playground/webhooks.v5 v5.15.0 h1:vnD8c5hN/w8qs0K3fQvIDAeYAHBnCclJHPnxNSJeBCw= gopkg.in/go-playground/webhooks.v5 v5.15.0/go.mod h1:LZbya/qLVdbqDR1aKrGuWV6qbia2zCYSR5dpom2SInQ= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.41.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/jcmturner/aescts.v1 v1.0.1 h1:cVVZBK2b1zY26haWB4vbBiZrfFQnfbTVrE3xZq6hrEw= gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= -gopkg.in/jcmturner/dnsutils.v1 v1.0.1 h1:cIuC1OLRGZrld+16ZJvvZxVJeKPsvd5eUIvxfoN5hSM= gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= -gopkg.in/jcmturner/goidentity.v2 v2.0.0 h1:6Bmcdaxb0dD3HyHbo/MtJ2Q1wXLDuZJFwXZmuZvM+zw= gopkg.in/jcmturner/goidentity.v2 v2.0.0/go.mod h1:vCwK9HeXksMeUmQ4SxDd1tRz4LejrKh3KRVjQWhjvZI= gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= -gopkg.in/jcmturner/gokrb5.v5 v5.3.0 h1:RS1MYApX27Hx1Xw7NECs7XxGxxrm69/4OmaRuX9kwec= gopkg.in/jcmturner/gokrb5.v5 v5.3.0/go.mod h1:oQz8Wc5GsctOTgCVyKad1Vw4TCWz5G6gfIQr88RPv4k= gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= -gopkg.in/jcmturner/rpc.v0 v0.0.2 h1:wBTgrbL1qmLBUPsYVCqdJiI5aJgQhexmK+JkTHPUNJI= gopkg.in/jcmturner/rpc.v0 v0.0.2/go.mod h1:NzMq6cRzR9lipgw7WxRBHNx5N8SifBuaCQsOT1kWY/E= gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= -gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= -gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= -gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE= -gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1744,13 +1702,11 @@ gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20190905181640-827449938966/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= @@ -1767,17 +1723,14 @@ k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= k8s.io/api v0.19.2/go.mod h1:IQpK0zFQ1xc5iNIQPqzgoOwuFugaYHK4iCknlAQP9nI= k8s.io/api v0.19.6/go.mod h1:Plxx44Nh4zVblkJrIgxVPgPre1mvng6tXf1Sj3bs0fU= k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= -k8s.io/api v0.21.5 h1:9zp3SslPRB+rqxhGKqqTo6VsN3HX0Ype1nWV6UQQ+Sk= k8s.io/api v0.21.5/go.mod h1:Un8C5Hemo2r3MfPOjZvwQQ9KkBbiTBUCGrjlivo9uJ0= k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY= -k8s.io/apiextensions-apiserver v0.19.2 h1:oG84UwiDsVDu7dlsGQs5GySmQHCzMhknfhFExJMz9tA= k8s.io/apiextensions-apiserver v0.19.2/go.mod h1:EYNjpqIAvNZe+svXVx9j4uBaVhTB4C94HkY3w058qcg= k8s.io/apimachinery v0.17.8/go.mod h1:Lg8zZ5iC/O8UjCqW6DNhcQG2m4TdjF9kwG3891OWbbA= k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= k8s.io/apimachinery v0.19.6/go.mod h1:6sRbGRAVY5DOCuZwB5XkqguBqpqLU6q/kOaOdk29z6Q= k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= -k8s.io/apimachinery v0.21.5 h1:56bnsHcUNboSCbD779GGi4Lh5kHTDFUoDrnHbhLTiaw= k8s.io/apimachinery v0.21.5/go.mod h1:3PfBV+4PPXNs0aueD+7fHcGyhdkFFYqXeshQtsKCi+4= k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= k8s.io/apiserver v0.19.2/go.mod h1:FreAq0bJ2vtZFj9Ago/X0oNGC51GfubKK/ViOKfVAOA= @@ -1786,12 +1739,10 @@ k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= k8s.io/client-go v0.19.2/go.mod h1:S5wPhCqyDNAlzM9CnEdgTGV4OqhsW3jGO1UM1epwfJA= k8s.io/client-go v0.19.6/go.mod h1:gEiS+efRlXYUEQ9Oz4lmNXlxAl5JZ8y2zbTDGhvXXnk= k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= -k8s.io/client-go v0.21.5 h1:zkVidiWVgciPKYqWpMFMjCUF+4rRXcfkKoyQS1Ue21k= k8s.io/client-go v0.21.5/go.mod h1:EUornVlr3rBrPKXUoMPNggJdEQmvFNMpYO3Kb6432kw= k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= k8s.io/code-generator v0.19.2/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk= k8s.io/code-generator v0.19.6/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0= -k8s.io/code-generator v0.21.5 h1:7X6dJG4hzKFHChYpP02iF0XrXhenqQHc76QoKYzDZfI= k8s.io/code-generator v0.21.5/go.mod h1:0K1k6o2ef8JD/j8LF3ZuqWLGFMHvO5psNzLLmxf7ZVE= k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM= k8s.io/component-base v0.19.2/go.mod h1:g5LrsiTiabMLZ40AR6Hl45f088DevyGY+cCE2agEIVo= @@ -1799,32 +1750,26 @@ k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8 k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027 h1:Uusb3oh8XcdzDF/ndlI4ToKTYVlkCSJP39SRY2mfRAw= k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.2.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.5.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= -k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts= k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200410145947-bcb3869e6f29/go.mod h1:F+5wygcW0wmRTnM3cOgIqGivxkwSWIWT5YdsDbeAOaU= k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= -k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0= k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20200912215256-4140de9c8800/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -moul.io/http2curl v1.0.1-0.20190925090545-5cd742060b0e h1:C7q+e9M5nggAvWfVg9Nl66kebKeuJlP3FD58V4RR5wo= moul.io/http2curl v1.0.1-0.20190925090545-5cd742060b0e/go.mod h1:nejbQVfXh96n9dSF6cH3Jsk/QI1Z2oEL7sSI2ifXFNA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= @@ -1832,20 +1777,15 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.9/go.mod h1:dzAXnQbTRyDlZPJX2SUPEqvnB+j7AJjtlox7PEwigU0= -sigs.k8s.io/controller-runtime v0.7.0 h1:bU20IBBEPccWz5+zXpLnpVsgBYxqclaHu1pVDl/gEt8= sigs.k8s.io/controller-runtime v0.7.0/go.mod h1:pJ3YBrJiAqMAZKi6UVGuE98ZrroV1p+pIhoHsMm9wdU= -sigs.k8s.io/controller-tools v0.4.1 h1:VkuV0MxlRPmRu5iTgBZU4UxUX2LiR99n3sdQGRxZF4w= sigs.k8s.io/controller-tools v0.4.1/go.mod h1:G9rHdZMVlBDocIxGkK3jHLWqcTMNvveypYJwrvYKjWU= sigs.k8s.io/structured-merge-diff/v2 v2.0.1/go.mod h1:Wb7vfKAodbKgf6tn1Kl0VvGj7mRH6DGaRcixXEJXTsE= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= -sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= -upper.io/db.v3 v3.6.3+incompatible h1:SJLWd7H56Vwm4rYa+cHAQDYWcvvOt1C/5PD/IIBZPW8= upper.io/db.v3 v3.6.3+incompatible/go.mod h1:FgTdD24eBjJAbPKsQSiHUNgXjOR4Lub3u1UMHSIh82Y= diff --git a/workflow/artifacts/git/git.go b/workflow/artifacts/git/git.go index 9931c49bc1af..271294853578 100644 --- a/workflow/artifacts/git/git.go +++ b/workflow/artifacts/git/git.go @@ -10,14 +10,14 @@ import ( "regexp" "strings" + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/config" + "github.com/go-git/go-git/v5/plumbing" + "github.com/go-git/go-git/v5/plumbing/transport" + "github.com/go-git/go-git/v5/plumbing/transport/http" + ssh2 "github.com/go-git/go-git/v5/plumbing/transport/ssh" log "github.com/sirupsen/logrus" "golang.org/x/crypto/ssh" - "gopkg.in/src-d/go-git.v4" - "gopkg.in/src-d/go-git.v4/config" - "gopkg.in/src-d/go-git.v4/plumbing" - "gopkg.in/src-d/go-git.v4/plumbing/transport" - "gopkg.in/src-d/go-git.v4/plumbing/transport/http" - ssh2 "gopkg.in/src-d/go-git.v4/plumbing/transport/ssh" wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" "github.com/argoproj/argo-workflows/v3/workflow/artifacts/common" From f8f93a6b16e4a1ec17060ef916ea6bd2e8cf80a4 Mon Sep 17 00:00:00 2001 From: Alex Collins Date: Wed, 17 Nov 2021 16:44:55 -0800 Subject: [PATCH 43/64] fix: refactor/fix pod GC. Fixes #7159 (#7176) Signed-off-by: Alex Collins --- go.sum | 53 +++++ pkg/apis/workflow/v1alpha1/workflow_types.go | 35 +-- .../workflow/v1alpha1/workflow_types_test.go | 59 +++++ test/e2e/pod_cleanup_test.go | 202 +++++++++--------- workflow/controller/controller.go | 18 -- workflow/controller/operator.go | 48 +---- workflow/controller/pod_cleanup.go | 52 +++++ workflow/controller/pod_cleanup_test.go | 72 +++++++ workflow/validate/validate.go | 11 +- workflow/validate/validate_test.go | 38 ++-- 10 files changed, 395 insertions(+), 193 deletions(-) create mode 100644 workflow/controller/pod_cleanup.go create mode 100644 workflow/controller/pod_cleanup_test.go diff --git a/go.sum b/go.sum index ad448b7fea37..66c3bf3f87af 100644 --- a/go.sum +++ b/go.sum @@ -1131,6 +1131,7 @@ github.com/valyala/gozstd v1.7.0/go.mod h1:y5Ew47GLlP37EkTB+B4s7r6A5rdaeB7ftbl9z github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= github.com/xanzy/go-gitlab v0.33.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= +github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/scram v1.0.3/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= @@ -1138,15 +1139,21 @@ github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHM github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xdg/stringprep v1.0.3/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/yahoo/athenz v1.8.55/go.mod h1:G7LLFUH7Z/r4QAB7FfudfuA7Am/eCzO1GlzBhDL6Kv0= +github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY= github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI= +github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA= github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= +github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1167,6 +1174,7 @@ go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qL go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.3.0/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= go.mongodb.org/mongo-driver v1.3.4/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= +go.mongodb.org/mongo-driver v1.3.5 h1:S0ZOruh4YGHjD7JoN7mIsTrNjnQbOjrmgrx6l6pZN7I= go.mongodb.org/mongo-driver v1.3.5/go.mod h1:Ual6Gkco7ZGQw8wE1t4tLnvBsf6yVSM60qW6TgOeJ5c= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -1176,6 +1184,7 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1228,6 +1237,7 @@ golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1257,6 +1267,7 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= @@ -1269,6 +1280,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1328,6 +1340,7 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1341,6 +1354,7 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602 h1:0Ja1LBD+yisY6RWM/BH7TJVXWsSjs2VwBSmvSX4HdBc= golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1353,6 +1367,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1438,9 +1453,11 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1450,12 +1467,14 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1535,10 +1554,12 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.1.0/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= @@ -1568,6 +1589,7 @@ google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34q google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.44.0 h1:URs6qR1lAxDsqWITsQXI4ZkGiYJ5dHtRNiCpfs2OeKA= google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1577,6 +1599,7 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1620,6 +1643,7 @@ google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1645,6 +1669,7 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5 google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc/examples v0.0.0-20201226181154-53788aa5dcb4/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -1659,6 +1684,7 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1671,18 +1697,25 @@ gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= +gopkg.in/go-playground/webhooks.v5 v5.15.0 h1:vnD8c5hN/w8qs0K3fQvIDAeYAHBnCclJHPnxNSJeBCw= gopkg.in/go-playground/webhooks.v5 v5.15.0/go.mod h1:LZbya/qLVdbqDR1aKrGuWV6qbia2zCYSR5dpom2SInQ= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.41.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/jcmturner/aescts.v1 v1.0.1 h1:cVVZBK2b1zY26haWB4vbBiZrfFQnfbTVrE3xZq6hrEw= gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= +gopkg.in/jcmturner/dnsutils.v1 v1.0.1 h1:cIuC1OLRGZrld+16ZJvvZxVJeKPsvd5eUIvxfoN5hSM= gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= gopkg.in/jcmturner/goidentity.v2 v2.0.0/go.mod h1:vCwK9HeXksMeUmQ4SxDd1tRz4LejrKh3KRVjQWhjvZI= gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= +gopkg.in/jcmturner/gokrb5.v5 v5.3.0 h1:RS1MYApX27Hx1Xw7NECs7XxGxxrm69/4OmaRuX9kwec= gopkg.in/jcmturner/gokrb5.v5 v5.3.0/go.mod h1:oQz8Wc5GsctOTgCVyKad1Vw4TCWz5G6gfIQr88RPv4k= gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= +gopkg.in/jcmturner/rpc.v0 v0.0.2 h1:wBTgrbL1qmLBUPsYVCqdJiI5aJgQhexmK+JkTHPUNJI= gopkg.in/jcmturner/rpc.v0 v0.0.2/go.mod h1:NzMq6cRzR9lipgw7WxRBHNx5N8SifBuaCQsOT1kWY/E= gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= @@ -1690,8 +1723,10 @@ gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24 gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1702,11 +1737,13 @@ gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20190905181640-827449938966/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= @@ -1723,14 +1760,17 @@ k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= k8s.io/api v0.19.2/go.mod h1:IQpK0zFQ1xc5iNIQPqzgoOwuFugaYHK4iCknlAQP9nI= k8s.io/api v0.19.6/go.mod h1:Plxx44Nh4zVblkJrIgxVPgPre1mvng6tXf1Sj3bs0fU= k8s.io/api v0.20.4/go.mod h1:++lNL1AJMkDymriNniQsWRkMDzRaX2Y/POTUi8yvqYQ= +k8s.io/api v0.21.5 h1:9zp3SslPRB+rqxhGKqqTo6VsN3HX0Ype1nWV6UQQ+Sk= k8s.io/api v0.21.5/go.mod h1:Un8C5Hemo2r3MfPOjZvwQQ9KkBbiTBUCGrjlivo9uJ0= k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY= +k8s.io/apiextensions-apiserver v0.19.2 h1:oG84UwiDsVDu7dlsGQs5GySmQHCzMhknfhFExJMz9tA= k8s.io/apiextensions-apiserver v0.19.2/go.mod h1:EYNjpqIAvNZe+svXVx9j4uBaVhTB4C94HkY3w058qcg= k8s.io/apimachinery v0.17.8/go.mod h1:Lg8zZ5iC/O8UjCqW6DNhcQG2m4TdjF9kwG3891OWbbA= k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA= k8s.io/apimachinery v0.19.6/go.mod h1:6sRbGRAVY5DOCuZwB5XkqguBqpqLU6q/kOaOdk29z6Q= k8s.io/apimachinery v0.20.4/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.21.5 h1:56bnsHcUNboSCbD779GGi4Lh5kHTDFUoDrnHbhLTiaw= k8s.io/apimachinery v0.21.5/go.mod h1:3PfBV+4PPXNs0aueD+7fHcGyhdkFFYqXeshQtsKCi+4= k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= k8s.io/apiserver v0.19.2/go.mod h1:FreAq0bJ2vtZFj9Ago/X0oNGC51GfubKK/ViOKfVAOA= @@ -1739,10 +1779,12 @@ k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= k8s.io/client-go v0.19.2/go.mod h1:S5wPhCqyDNAlzM9CnEdgTGV4OqhsW3jGO1UM1epwfJA= k8s.io/client-go v0.19.6/go.mod h1:gEiS+efRlXYUEQ9Oz4lmNXlxAl5JZ8y2zbTDGhvXXnk= k8s.io/client-go v0.20.4/go.mod h1:LiMv25ND1gLUdBeYxBIwKpkSC5IsozMMmOOeSJboP+k= +k8s.io/client-go v0.21.5 h1:zkVidiWVgciPKYqWpMFMjCUF+4rRXcfkKoyQS1Ue21k= k8s.io/client-go v0.21.5/go.mod h1:EUornVlr3rBrPKXUoMPNggJdEQmvFNMpYO3Kb6432kw= k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= k8s.io/code-generator v0.19.2/go.mod h1:moqLn7w0t9cMs4+5CQyxnfA/HV8MF6aAVENF+WZZhgk= k8s.io/code-generator v0.19.6/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0= +k8s.io/code-generator v0.21.5 h1:7X6dJG4hzKFHChYpP02iF0XrXhenqQHc76QoKYzDZfI= k8s.io/code-generator v0.21.5/go.mod h1:0K1k6o2ef8JD/j8LF3ZuqWLGFMHvO5psNzLLmxf7ZVE= k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM= k8s.io/component-base v0.19.2/go.mod h1:g5LrsiTiabMLZ40AR6Hl45f088DevyGY+cCE2agEIVo= @@ -1750,26 +1792,32 @@ k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8 k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027 h1:Uusb3oh8XcdzDF/ndlI4ToKTYVlkCSJP39SRY2mfRAw= k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.2.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.5.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts= k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= k8s.io/kube-openapi v0.0.0-20200410145947-bcb3869e6f29/go.mod h1:F+5wygcW0wmRTnM3cOgIqGivxkwSWIWT5YdsDbeAOaU= k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0= k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20200912215256-4140de9c8800/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +moul.io/http2curl v1.0.1-0.20190925090545-5cd742060b0e h1:C7q+e9M5nggAvWfVg9Nl66kebKeuJlP3FD58V4RR5wo= moul.io/http2curl v1.0.1-0.20190925090545-5cd742060b0e/go.mod h1:nejbQVfXh96n9dSF6cH3Jsk/QI1Z2oEL7sSI2ifXFNA= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= @@ -1777,15 +1825,20 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.9/go.mod h1:dzAXnQbTRyDlZPJX2SUPEqvnB+j7AJjtlox7PEwigU0= +sigs.k8s.io/controller-runtime v0.7.0 h1:bU20IBBEPccWz5+zXpLnpVsgBYxqclaHu1pVDl/gEt8= sigs.k8s.io/controller-runtime v0.7.0/go.mod h1:pJ3YBrJiAqMAZKi6UVGuE98ZrroV1p+pIhoHsMm9wdU= +sigs.k8s.io/controller-tools v0.4.1 h1:VkuV0MxlRPmRu5iTgBZU4UxUX2LiR99n3sdQGRxZF4w= sigs.k8s.io/controller-tools v0.4.1/go.mod h1:G9rHdZMVlBDocIxGkK3jHLWqcTMNvveypYJwrvYKjWU= sigs.k8s.io/structured-merge-diff/v2 v2.0.1/go.mod h1:Wb7vfKAodbKgf6tn1Kl0VvGj7mRH6DGaRcixXEJXTsE= sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= +upper.io/db.v3 v3.6.3+incompatible h1:SJLWd7H56Vwm4rYa+cHAQDYWcvvOt1C/5PD/IIBZPW8= upper.io/db.v3 v3.6.3+incompatible/go.mod h1:FgTdD24eBjJAbPKsQSiHUNgXjOR4Lub3u1UMHSIh82Y= diff --git a/pkg/apis/workflow/v1alpha1/workflow_types.go b/pkg/apis/workflow/v1alpha1/workflow_types.go index 8e2f9c9aac09..4a6a00504209 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types.go @@ -79,8 +79,21 @@ const ( // PodGCStrategy is the strategy when to delete completed pods for GC. type PodGCStrategy string +func (s PodGCStrategy) IsValid() bool { + switch s { + case PodGCOnPodNone, + PodGCOnPodCompletion, + PodGCOnPodSuccess, + PodGCOnWorkflowCompletion, + PodGCOnWorkflowSuccess: + return true + } + return false +} + // PodGCStrategy const ( + PodGCOnPodNone PodGCStrategy = "" PodGCOnPodCompletion PodGCStrategy = "OnPodCompletion" PodGCOnPodSuccess PodGCStrategy = "OnPodSuccess" PodGCOnWorkflowCompletion PodGCStrategy = "OnWorkflowCompletion" @@ -848,24 +861,22 @@ type PodGC struct { LabelSelector *metav1.LabelSelector `json:"labelSelector,omitempty" protobuf:"bytes,2,opt,name=labelSelector"` } -// Matches returns whether the pod labels match with the label selector specified in podGC. -func (podGC *PodGC) Matches(labels labels.Set) (bool, error) { +// GetLabelSelector gets the label selector from podGC. +func (podGC *PodGC) GetLabelSelector() (labels.Selector, error) { if podGC == nil { - return true, nil + return labels.Nothing(), nil } - selector, err := metav1.LabelSelectorAsSelector(podGC.LabelSelector) - if err != nil { - return false, err + if podGC.LabelSelector == nil { + return labels.Everything(), nil } - return selector.Matches(labels), nil + return metav1.LabelSelectorAsSelector(podGC.LabelSelector) } -// GetLabelSelector gets the label selector from podGC. -func (podGC *PodGC) GetLabelSelector() *metav1.LabelSelector { - if podGC != nil && podGC.LabelSelector != nil { - return podGC.LabelSelector +func (podGC *PodGC) GetStrategy() PodGCStrategy { + if podGC != nil { + return podGC.Strategy } - return nil + return PodGCOnPodNone } // VolumeClaimGC describes how to delete volumes from completed Workflows diff --git a/pkg/apis/workflow/v1alpha1/workflow_types_test.go b/pkg/apis/workflow/v1alpha1/workflow_types_test.go index d2a2df207b2e..0572cb6deb30 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types_test.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/assert" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" "k8s.io/utils/pointer" ) @@ -351,6 +352,64 @@ func TestArtifact_GetArchive(t *testing.T) { assert.Equal(t, &ArchiveStrategy{None: &NoneStrategy{}}, (&Artifact{Archive: &ArchiveStrategy{None: &NoneStrategy{}}}).GetArchive()) } +func TestPodGCStrategy_IsValid(t *testing.T) { + for _, s := range []PodGCStrategy{ + PodGCOnPodNone, + PodGCOnPodCompletion, + PodGCOnPodSuccess, + PodGCOnWorkflowCompletion, + PodGCOnWorkflowSuccess, + } { + t.Run(string(s), func(t *testing.T) { + assert.True(t, s.IsValid()) + }) + } + t.Run("Invalid", func(t *testing.T) { + assert.False(t, PodGCStrategy("Foo").IsValid()) + }) +} + +func TestPodGC_GetStrategy(t *testing.T) { + t.Run("Nil", func(t *testing.T) { + var podGC *PodGC + assert.Equal(t, PodGCOnPodNone, podGC.GetStrategy()) + }) + t.Run("Unspecified", func(t *testing.T) { + var podGC = &PodGC{} + assert.Equal(t, PodGCOnPodNone, podGC.GetStrategy()) + }) + t.Run("Specified", func(t *testing.T) { + var podGC = &PodGC{Strategy: PodGCOnWorkflowSuccess} + assert.Equal(t, PodGCOnWorkflowSuccess, podGC.GetStrategy()) + }) +} + +func TestPodGC_GetLabelSelector(t *testing.T) { + t.Run("Nil", func(t *testing.T) { + var podGC *PodGC + selector, err := podGC.GetLabelSelector() + assert.NoError(t, err) + assert.Equal(t, labels.Nothing(), selector) + }) + t.Run("Unspecified", func(t *testing.T) { + var podGC = &PodGC{} + selector, err := podGC.GetLabelSelector() + assert.NoError(t, err) + assert.Equal(t, labels.Everything(), selector) + }) + t.Run("Specified", func(t *testing.T) { + labelSelector := &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "foo": "bar", + }, + } + var podGC = &PodGC{LabelSelector: labelSelector} + selector, err := podGC.GetLabelSelector() + assert.NoError(t, err) + assert.Equal(t, "foo=bar", selector.String()) + }) +} + func TestNodes_FindByDisplayName(t *testing.T) { assert.Nil(t, Nodes{}.FindByDisplayName("")) assert.NotNil(t, Nodes{"": NodeStatus{DisplayName: "foo"}}.FindByDisplayName("foo")) diff --git a/test/e2e/pod_cleanup_test.go b/test/e2e/pod_cleanup_test.go index 07f674dcb162..6142ed4a3820 100644 --- a/test/e2e/pod_cleanup_test.go +++ b/test/e2e/pod_cleanup_test.go @@ -3,16 +3,11 @@ package e2e import ( - "strings" "testing" "time" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" "github.com/argoproj/argo-workflows/v3/test/e2e/fixtures" "github.com/argoproj/argo-workflows/v3/workflow/common" ) @@ -47,36 +42,6 @@ spec: }) } -func (s *PodCleanupSuite) TestInvalidPodGCLabelSelector() { - s.Given(). - Workflow(` -metadata: - generateName: test-pod-cleanup-invalid-pod-gc-label-selector- -spec: - podGC: - strategy: OnPodCompletion - labelSelector: - matchExpressions: - - {key: environment, operator: InvalidOperator, values: [dev]} - entrypoint: main - templates: - - name: main - steps: - - - name: success - template: success - - name: success - container: - image: argoproj/argosay:v2 -`). - When(). - SubmitWorkflow(). - WaitForWorkflow(fixtures.ToBeFailed). - Then(). - ExpectWorkflow(func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { - assert.True(t, strings.Contains(status.Message, "failed to parse label selector")) - }) -} - func (s *PodCleanupSuite) TestOnPodCompletion() { s.Given(). Workflow(` @@ -119,8 +84,9 @@ spec: } func (s *PodCleanupSuite) TestOnPodCompletionLabelSelected() { - s.Given(). - Workflow(` + s.Run("FailedPod", func() { + s.Given(). + Workflow(` metadata: generateName: test-pod-cleanup-on-pod-completion-label-selected- spec: @@ -148,26 +114,52 @@ spec: labels: evicted: true `). - When(). - SubmitWorkflow(). - WaitForWorkflow(). - Wait(enoughTimeForPodCleanup). - Then(). - ExpectWorkflowNode(wfv1.FailedPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.Nil(t, p, "failed pod is deleted since it matched the label selector in podGC") - } - }). - ExpectWorkflowNode(wfv1.SucceededPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.NotNil(t, p, "successful pod is not deleted since it did not match the label selector in podGC") - } - }) + When(). + SubmitWorkflow(). + WaitForWorkflow(). + Wait(enoughTimeForPodCleanup). + Then(). + ExpectWorkflowNode(wfv1.FailedPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { + if assert.NotNil(t, n) { + assert.Nil(t, p, "failed pod is deleted since it matched the label selector in podGC") + } + }). + ExpectWorkflowNode(wfv1.SucceededPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { + if assert.NotNil(t, n) { + assert.NotNil(t, p, "successful pod is not deleted since it did not match the label selector in podGC") + } + }) + }) } func (s *PodCleanupSuite) TestOnPodSuccess() { - s.Given(). - Workflow(` + s.Run("SucceededPod", func() { + s.Given(). + Workflow(` +metadata: + generateName: test-pod-cleanup-on-pod-completion-label-selected- +spec: + podGC: + strategy: OnPodCompletion + labelSelector: + matchLabels: + evicted: true + entrypoint: main + templates: + - name: main + container: + image: argoproj/argosay:v2 +`). + When(). + SubmitWorkflow(). + WaitForPod(fixtures.PodCompleted) + }) +} + +func (s *PodCleanupSuite) TestOnPodSuccess() { + s.Run("FailedPod", func() { + s.Given(). + Workflow(` metadata: generateName: test-pod-cleanup-on-pod-success- spec: @@ -189,21 +181,22 @@ spec: image: argoproj/argosay:v2 args: [exit, 1] `). - When(). - SubmitWorkflow(). - WaitForWorkflow(). - Wait(enoughTimeForPodCleanup). - Then(). - ExpectWorkflowNode(wfv1.FailedPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.NotNil(t, p, "failed pod is NOT deleted") - } - }). - ExpectWorkflowNode(wfv1.SucceededPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.Nil(t, p, "successful pod is deleted") - } - }) + When(). + SubmitWorkflow(). + WaitForWorkflow(). + Wait(enoughTimeForPodCleanup). + Then(). + ExpectWorkflowNode(wfv1.FailedPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { + if assert.NotNil(t, n) { + assert.NotNil(t, p, "failed pod is NOT deleted") + } + }). + ExpectWorkflowNode(wfv1.SucceededPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { + if assert.NotNil(t, n) { + assert.Nil(t, p, "successful pod is deleted") + } + }) + }) } func (s *PodCleanupSuite) TestOnPodSuccessLabelNotMatch() { @@ -220,21 +213,8 @@ spec: entrypoint: main templates: - name: main - steps: - - - name: success - template: success - - name: failure - template: failure - - name: success - container: - image: argoproj/argosay:v2 - - name: failure container: image: argoproj/argosay:v2 - args: [exit, 1] - metadata: - labels: - evicted: true `). When(). SubmitWorkflow(). @@ -254,8 +234,31 @@ spec: } func (s *PodCleanupSuite) TestOnPodSuccessLabelMatch() { - s.Given(). - Workflow(` + s.Run("FailedPod", func() { + s.Given(). + Workflow(` +metadata: + generateName: test-pod-cleanup-on-pod-success-label-match- +spec: + podGC: + strategy: OnPodSuccess + labelSelector: + matchLabels: + evicted: true + entrypoint: main + templates: + - name: main + container: + image: argoproj/argosay:v2 + args: [exit, 1] +`). + When(). + SubmitWorkflow(). + WaitForPod(fixtures.PodCompleted) + }) + s.Run("SucceededPod", func() { + s.Given(). + Workflow(` metadata: generateName: test-pod-cleanup-on-pod-success-label-match- spec: @@ -283,21 +286,22 @@ spec: image: argoproj/argosay:v2 args: [exit, 1] `). - When(). - SubmitWorkflow(). - WaitForWorkflow(). - Wait(enoughTimeForPodCleanup). - Then(). - ExpectWorkflowNode(wfv1.FailedPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.NotNil(t, p, "failed pod is not deleted since it did not succeed") - } - }). - ExpectWorkflowNode(wfv1.SucceededPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.Nil(t, p, "successful pod is deleted since it succeeded and matched the label selector in podGC") - } - }) + When(). + SubmitWorkflow(). + WaitForWorkflow(). + Wait(enoughTimeForPodCleanup). + Then(). + ExpectWorkflowNode(wfv1.FailedPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { + if assert.NotNil(t, n) { + assert.NotNil(t, p, "failed pod is not deleted since it did not succeed") + } + }). + ExpectWorkflowNode(wfv1.SucceededPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { + if assert.NotNil(t, n) { + assert.Nil(t, p, "successful pod is deleted since it succeeded and matched the label selector in podGC") + } + }) + }) } func (s *PodCleanupSuite) TestOnWorkflowCompletion() { diff --git a/workflow/controller/controller.go b/workflow/controller/controller.go index d715c7671ef5..91fe1c4e7883 100644 --- a/workflow/controller/controller.go +++ b/workflow/controller/controller.go @@ -774,24 +774,6 @@ func (wfc *WorkflowController) processNextItem(ctx context.Context) bool { if err != nil { log.WithError(err).Warn("error to complete the taskset") } - // Send all completed pods to gcPods channel to delete it later depend on the PodGCStrategy. - var doPodGC bool - if woc.execWf.Spec.PodGC != nil { - switch woc.execWf.Spec.PodGC.Strategy { - case wfv1.PodGCOnWorkflowCompletion: - doPodGC = true - case wfv1.PodGCOnWorkflowSuccess: - if woc.wf.Status.Successful() { - doPodGC = true - } - } - } - if doPodGC { - for podName := range woc.completedPods { - delay := woc.controller.Config.GetPodGCDeleteDelayDuration() - woc.controller.queuePodForCleanupAfter(woc.wf.Namespace, podName, deletePod, delay) - } - } } // TODO: operate should return error if it was unable to operate properly diff --git a/workflow/controller/operator.go b/workflow/controller/operator.go index bb1892d80aa3..4c0b22af229b 100644 --- a/workflow/controller/operator.go +++ b/workflow/controller/operator.go @@ -84,7 +84,7 @@ type wfOperationCtx struct { // ArtifactRepository contains the default location of an artifact repository for container artifacts artifactRepository *wfv1.ArtifactRepository // map of completed pods with their corresponding phases - completedPods map[string]apiv1.PodPhase + completedPods map[string]*apiv1.Pod // deadline is the dealine time in which this operation should relinquish // its hold on the workflow so that an operation does not run for too long // and starve other workqueue items. It also enables workflow progress to @@ -155,7 +155,7 @@ func newWorkflowOperationCtx(wf *wfv1.Workflow, wfc *WorkflowController) *wfOper controller: wfc, globalParams: make(map[string]string), volumes: wf.Spec.DeepCopy().Volumes, - completedPods: make(map[string]apiv1.PodPhase), + completedPods: make(map[string]*apiv1.Pod), deadline: time.Now().UTC().Add(maxOperationTime), eventRecorder: wfc.eventRecorderManager.Get(wf.Namespace), preExecutionNodePhases: make(map[string]wfv1.NodePhase), @@ -641,28 +641,8 @@ func (woc *wfOperationCtx) persistUpdates(ctx context.Context) { // It is important that we *never* label pods as completed until we successfully updated the workflow // Failing to do so means we can have inconsistent state. - // TODO: The completedPods will be labeled multiple times. I think it would be improved in the future. - // Send succeeded pods or completed pods to gcPods channel to delete it later depend on the PodGCStrategy. - // Notice we do not need to label the pod if we will delete it later for GC. Otherwise, that may even result in - // errors if we label a pod that was deleted already. - for podName, podPhase := range woc.completedPods { - if woc.execWf.Spec.PodGC != nil { - switch woc.execWf.Spec.PodGC.Strategy { - case wfv1.PodGCOnPodSuccess: - if podPhase == apiv1.PodSucceeded { - delay := woc.controller.Config.GetPodGCDeleteDelayDuration() - woc.controller.queuePodForCleanupAfter(woc.wf.Namespace, podName, deletePod, delay) - } - case wfv1.PodGCOnPodCompletion: - delay := woc.controller.Config.GetPodGCDeleteDelayDuration() - woc.controller.queuePodForCleanupAfter(woc.wf.Namespace, podName, deletePod, delay) - } - } else { - // label pods which will not be deleted - woc.controller.queuePodForCleanup(woc.wf.Namespace, podName, labelPodCompleted) - } - } - + // Pods may be be labeled multiple times. + woc.queuePodsForCleanup() } func (woc *wfOperationCtx) writeBackToInformer() error { @@ -981,15 +961,6 @@ func (woc *wfOperationCtx) podReconciliation(ctx context.Context) error { woc.updated = true } node := woc.wf.Status.Nodes[nodeID] - match := true - if woc.execWf.Spec.PodGC.GetLabelSelector() != nil { - var podLabels labels.Set = pod.GetLabels() - match, err = woc.execWf.Spec.PodGC.Matches(podLabels) - if err != nil { - woc.markWorkflowFailed(ctx, fmt.Sprintf("failed to parse label selector %s for pod GC: %v", woc.execWf.Spec.PodGC.LabelSelector, err)) - return - } - } if node.Type == wfv1.NodeTypePod { if node.HostNodeName != pod.Spec.NodeName { node.HostNodeName = pod.Spec.NodeName @@ -998,18 +969,13 @@ func (woc *wfOperationCtx) podReconciliation(ctx context.Context) error { } } if node.Fulfilled() && !node.IsDaemoned() { - if pod.GetLabels()[common.LabelKeyCompleted] == "true" { - return - } - if match { - woc.completedPods[pod.Name] = pod.Status.Phase - } if woc.shouldPrintPodSpec(node) { printPodSpecLog(pod, woc.wf.Name) } } - if node.Succeeded() && match { - woc.completedPods[pod.Name] = pod.Status.Phase + switch pod.Status.Phase { + case apiv1.PodSucceeded, apiv1.PodFailed: + woc.completedPods[pod.Name] = pod } } } diff --git a/workflow/controller/pod_cleanup.go b/workflow/controller/pod_cleanup.go new file mode 100644 index 000000000000..c167db4384b8 --- /dev/null +++ b/workflow/controller/pod_cleanup.go @@ -0,0 +1,52 @@ +package controller + +import ( + apiv1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + + wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" +) + +func (woc *wfOperationCtx) queuePodsForCleanup() { + delay := woc.controller.Config.GetPodGCDeleteDelayDuration() + podGC := woc.execWf.Spec.PodGC + strategy := podGC.GetStrategy() + selector, _ := podGC.GetLabelSelector() + workflowPhase := woc.wf.Status.Phase + for _, pod := range woc.completedPods { + switch determinePodCleanupAction(selector, pod.Labels, strategy, workflowPhase, pod.Status.Phase) { + case deletePod: + woc.controller.queuePodForCleanupAfter(pod.Namespace, pod.Name, deletePod, delay) + case labelPodCompleted: + woc.controller.queuePodForCleanup(pod.Namespace, pod.Name, labelPodCompleted) + } + } +} + +func determinePodCleanupAction( + selector labels.Selector, + podLabels map[string]string, + strategy wfv1.PodGCStrategy, + workflowPhase wfv1.WorkflowPhase, + podPhase apiv1.PodPhase, +) podCleanupAction { + switch { + case !selector.Matches(labels.Set(podLabels)): // if the pod will never be deleted, label it now + return labelPodCompleted + case strategy == wfv1.PodGCOnPodNone: + return labelPodCompleted + case strategy == wfv1.PodGCOnWorkflowCompletion && workflowPhase.Completed(): + return deletePod + case strategy == wfv1.PodGCOnWorkflowSuccess && workflowPhase == wfv1.WorkflowSucceeded: + return deletePod + case strategy == wfv1.PodGCOnPodCompletion: + return deletePod + case strategy == wfv1.PodGCOnPodSuccess && podPhase == apiv1.PodSucceeded: + return deletePod + case strategy == wfv1.PodGCOnPodSuccess && podPhase == apiv1.PodFailed: + return labelPodCompleted + case workflowPhase.Completed(): + return labelPodCompleted + } + return "" +} diff --git a/workflow/controller/pod_cleanup_test.go b/workflow/controller/pod_cleanup_test.go new file mode 100644 index 000000000000..80c69d02d467 --- /dev/null +++ b/workflow/controller/pod_cleanup_test.go @@ -0,0 +1,72 @@ +package controller + +import ( + "testing" + + "github.com/stretchr/testify/assert" + apiv1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + + wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" +) + +func Test_determinePodCleanupAction(t *testing.T) { + + assert.Equal(t, labelPodCompleted, determinePodCleanupAction(labels.Nothing(), nil, wfv1.PodGCOnPodCompletion, wfv1.WorkflowSucceeded, apiv1.PodSucceeded)) + assert.Equal(t, labelPodCompleted, determinePodCleanupAction(labels.Everything(), nil, wfv1.PodGCOnPodNone, wfv1.WorkflowSucceeded, apiv1.PodSucceeded)) + + type fields = struct { + Strategy wfv1.PodGCStrategy `json:"strategy,omitempty"` + WorkflowPhase wfv1.WorkflowPhase `json:"workflowPhase,omitempty"` + PodPhase apiv1.PodPhase `json:"podPhase,omitempty"` + } + for _, tt := range []struct { + Fields fields `json:"fields"` + Want podCleanupAction `json:"want,omitempty"` + }{ + + // strategy = 4 options + // workflow phase = 3 options + // pod phase = 2 options + + // 4 * 3 * 2 = 24 options + + {fields{wfv1.PodGCOnWorkflowSuccess, wfv1.WorkflowRunning, apiv1.PodSucceeded}, ""}, + {fields{wfv1.PodGCOnWorkflowSuccess, wfv1.WorkflowRunning, apiv1.PodFailed}, ""}, + {fields{wfv1.PodGCOnWorkflowSuccess, wfv1.WorkflowSucceeded, apiv1.PodSucceeded}, deletePod}, + {fields{wfv1.PodGCOnWorkflowSuccess, wfv1.WorkflowSucceeded, apiv1.PodFailed}, deletePod}, + {fields{wfv1.PodGCOnWorkflowSuccess, wfv1.WorkflowFailed, apiv1.PodSucceeded}, labelPodCompleted}, + {fields{wfv1.PodGCOnWorkflowSuccess, wfv1.WorkflowFailed, apiv1.PodFailed}, labelPodCompleted}, + + {fields{wfv1.PodGCOnWorkflowCompletion, wfv1.WorkflowRunning, apiv1.PodSucceeded}, ""}, + {fields{wfv1.PodGCOnWorkflowCompletion, wfv1.WorkflowRunning, apiv1.PodFailed}, ""}, + {fields{wfv1.PodGCOnWorkflowCompletion, wfv1.WorkflowSucceeded, apiv1.PodSucceeded}, deletePod}, + {fields{wfv1.PodGCOnWorkflowCompletion, wfv1.WorkflowSucceeded, apiv1.PodFailed}, deletePod}, + {fields{wfv1.PodGCOnWorkflowCompletion, wfv1.WorkflowFailed, apiv1.PodSucceeded}, deletePod}, + {fields{wfv1.PodGCOnWorkflowCompletion, wfv1.WorkflowFailed, apiv1.PodFailed}, deletePod}, + + {fields{wfv1.PodGCOnPodSuccess, wfv1.WorkflowRunning, apiv1.PodSucceeded}, deletePod}, + {fields{wfv1.PodGCOnPodSuccess, wfv1.WorkflowRunning, apiv1.PodFailed}, labelPodCompleted}, + {fields{wfv1.PodGCOnPodSuccess, wfv1.WorkflowSucceeded, apiv1.PodSucceeded}, deletePod}, + {fields{wfv1.PodGCOnPodSuccess, wfv1.WorkflowSucceeded, apiv1.PodFailed}, labelPodCompleted}, + {fields{wfv1.PodGCOnPodSuccess, wfv1.WorkflowFailed, apiv1.PodSucceeded}, deletePod}, + {fields{wfv1.PodGCOnPodSuccess, wfv1.WorkflowFailed, apiv1.PodFailed}, labelPodCompleted}, + + {fields{wfv1.PodGCOnPodCompletion, wfv1.WorkflowRunning, apiv1.PodSucceeded}, deletePod}, + {fields{wfv1.PodGCOnPodCompletion, wfv1.WorkflowRunning, apiv1.PodFailed}, deletePod}, + {fields{wfv1.PodGCOnPodCompletion, wfv1.WorkflowSucceeded, apiv1.PodSucceeded}, deletePod}, + {fields{wfv1.PodGCOnPodCompletion, wfv1.WorkflowSucceeded, apiv1.PodFailed}, deletePod}, + {fields{wfv1.PodGCOnPodCompletion, wfv1.WorkflowFailed, apiv1.PodSucceeded}, deletePod}, + {fields{wfv1.PodGCOnPodCompletion, wfv1.WorkflowFailed, apiv1.PodFailed}, deletePod}, + } { + t.Run(wfv1.MustMarshallJSON(tt), func(t *testing.T) { + action := determinePodCleanupAction( + labels.Everything(), + nil, + tt.Fields.Strategy, + tt.Fields.WorkflowPhase, + tt.Fields.PodPhase) + assert.Equal(t, tt.Want, action) + }) + } +} diff --git a/workflow/validate/validate.go b/workflow/validate/validate.go index 512ad19a5597..c8d5de7a98a7 100644 --- a/workflow/validate/validate.go +++ b/workflow/validate/validate.go @@ -217,12 +217,11 @@ func ValidateWorkflow(wftmplGetter templateresolution.WorkflowTemplateNamespaced } } - if wf.Spec.PodGC != nil { - switch wf.Spec.PodGC.Strategy { - case wfv1.PodGCOnPodCompletion, wfv1.PodGCOnPodSuccess, wfv1.PodGCOnWorkflowCompletion, wfv1.PodGCOnWorkflowSuccess: - default: - return nil, errors.Errorf(errors.CodeBadRequest, "podGC.strategy unknown strategy '%s'", wf.Spec.PodGC.Strategy) - } + if !wf.Spec.PodGC.GetStrategy().IsValid() { + return nil, errors.Errorf(errors.CodeBadRequest, "podGC.strategy unknown strategy '%s'", wf.Spec.PodGC.Strategy) + } + if _, err := wf.Spec.PodGC.GetLabelSelector(); err != nil { + return nil, errors.Errorf(errors.CodeBadRequest, "podGC.labelSelector invalid: %v", err) } // Check if all templates can be resolved. diff --git a/workflow/validate/validate_test.go b/workflow/validate/validate_test.go index 4486bc2c0aa7..52d6212ae749 100644 --- a/workflow/validate/validate_test.go +++ b/workflow/validate/validate_test.go @@ -1814,38 +1814,42 @@ func TestInvalidResourceWorkflow(t *testing.T) { } var invalidPodGC = ` -apiVersion: argoproj.io/v1alpha1 -kind: Workflow metadata: generateName: pod-gc-strategy-unknown- spec: podGC: strategy: Foo - entrypoint: whalesay + entrypoint: main templates: - - name: whalesay + - name: main container: - image: docker/whalesay:latest - command: [cowsay] - args: ["hello world"] + image: docker/whalesay ` // TestIncorrectPodGCStrategy verifies pod gc strategy is correct. func TestIncorrectPodGCStrategy(t *testing.T) { wf := unmarshalWf(invalidPodGC) _, err := ValidateWorkflow(wftmplGetter, cwftmplGetter, wf, ValidateOpts{}) - assert.EqualError(t, err, "podGC.strategy unknown strategy 'Foo'") +} - for _, start := range []wfv1.PodGCStrategy{wfv1.PodGCOnPodCompletion, wfv1.PodGCOnPodSuccess, wfv1.PodGCOnWorkflowCompletion, wfv1.PodGCOnWorkflowSuccess} { - wf.Spec.PodGC.Strategy = start - _, err = ValidateWorkflow(wftmplGetter, cwftmplGetter, wf, ValidateOpts{}) - assert.NoError(t, err) - - wf.Spec.PodGC.LabelSelector = &metav1.LabelSelector{MatchLabels: map[string]string{"evicted": "true"}} - _, err = ValidateWorkflow(wftmplGetter, cwftmplGetter, wf, ValidateOpts{}) - assert.NoError(t, err) - } +func TestInvalidPodGCLabelSelector(t *testing.T) { + wf := unmarshalWf(` +metadata: + generateName: pod-gc-strategy-unknown- +spec: + podGC: + labelSelector: + matchExpressions: + - {key: environment, operator: InvalidOperator, values: [dev]} + entrypoint: main + templates: + - name: main + container: + image: docker/whalesay +`) + _, err := ValidateWorkflow(wftmplGetter, cwftmplGetter, wf, ValidateOpts{}) + assert.EqualError(t, err, "podGC.labelSelector invalid: \"InvalidOperator\" is not a valid pod selector operator") } //nolint:gosec From 2f96c464a3098b34dfd94c44cc629c881ea3d33f Mon Sep 17 00:00:00 2001 From: Alex Collins Date: Mon, 22 Nov 2021 11:13:29 -0800 Subject: [PATCH 44/64] fix: Fix `argo auth token`. Fixes #7175 (#7186) Signed-off-by: Alex Collins --- util/kubeconfig/kubeconfig.go | 15 +++++++++------ util/kubeconfig/roundtripper.go | 17 ----------------- 2 files changed, 9 insertions(+), 23 deletions(-) delete mode 100644 util/kubeconfig/roundtripper.go diff --git a/util/kubeconfig/kubeconfig.go b/util/kubeconfig/kubeconfig.go index acb1ec2ce29a..18b93d54ca97 100644 --- a/util/kubeconfig/kubeconfig.go +++ b/util/kubeconfig/kubeconfig.go @@ -165,18 +165,21 @@ func GetBearerToken(in *restclient.Config, explicitKubeConfigPath string) (strin // This code is not making actual request. We can ignore it. _ = auth.UpdateTransportConfig(tc) - rt, err := transport.New(tc) + tp, err := transport.New(tc) if err != nil { return "", err } - req := http.Request{Header: map[string][]string{}} - - newT := NewUserAgentRoundTripper("dummy", rt) - resp, err := newT.RoundTrip(&req) + req, err := http.NewRequest("GET", in.Host, nil) + if err != nil { + return "", err + } + resp, err := tc.WrapTransport(tp).RoundTrip(req) if err != nil { return "", err } - resp.Body.Close() + if err := resp.Body.Close(); err != nil { + return "", err + } token := req.Header.Get("Authorization") return strings.TrimPrefix(token, "Bearer "), nil diff --git a/util/kubeconfig/roundtripper.go b/util/kubeconfig/roundtripper.go deleted file mode 100644 index 1eb4bb2fa8a6..000000000000 --- a/util/kubeconfig/roundtripper.go +++ /dev/null @@ -1,17 +0,0 @@ -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} -} From 06e5950b8f3fbafdfeb7d45a603caf03096f958e Mon Sep 17 00:00:00 2001 From: Simon Behar Date: Mon, 29 Nov 2021 14:35:01 -0500 Subject: [PATCH 45/64] fix: Use default value for empty env vars (#7297) Signed-off-by: Simon Behar --- util/env/env.go | 6 +++--- util/env/env_test.go | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/util/env/env.go b/util/env/env.go index 281aaca50037..76e23461f64c 100644 --- a/util/env/env.go +++ b/util/env/env.go @@ -10,7 +10,7 @@ import ( func LookupEnvDurationOr(key string, o time.Duration) time.Duration { v, found := os.LookupEnv(key) - if found { + if found && v != "" { d, err := time.ParseDuration(v) if err != nil { log.WithField(key, v).WithError(err).Panic("failed to parse") @@ -23,7 +23,7 @@ func LookupEnvDurationOr(key string, o time.Duration) time.Duration { func LookupEnvIntOr(key string, o int) int { v, found := os.LookupEnv(key) - if found { + if found && v != "" { d, err := strconv.Atoi(v) if err != nil { log.WithField(key, v).WithError(err).Panic("failed to convert to int") @@ -36,7 +36,7 @@ func LookupEnvIntOr(key string, o int) int { func LookupEnvFloatOr(key string, o float64) float64 { v, found := os.LookupEnv(key) - if found { + if found && v != "" { d, err := strconv.ParseFloat(v, 64) if err != nil { log.WithField(key, v).WithError(err).Panic("failed to convert to float") diff --git a/util/env/env_test.go b/util/env/env_test.go index d5daa4788b5a..8a51b3655ff2 100644 --- a/util/env/env_test.go +++ b/util/env/env_test.go @@ -15,6 +15,8 @@ func TestLookupEnvDurationOr(t *testing.T) { assert.Panics(t, func() { LookupEnvDurationOr("FOO", time.Second) }, "bad value") _ = os.Setenv("FOO", "1h") assert.Equal(t, time.Hour, LookupEnvDurationOr("FOO", time.Second), "env var value") + _ = os.Setenv("FOO", "") + assert.Equal(t, time.Second, LookupEnvDurationOr("FOO", time.Second), "empty var value; default value") } func TestLookupEnvIntOr(t *testing.T) { @@ -24,6 +26,8 @@ func TestLookupEnvIntOr(t *testing.T) { assert.Panics(t, func() { LookupEnvIntOr("FOO", 1) }, "bad value") _ = os.Setenv("FOO", "2") assert.Equal(t, 2, LookupEnvIntOr("FOO", 1), "env var value") + _ = os.Setenv("FOO", "") + assert.Equal(t, 1, LookupEnvIntOr("FOO", 1), "empty var value; default value") } func TestLookupEnvFloatOr(t *testing.T) { @@ -33,4 +37,6 @@ func TestLookupEnvFloatOr(t *testing.T) { assert.Panics(t, func() { LookupEnvFloatOr("FOO", 1.) }, "bad value") _ = os.Setenv("FOO", "2.0") assert.Equal(t, 2., LookupEnvFloatOr("FOO", 1.), "env var value") + _ = os.Setenv("FOO", "") + assert.Equal(t, 1., LookupEnvFloatOr("FOO", 1.), "empty var value; default value") } From 34f3d13e7e603198548937beb8df7e84f022b918 Mon Sep 17 00:00:00 2001 From: Takumi Sue <23391543+mikutas@users.noreply.github.com> Date: Wed, 1 Dec 2021 00:03:31 +0900 Subject: [PATCH 46/64] fix: pod name shown in log when pod deletion (#7301) Signed-off-by: mikutas <23391543+mikutas@users.noreply.github.com> --- workflow/util/util.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/workflow/util/util.go b/workflow/util/util.go index 483a2d7bfcd6..8bcb0956010c 100644 --- a/workflow/util/util.go +++ b/workflow/util/util.go @@ -804,8 +804,8 @@ func retryWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrato return nil, errors.InternalErrorf("Workflow cannot be retried with node %s in %s phase", node.Name, node.Phase) } if node.Type == wfv1.NodeTypePod { - log.Infof("Deleting pod: %s", node.ID) podName := PodName(wf.Name, node.Name, node.TemplateName, node.ID) + log.Infof("Deleting pod: %s", podName) err := podIf.Delete(ctx, podName, metav1.DeleteOptions{}) if err != nil && !apierr.IsNotFound(err) { return nil, errors.InternalWrapError(err) From a142ac234ee7a4e789ac626636837c00b296be23 Mon Sep 17 00:00:00 2001 From: Saravanan Balasubramanian <33908564+sarabala1979@users.noreply.github.com> Date: Tue, 30 Nov 2021 21:53:11 -0800 Subject: [PATCH 47/64] fix: Handle the panic in operate function (#7262) * fix: Handle the panic in operate function * fix: update Signed-off-by: Saravanan Balasubramanian * chore: addressed comments Signed-off-by: Saravanan Balasubramanian * Update util/runtime/panic.go Co-authored-by: Simon Behar * fix: test Signed-off-by: Saravanan Balasubramanian * fix: lint Signed-off-by: Saravanan Balasubramanian Co-authored-by: Simon Behar --- util/runtime/panic.go | 22 ++++++++++++++++++++++ workflow/controller/operator.go | 4 ++++ workflow/controller/operator_test.go | 27 +++++++++++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 util/runtime/panic.go diff --git a/util/runtime/panic.go b/util/runtime/panic.go new file mode 100644 index 000000000000..e66a4cf52869 --- /dev/null +++ b/util/runtime/panic.go @@ -0,0 +1,22 @@ +package runtime + +import ( + "runtime" + + log "github.com/sirupsen/logrus" +) + +func RecoverFromPanic(log *log.Entry) { + if r := recover(); r != nil { + // Same as stdlib http server code. Manually allocate stack trace buffer size + // to prevent excessively large logs + const size = 64 << 10 + stackTraceBuffer := make([]byte, size) + stackSize := runtime.Stack(stackTraceBuffer, false) + // Free up the unused spaces + stackTraceBuffer = stackTraceBuffer[:stackSize] + log.Errorf("recovered from panic %q. Call stack:\n%s", + r, + stackTraceBuffer) + } +} diff --git a/workflow/controller/operator.go b/workflow/controller/operator.go index 4c0b22af229b..178853114797 100644 --- a/workflow/controller/operator.go +++ b/workflow/controller/operator.go @@ -46,6 +46,8 @@ import ( "github.com/argoproj/argo-workflows/v3/util/intstr" "github.com/argoproj/argo-workflows/v3/util/resource" "github.com/argoproj/argo-workflows/v3/util/retry" + + argoruntime "github.com/argoproj/argo-workflows/v3/util/runtime" "github.com/argoproj/argo-workflows/v3/util/template" waitutil "github.com/argoproj/argo-workflows/v3/util/wait" "github.com/argoproj/argo-workflows/v3/workflow/common" @@ -178,6 +180,8 @@ func newWorkflowOperationCtx(wf *wfv1.Workflow, wfc *WorkflowController) *wfOper // later time // As you must not call `persistUpdates` twice, you must not call `operate` twice. func (woc *wfOperationCtx) operate(ctx context.Context) { + defer argoruntime.RecoverFromPanic(woc.log) + defer func() { if woc.wf.Status.Fulfilled() { woc.killDaemonedChildren("") diff --git a/workflow/controller/operator_test.go b/workflow/controller/operator_test.go index 90401ee4028a..4b8fa2aa4400 100644 --- a/workflow/controller/operator_test.go +++ b/workflow/controller/operator_test.go @@ -7619,6 +7619,33 @@ func TestExitHandlerWithRetryNodeParam(t *testing.T) { assert.Equal(t, "hello world", onExitNode.Inputs.Parameters[0].Value.String()) } +func TestReOperateCompletedWf(t *testing.T) { + wf := wfv1.MustUnmarshalWorkflow(` +metadata: + name: my-wf + namespace: my-ns +spec: + entrypoint: main + templates: + - name: main + dag: + tasks: + - name: pod + template: pod + - name: pod + container: + image: my-image +`) + wf.Status.Phase = wfv1.WorkflowError + wf.Status.FinishedAt = metav1.Now() + cancel, controller := newController(wf) + defer cancel() + + ctx := context.Background() + woc := newWorkflowOperationCtx(wf, controller) + assert.NotPanics(t, func() { woc.operate(ctx) }) +} + func TestSetWFPodNamesAnnotation(t *testing.T) { defer func() { _ = os.Unsetenv("POD_NAMES") From 6bcedb18be40005f8f81eedf923e890a33e9d11e Mon Sep 17 00:00:00 2001 From: Yuan Tang Date: Wed, 1 Dec 2021 11:08:29 -0500 Subject: [PATCH 48/64] fix: Validate the type of configmap before loading parameters. Fixes #7312 (#7314) Signed-off-by: Yuan Tang --- {util => workflow/common}/configmap.go | 7 ++++++- workflow/common/util.go | 2 +- workflow/controller/operator.go | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) rename {util => workflow/common}/configmap.go (72%) diff --git a/util/configmap.go b/workflow/common/configmap.go similarity index 72% rename from util/configmap.go rename to workflow/common/configmap.go index edf4f481fbc4..1440874045f3 100644 --- a/util/configmap.go +++ b/workflow/common/configmap.go @@ -1,4 +1,4 @@ -package util +package common import ( "fmt" @@ -18,6 +18,11 @@ func GetConfigMapValue(configMapInformer cache.SharedIndexInformer, namespace, n if !ok { return "", fmt.Errorf("unable to convert object %s to configmap when syncing ConfigMaps", name) } + if cmType := cm.Labels[LabelKeyConfigMapType]; cmType != LabelValueTypeConfigMapParameter { + return "", fmt.Errorf( + "ConfigMap '%s' needs to have the label %s: %s to load parameters", + name, LabelKeyConfigMapType, LabelValueTypeConfigMapParameter) + } cmValue, ok := cm.Data[key] if !ok { return "", fmt.Errorf("ConfigMap '%s' does not have the key '%s'", name, key) diff --git a/workflow/common/util.go b/workflow/common/util.go index f0fe15cac3b4..c941d21f9b80 100644 --- a/workflow/common/util.go +++ b/workflow/common/util.go @@ -135,7 +135,7 @@ func ProcessArgs(tmpl *wfv1.Template, args wfv1.ArgumentsProvider, globalParams, } if inParam.ValueFrom != nil && inParam.ValueFrom.ConfigMapKeyRef != nil { if configMapInformer != nil { - cmValue, err := util.GetConfigMapValue(configMapInformer, namespace, inParam.ValueFrom.ConfigMapKeyRef.Name, inParam.ValueFrom.ConfigMapKeyRef.Key) + cmValue, err := GetConfigMapValue(configMapInformer, namespace, inParam.ValueFrom.ConfigMapKeyRef.Name, inParam.ValueFrom.ConfigMapKeyRef.Key) if err != nil { return nil, errors.Errorf(errors.CodeBadRequest, "unable to retrieve inputs.parameters.%s from ConfigMap: %s", inParam.Name, err) } diff --git a/workflow/controller/operator.go b/workflow/controller/operator.go index 178853114797..7765e5a72433 100644 --- a/workflow/controller/operator.go +++ b/workflow/controller/operator.go @@ -528,7 +528,7 @@ func (woc *wfOperationCtx) setGlobalParameters(executionParameters wfv1.Argument woc.globalParams["workflow.parameters."+param.Name] = param.Value.String() } else if param.ValueFrom != nil { if param.ValueFrom.ConfigMapKeyRef != nil { - cmValue, err := util.GetConfigMapValue(woc.controller.configMapInformer, woc.wf.ObjectMeta.Namespace, param.ValueFrom.ConfigMapKeyRef.Name, param.ValueFrom.ConfigMapKeyRef.Key) + cmValue, err := common.GetConfigMapValue(woc.controller.configMapInformer, woc.wf.ObjectMeta.Namespace, param.ValueFrom.ConfigMapKeyRef.Name, param.ValueFrom.ConfigMapKeyRef.Key) if err != nil { return fmt.Errorf("failed to set global parameter %s from configmap with name %s and key %s: %w", param.Name, param.ValueFrom.ConfigMapKeyRef.Name, param.ValueFrom.ConfigMapKeyRef.Key, err) From a85458e86fa80f931f1a0a42230f843d26d84fad Mon Sep 17 00:00:00 2001 From: Alex Collins Date: Wed, 1 Dec 2021 12:13:05 -0800 Subject: [PATCH 49/64] fix(ui): Fix events error. Fixes #7320 (#7321) Signed-off-by: Alex Collins --- ui/src/app/workflows/components/events-panel.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/src/app/workflows/components/events-panel.tsx b/ui/src/app/workflows/components/events-panel.tsx index da67a07f0f54..ec50cc2ca086 100644 --- a/ui/src/app/workflows/components/events-panel.tsx +++ b/ui/src/app/workflows/components/events-panel.tsx @@ -110,6 +110,7 @@ export const EventsPanel = ({namespace, name, kind}: {namespace: string; name: s
Message
{events + .filter(e => e && e.lastTimestamp) .sort((a, b) => -a.lastTimestamp.localeCompare(b.lastTimestamp)) .map(e => (
From 5a472dd39faaf57a8b4f1e2d748d5167b66d07a0 Mon Sep 17 00:00:00 2001 From: BOOK Date: Fri, 3 Dec 2021 03:09:12 +0800 Subject: [PATCH 50/64] fix: cannot access HTTP template's outputs (#7200) Signed-off-by: book987 --- .golangci.yml | 2 +- pkg/apis/workflow/v1alpha1/workflow_types.go | 2 +- test/e2e/functional_test.go | 15 ++++++++ test/e2e/testdata/http-outputs.yaml | 40 ++++++++++++++++++++ workflow/controller/agent.go | 9 +++-- workflow/executor/agent.go | 3 +- 6 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 test/e2e/testdata/http-outputs.yaml diff --git a/.golangci.yml b/.golangci.yml index f8bf17c54041..e5c7b134f2cc 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,7 +1,7 @@ # https://golangci-lint.run/usage/quick-start/ run: concurrency: 4 - timeout: 5m + timeout: 8m skip-dirs: - pkg/client - vendor diff --git a/pkg/apis/workflow/v1alpha1/workflow_types.go b/pkg/apis/workflow/v1alpha1/workflow_types.go index 4a6a00504209..cabc21343cdd 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types.go @@ -2425,7 +2425,7 @@ func (tmpl *Template) GetVolumeMounts() []apiv1.VolumeMount { // whether or not the template can and will have outputs (i.e. exit code and result) func (tmpl *Template) HasOutput() bool { - return tmpl.Container != nil || tmpl.ContainerSet.HasContainerNamed("main") || tmpl.Script != nil || tmpl.Data != nil + return tmpl.Container != nil || tmpl.ContainerSet.HasContainerNamed("main") || tmpl.Script != nil || tmpl.Data != nil || tmpl.HTTP != nil } // if logs should be saved as an artifact diff --git a/test/e2e/functional_test.go b/test/e2e/functional_test.go index 2d4bfcc7cbac..b50aaea92219 100644 --- a/test/e2e/functional_test.go +++ b/test/e2e/functional_test.go @@ -809,6 +809,21 @@ func (s *FunctionalSuite) TestDataTransformation() { }) } +func (s *FunctionalSuite) TestHTTPOutputs() { + s.Given(). + Workflow("@testdata/http-outputs.yaml"). + When(). + SubmitWorkflow(). + WaitForWorkflow(fixtures.ToBeSucceeded). + Then(). + ExpectWorkflow(func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + httpNode := status.Nodes.FindByDisplayName("http") + assert.NotNil(t, httpNode.Outputs.Result) + echoNode := status.Nodes.FindByDisplayName("echo") + assert.Equal(t, *httpNode.Outputs.Result, echoNode.Inputs.Parameters[0].Value.String()) + }) +} + func (s *FunctionalSuite) TestScriptAsNonRoot() { s.Given(). Workflow(` diff --git a/test/e2e/testdata/http-outputs.yaml b/test/e2e/testdata/http-outputs.yaml new file mode 100644 index 000000000000..181846f2abef --- /dev/null +++ b/test/e2e/testdata/http-outputs.yaml @@ -0,0 +1,40 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: http-outputs- +spec: + entrypoint: main + templates: + - name: main + dag: + tasks: + - name: http + template: http + arguments: + parameters: + - name: url + value: >- + https://raw.githubusercontent.com/argoproj/argo-workflows/4e450e250168e6b4d51a126b784e90b11a0162bc/pkg/apis/workflow/v1alpha1/generated.swagger.json + - name: echo + template: echo + arguments: + parameters: + - name: msg + value: '{{tasks.http.outputs.result}}' + dependencies: + - http + - name: http + inputs: + parameters: + - name: url + http: + url: '{{inputs.parameters.url}}' + - name: echo + inputs: + parameters: + - name: msg + container: + image: 'argoproj/argosay:v2' + args: + - echo + - '{{inputs.parameters.msg}}' diff --git a/workflow/controller/agent.go b/workflow/controller/agent.go index 459c512e9f98..9a2de98cfa00 100644 --- a/workflow/controller/agent.go +++ b/workflow/controller/agent.go @@ -97,10 +97,11 @@ func (woc *wfOperationCtx) createAgentPod(ctx context.Context) (*apiv1.Pod, erro ImagePullSecrets: woc.execWf.Spec.ImagePullSecrets, Containers: []apiv1.Container{ { - Name: "main", - Command: []string{"argoexec"}, - Args: []string{"agent"}, - Image: woc.controller.executorImage(), + Name: "main", + Command: []string{"argoexec"}, + Args: []string{"agent"}, + Image: woc.controller.executorImage(), + ImagePullPolicy: woc.controller.executorImagePullPolicy(), Env: []apiv1.EnvVar{ {Name: common.EnvVarWorkflowName, Value: woc.wf.Name}, }, diff --git a/workflow/executor/agent.go b/workflow/executor/agent.go index 8f8cab934104..dd2976a5d04d 100644 --- a/workflow/executor/agent.go +++ b/workflow/executor/agent.go @@ -16,6 +16,7 @@ import ( "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" + "k8s.io/utils/pointer" "github.com/argoproj/argo-workflows/v3/errors" wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" @@ -133,7 +134,7 @@ func (ae *AgentExecutor) executeHTTPTemplate(ctx context.Context, tmpl wfv1.Temp return nil, err } outputs := &wfv1.Outputs{} - outputs.Parameters = append(outputs.Parameters, wfv1.Parameter{Name: "result", Value: wfv1.AnyStringPtr(response)}) + outputs.Result = pointer.StringPtr(response) return outputs, nil } From 3911d091530fc743585c72c7366db3a9c7932bfd Mon Sep 17 00:00:00 2001 From: Dominik Deren Date: Tue, 7 Dec 2021 06:25:20 +0100 Subject: [PATCH 51/64] fix: improve error message for ListArchivedWorkflows (#7345) * fix: improve error message for ListArchivedWorkflows Error message that is returned when user tries to list archived workflows and doesn't specify a namespace is very generic and hard to understand. This PR tries to make it a bit more clear as to what might be the cause of the issue, to help guide the user. I thought that it might be a good idea to check if `namespace` is an empty string, and if it is, return a custom error for this case, telling user that `namespace` can't be empty. But I assume that this would not be correct for cases when Argo-Workflows runs with ClusterRole permissions? Signed-off-by: Dominik Deren * Fixing test & adding string formatting. Signed-off-by: Dominik Deren --- server/workflowarchive/archived_workflow_server.go | 2 +- server/workflowarchive/archived_workflow_server_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/workflowarchive/archived_workflow_server.go b/server/workflowarchive/archived_workflow_server.go index f9dfe9ab1fcf..806d844cd09b 100644 --- a/server/workflowarchive/archived_workflow_server.go +++ b/server/workflowarchive/archived_workflow_server.go @@ -83,7 +83,7 @@ func (w *archivedWorkflowServer) ListArchivedWorkflows(ctx context.Context, req return nil, err } if !allowed { - return nil, status.Error(codes.PermissionDenied, "permission denied") + return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("Permission denied, you are not allowed to list workflows in namespace \"%s\". Maybe you want to specify a namespace with `listOptions.fieldSelector=metadata.namespace=your-ns`?", namespace)) } // When the zero value is passed, we should treat this as returning all results diff --git a/server/workflowarchive/archived_workflow_server_test.go b/server/workflowarchive/archived_workflow_server_test.go index 6b00f73d2dfc..c613c765e338 100644 --- a/server/workflowarchive/archived_workflow_server_test.go +++ b/server/workflowarchive/archived_workflow_server_test.go @@ -73,7 +73,7 @@ func Test_archivedWorkflowServer(t *testing.T) { t.Run("ListArchivedWorkflows", func(t *testing.T) { allowed = false _, err := w.ListArchivedWorkflows(ctx, &workflowarchivepkg.ListArchivedWorkflowsRequest{ListOptions: &metav1.ListOptions{Limit: 1}}) - assert.Equal(t, err, status.Error(codes.PermissionDenied, "permission denied")) + assert.Equal(t, err, status.Error(codes.PermissionDenied, "Permission denied, you are not allowed to list workflows in namespace \"\". Maybe you want to specify a namespace with `listOptions.fieldSelector=metadata.namespace=your-ns`?")) allowed = true resp, err := w.ListArchivedWorkflows(ctx, &workflowarchivepkg.ListArchivedWorkflowsRequest{ListOptions: &metav1.ListOptions{Limit: 1}}) if assert.NoError(t, err) { From 48e7906d503831385261dcccd4e1c8695c895895 Mon Sep 17 00:00:00 2001 From: Takumi Sue <23391543+mikutas@users.noreply.github.com> Date: Wed, 8 Dec 2021 09:05:26 +0900 Subject: [PATCH 52/64] fix: argument of PodName function (fixes #7315) (#7316) Signed-off-by: mikutas <23391543+mikutas@users.noreply.github.com> --- workflow/util/util.go | 10 +++++++++- workflow/util/util_test.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/workflow/util/util.go b/workflow/util/util.go index 8bcb0956010c..c0044422eaf4 100644 --- a/workflow/util/util.go +++ b/workflow/util/util.go @@ -804,7 +804,8 @@ func retryWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrato return nil, errors.InternalErrorf("Workflow cannot be retried with node %s in %s phase", node.Name, node.Phase) } if node.Type == wfv1.NodeTypePod { - podName := PodName(wf.Name, node.Name, node.TemplateName, node.ID) + templateName := getTemplateFromNode(node) + podName := PodName(wf.Name, node.Name, templateName, node.ID) log.Infof("Deleting pod: %s", podName) err := podIf.Delete(ctx, podName, metav1.DeleteOptions{}) if err != nil && !apierr.IsNotFound(err) { @@ -856,6 +857,13 @@ func retryWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrato return wfClient.Update(ctx, newWF, metav1.UpdateOptions{}) } +func getTemplateFromNode(node wfv1.NodeStatus) string { + if node.TemplateRef != nil { + return node.TemplateRef.Template + } + return node.TemplateName +} + func getNodeIDsToReset(restartSuccessful bool, nodeFieldSelector string, nodes wfv1.Nodes) (map[string]bool, error) { nodeIDsToReset := make(map[string]bool) if !restartSuccessful || len(nodeFieldSelector) == 0 { diff --git a/workflow/util/util_test.go b/workflow/util/util_test.go index 19b355e8a7ab..b2423a7a38d0 100644 --- a/workflow/util/util_test.go +++ b/workflow/util/util_test.go @@ -839,3 +839,34 @@ func TestToUnstructured(t *testing.T) { assert.Equal(t, workflow.Version, gv.Version) } } + +func TestGetTemplateFromNode(t *testing.T) { + cases := []struct { + inputNode wfv1.NodeStatus + expectedTemplateName string + }{ + { + inputNode: wfv1.NodeStatus{ + TemplateRef: &wfv1.TemplateRef{ + Name: "foo-workflowtemplate", + Template: "foo-template", + ClusterScope: false, + }, + TemplateName: "", + }, + expectedTemplateName: "foo-template", + }, + { + inputNode: wfv1.NodeStatus{ + TemplateRef: nil, + TemplateName: "bar-template", + }, + expectedTemplateName: "bar-template", + }, + } + + for _, tc := range cases { + actual := getTemplateFromNode(tc.inputNode) + assert.Equal(t, tc.expectedTemplateName, actual) + } +} From 7c2427005cb69f351b081a6c546bda7978ae665f Mon Sep 17 00:00:00 2001 From: Simon Behar Date: Sat, 11 Dec 2021 11:24:55 -0500 Subject: [PATCH 53/64] fix: Skip missed executions if CronWorkflow schedule is changed. Fixes #7182 (#7353) Signed-off-by: Simon Behar --- cmd/argo/commands/cron/util.go | 6 +- .../workflow/v1alpha1/cron_workflow_types.go | 30 ++++++++ .../v1alpha1/cron_workflow_types_test.go | 12 +++ test/e2e/cron_test.go | 2 + workflow/cron/controller.go | 7 +- workflow/cron/operator.go | 13 +++- workflow/cron/operator_test.go | 73 ++++++++++++++++++- 7 files changed, 127 insertions(+), 16 deletions(-) diff --git a/cmd/argo/commands/cron/util.go b/cmd/argo/commands/cron/util.go index 4f5d2df7b467..bd0fc8b98300 100644 --- a/cmd/argo/commands/cron/util.go +++ b/cmd/argo/commands/cron/util.go @@ -11,11 +11,7 @@ import ( // GetNextRuntime returns the next time the workflow should run in local time. It assumes the workflow-controller is in // UTC, but nevertheless returns the time in the local timezone. func GetNextRuntime(cwf *v1alpha1.CronWorkflow) (time.Time, error) { - cronScheduleString := cwf.Spec.Schedule - if cwf.Spec.Timezone != "" { - cronScheduleString = "CRON_TZ=" + cwf.Spec.Timezone + " " + cronScheduleString - } - cronSchedule, err := cron.ParseStandard(cronScheduleString) + cronSchedule, err := cron.ParseStandard(cwf.Spec.GetScheduleString()) if err != nil { return time.Time{}, err } diff --git a/pkg/apis/workflow/v1alpha1/cron_workflow_types.go b/pkg/apis/workflow/v1alpha1/cron_workflow_types.go index 7163067c9269..8a420d978d45 100644 --- a/pkg/apis/workflow/v1alpha1/cron_workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/cron_workflow_types.go @@ -4,6 +4,8 @@ import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + + "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow" ) // CronWorkflow is the definition of a scheduled workflow resource @@ -34,6 +36,8 @@ const ( ReplaceConcurrent ConcurrencyPolicy = "Replace" ) +const annotationKeyLatestSchedule = workflow.CronWorkflowFullName + "/last-used-schedule" + // CronWorkflowSpec is the specification of a CronWorkflow type CronWorkflowSpec struct { // WorkflowSpec is the spec of the workflow to be run @@ -67,6 +71,32 @@ type CronWorkflowStatus struct { Conditions Conditions `json:"conditions" protobuf:"bytes,3,rep,name=conditions"` } +func (c *CronWorkflow) IsUsingNewSchedule() bool { + lastUsedSchedule, exists := c.Annotations[annotationKeyLatestSchedule] + // If last-used-schedule does not exist, or if it does not match the current schedule then the CronWorkflow schedule + // was just updated + return !exists || lastUsedSchedule != c.Spec.GetScheduleString() +} + +func (c *CronWorkflow) SetSchedule(schedule string) { + if c.Annotations == nil { + c.Annotations = map[string]string{} + } + c.Annotations[annotationKeyLatestSchedule] = schedule +} + +func (c *CronWorkflow) GetLatestSchedule() string { + return c.Annotations[annotationKeyLatestSchedule] +} + +func (c *CronWorkflowSpec) GetScheduleString() string { + scheduleString := c.Schedule + if c.Timezone != "" { + scheduleString = "CRON_TZ=" + c.Timezone + " " + scheduleString + } + return scheduleString +} + func (c *CronWorkflowStatus) HasActiveUID(uid types.UID) bool { for _, ref := range c.Active { if uid == ref.UID { diff --git a/pkg/apis/workflow/v1alpha1/cron_workflow_types_test.go b/pkg/apis/workflow/v1alpha1/cron_workflow_types_test.go index 877cec2b0ab6..5181680b3e23 100644 --- a/pkg/apis/workflow/v1alpha1/cron_workflow_types_test.go +++ b/pkg/apis/workflow/v1alpha1/cron_workflow_types_test.go @@ -15,3 +15,15 @@ func TestCronWorkflowStatus_HasActiveUID(t *testing.T) { assert.True(t, cwfStatus.HasActiveUID("123")) assert.False(t, cwfStatus.HasActiveUID("foo")) } + +func TestCronWorkflowSpec_GetScheduleString(t *testing.T) { + cwfSpec := CronWorkflowSpec{ + Timezone: "", + Schedule: "* * * * *", + } + + assert.Equal(t, "* * * * *", cwfSpec.GetScheduleString()) + + cwfSpec.Timezone = "America/Los_Angeles" + assert.Equal(t, "CRON_TZ=America/Los_Angeles * * * * *", cwfSpec.GetScheduleString()) +} diff --git a/test/e2e/cron_test.go b/test/e2e/cron_test.go index 140cdac398b8..498a8b1e0ca2 100644 --- a/test/e2e/cron_test.go +++ b/test/e2e/cron_test.go @@ -70,6 +70,7 @@ spec: Wait(1 * time.Minute). Then(). ExpectCron(func(t *testing.T, cronWf *wfv1.CronWorkflow) { + assert.Equal(t, cronWf.Spec.GetScheduleString(), cronWf.GetLatestSchedule()) assert.True(t, cronWf.Status.LastScheduledTime.Time.After(time.Now().Add(-1*time.Minute))) }) }) @@ -108,6 +109,7 @@ spec: Wait(1 * time.Minute). Then(). ExpectCron(func(t *testing.T, cronWf *wfv1.CronWorkflow) { + assert.Equal(t, cronWf.Spec.GetScheduleString(), cronWf.GetLatestSchedule()) assert.True(t, cronWf.Status.LastScheduledTime.Time.After(time.Now().Add(-1*time.Minute))) }) }) diff --git a/workflow/cron/controller.go b/workflow/cron/controller.go index 4d1ee511df63..9e16e70ef528 100644 --- a/workflow/cron/controller.go +++ b/workflow/cron/controller.go @@ -182,12 +182,7 @@ func (cc *Controller) processNextCronItem(ctx context.Context) bool { // The job is currently scheduled, remove it and re add it. cc.cron.Delete(key.(string)) - cronSchedule := cronWf.Spec.Schedule - if cronWf.Spec.Timezone != "" { - cronSchedule = "CRON_TZ=" + cronWf.Spec.Timezone + " " + cronSchedule - } - - lastScheduledTimeFunc, err := cc.cron.AddJob(key.(string), cronSchedule, cronWorkflowOperationCtx) + lastScheduledTimeFunc, err := cc.cron.AddJob(key.(string), cronWf.Spec.GetScheduleString(), cronWorkflowOperationCtx) if err != nil { logCtx.WithError(err).Error("could not schedule CronWorkflow") return true diff --git a/workflow/cron/operator.go b/workflow/cron/operator.go index 62abc6fc57cd..1a2fba8ad5c8 100644 --- a/workflow/cron/operator.go +++ b/workflow/cron/operator.go @@ -73,6 +73,11 @@ func (woc *cronWfOperationCtx) run(ctx context.Context, scheduledRuntime time.Ti woc.log.Infof("Running %s", woc.name) + // If the cron workflow has a schedule that was just updated, update its annotation + if woc.cronWf.IsUsingNewSchedule() { + woc.cronWf.SetSchedule(woc.cronWf.Spec.GetScheduleString()) + } + err := woc.validateCronWorkflow() if err != nil { return @@ -129,7 +134,7 @@ func getWorkflowObjectReference(wf *v1alpha1.Workflow, runWf *v1alpha1.Workflow) } func (woc *cronWfOperationCtx) persistUpdate(ctx context.Context) { - woc.patch(ctx, map[string]interface{}{"status": woc.cronWf.Status}) + woc.patch(ctx, map[string]interface{}{"status": woc.cronWf.Status, "metadata": map[string]interface{}{"annotations": woc.cronWf.Annotations}}) } func (woc *cronWfOperationCtx) persistUpdateActiveWorkflows(ctx context.Context) { @@ -214,6 +219,10 @@ func (woc *cronWfOperationCtx) runOutstandingWorkflows(ctx context.Context) (boo } func (woc *cronWfOperationCtx) shouldOutstandingWorkflowsBeRun() (time.Time, error) { + // If the CronWorkflow schedule was just updated, then do not run any outstanding workflows. + if woc.cronWf.IsUsingNewSchedule() { + return time.Time{}, nil + } // If this CronWorkflow has been run before, check if we have missed any scheduled executions if woc.cronWf.Status.LastScheduledTime != nil { var now time.Time @@ -225,7 +234,7 @@ func (woc *cronWfOperationCtx) shouldOutstandingWorkflowsBeRun() (time.Time, err } now = time.Now().In(loc) - cronScheduleString := "CRON_TZ=" + woc.cronWf.Spec.Timezone + " " + woc.cronWf.Spec.Schedule + cronScheduleString := woc.cronWf.Spec.GetScheduleString() cronSchedule, err = cron.ParseStandard(cronScheduleString) if err != nil { return time.Time{}, fmt.Errorf("unable to form timezone schedule '%s': %s", cronScheduleString, err) diff --git a/workflow/cron/operator_test.go b/workflow/cron/operator_test.go index f268e2ec029c..1217fab8fd04 100644 --- a/workflow/cron/operator_test.go +++ b/workflow/cron/operator_test.go @@ -32,7 +32,6 @@ var scheduledWf = ` schedule: '* * * * *' startingDeadlineSeconds: 30 workflowSpec: - entrypoint: whalesay templates: - container: @@ -76,6 +75,7 @@ func TestRunOutstandingWorkflows(t *testing.T) { cronWf: &cronWf, log: logrus.WithFields(logrus.Fields{}), } + woc.cronWf.SetSchedule(woc.cronWf.Spec.GetScheduleString()) missedExecutionTime, err := woc.shouldOutstandingWorkflowsBeRun() assert.NoError(t, err) // The missedExecutionTime should be the last complete minute mark, which we can get with inferScheduledTime @@ -92,8 +92,14 @@ func TestRunOutstandingWorkflows(t *testing.T) { assert.NoError(t, err) assert.True(t, missedExecutionTime.IsZero()) - // Run the same test in a different timezone + // Same test, but simulate a change to the schedule immediately prior by setting a different last-used-schedule annotation + // In this case, since a schedule change is detected, not workflow should be run + woc.cronWf.SetSchedule("0 * * * *") + missedExecutionTime, err = woc.shouldOutstandingWorkflowsBeRun() + assert.NoError(t, err) + assert.True(t, missedExecutionTime.IsZero()) + // Run the same test in a different timezone testTimezone := "Pacific/Niue" testLocation, err := time.LoadLocation(testTimezone) if err != nil { @@ -109,6 +115,8 @@ func TestRunOutstandingWorkflows(t *testing.T) { cronWf: &cronWf, log: logrus.WithFields(logrus.Fields{}), } + // Reset last-used-schedule as if the current schedule has been used before + woc.cronWf.SetSchedule(woc.cronWf.Spec.GetScheduleString()) missedExecutionTime, err = woc.shouldOutstandingWorkflowsBeRun() assert.NoError(t, err) // The missedExecutionTime should be the last complete minute mark, which we can get with inferScheduledTime @@ -124,6 +132,13 @@ func TestRunOutstandingWorkflows(t *testing.T) { missedExecutionTime, err = woc.shouldOutstandingWorkflowsBeRun() assert.NoError(t, err) assert.True(t, missedExecutionTime.IsZero()) + + // Same test, but simulate a change to the schedule immediately prior by setting a different last-used-schedule annotation + // In this case, since a schedule change is detected, not workflow should be run + woc.cronWf.SetSchedule("0 * * * *") + missedExecutionTime, err = woc.shouldOutstandingWorkflowsBeRun() + assert.NoError(t, err) + assert.True(t, missedExecutionTime.IsZero()) } type fakeLister struct{} @@ -144,7 +159,6 @@ var invalidWf = ` schedule: '* * * * *' startingDeadlineSeconds: 30 workflowSpec: - entrypoint: whalesay templates: - container: @@ -263,3 +277,56 @@ func TestScheduleTimeParam(t *testing.T) { assert.Len(t, wf.GetAnnotations(), 1) assert.NotEmpty(t, wf.GetAnnotations()[common.AnnotationKeyCronWfScheduledTime]) } + +const lastUsedSchedule = `apiVersion: argoproj.io/v1alpha1 +kind: CronWorkflow +metadata: + name: test +spec: + concurrencyPolicy: Forbid + failedJobsHistoryLimit: 1 + schedule: 41 12 * * * + successfulJobsHistoryLimit: 1 + timezone: America/New_York + workflowSpec: + arguments: {} + entrypoint: job + templates: + - container: + args: + - /bin/echo "hello argo" + command: + - /bin/sh + - -c + image: alpine + imagePullPolicy: Always + name: job +` + +func TestLastUsedSchedule(t *testing.T) { + var cronWf v1alpha1.CronWorkflow + v1alpha1.MustUnmarshal([]byte(lastUsedSchedule), &cronWf) + + cs := fake.NewSimpleClientset() + testMetrics := metrics.New(metrics.ServerConfig{}, metrics.ServerConfig{}) + woc := &cronWfOperationCtx{ + wfClientset: cs, + wfClient: cs.ArgoprojV1alpha1().Workflows(""), + cronWfIf: cs.ArgoprojV1alpha1().CronWorkflows(""), + cronWf: &cronWf, + log: logrus.WithFields(logrus.Fields{}), + metrics: testMetrics, + scheduledTimeFunc: inferScheduledTime, + } + + missedExecutionTime, err := woc.shouldOutstandingWorkflowsBeRun() + if assert.NoError(t, err) { + assert.Equal(t, time.Time{}, missedExecutionTime) + } + + woc.cronWf.SetSchedule(woc.cronWf.Spec.GetScheduleString()) + + if assert.NotNil(t, woc.cronWf.Annotations) { + assert.Equal(t, woc.cronWf.Spec.GetScheduleString(), woc.cronWf.GetLatestSchedule()) + } +} From 0eec0f0d5495a0d5174e74e6cac87cc068eb5295 Mon Sep 17 00:00:00 2001 From: Dillen Padhiar <38965141+dpadhiar@users.noreply.github.com> Date: Tue, 14 Dec 2021 15:38:57 -0800 Subject: [PATCH 54/64] fix: added check for initContainer name in workflow template (#7411) Signed-off-by: Dillen Padhiar --- workflow/validate/validate.go | 13 +++++++++++ workflow/validate/validate_test.go | 37 ++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/workflow/validate/validate.go b/workflow/validate/validate.go index c8d5de7a98a7..3c937e6ed265 100644 --- a/workflow/validate/validate.go +++ b/workflow/validate/validate.go @@ -310,6 +310,15 @@ func ValidateCronWorkflow(wftmplGetter templateresolution.WorkflowTemplateNamesp return nil } +func (ctx *templateValidationCtx) validateInitContainers(containers []wfv1.UserContainer) error { + for _, container := range containers { + if len(container.Container.Name) == 0 { + return errors.Errorf(errors.CodeBadRequest, "initContainers must all have container name") + } + } + return nil +} + func (ctx *templateValidationCtx) validateTemplate(tmpl *wfv1.Template, tmplCtx *templateresolution.Context, args wfv1.ArgumentsProvider) error { if err := validateTemplateType(tmpl); err != nil { return err @@ -320,6 +329,10 @@ func (ctx *templateValidationCtx) validateTemplate(tmpl *wfv1.Template, tmplCtx return err } + if err := ctx.validateInitContainers(tmpl.InitContainers); err != nil { + return err + } + localParams := make(map[string]string) if tmpl.IsPodType() { localParams[common.LocalVarPodName] = placeholderGenerator.NextPlaceholder() diff --git a/workflow/validate/validate_test.go b/workflow/validate/validate_test.go index 52d6212ae749..afe857fe22d3 100644 --- a/workflow/validate/validate_test.go +++ b/workflow/validate/validate_test.go @@ -3138,3 +3138,40 @@ func TestStepsOutputParametersForContainerSet(t *testing.T) { _, err := validate(stepsOutputParametersForContainerSet) assert.NoError(t, err) } + +var testInitContainerHasName = ` +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: spurious- +spec: + entrypoint: main + + templates: + - name: main + dag: + tasks: + - name: spurious + template: spurious + + - name: spurious + retryStrategy: + retryPolicy: Always + initContainers: + - image: alpine:latest + # name: sleep + command: + - sleep + - "15" + container: + image: alpine:latest + command: + - echo + - "i am running" +` + +func TestInitContainerHasName(t *testing.T) { + + _, err := validate(testInitContainerHasName) + assert.EqualError(t, err, "templates.main.tasks.spurious initContainers must all have container name") +} From 7933f9579680de570f481004d734bd36ea0ca69e Mon Sep 17 00:00:00 2001 From: Yuan Tang Date: Wed, 1 Dec 2021 11:08:29 -0500 Subject: [PATCH 55/64] fix: makefile and common variable Signed-off-by: Saravanan Balasubramanian --- Makefile | 7 +------ workflow/common/common.go | 7 +++++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 4010229cc676..dab6ef15e6a9 100644 --- a/Makefile +++ b/Makefile @@ -576,14 +576,9 @@ validate-examples: api/jsonschema/schema.json cd examples && go test # pre-push - -<<<<<<< HEAD -.PHONY: pre-commit -pre-commit: codegen lint test start -======= .git/hooks/commit-msg: hack/git/hooks/commit-msg cp -v hack/git/hooks/commit-msg .git/hooks/commit-msg ->>>>>>> 0fb104481... build: prevent bad commit messages, fix broken builds (#7086) + .PHONY: githooks githooks: .git/hooks/commit-msg diff --git a/workflow/common/common.go b/workflow/common/common.go index e006830cc5ba..d36da67f374c 100644 --- a/workflow/common/common.go +++ b/workflow/common/common.go @@ -75,6 +75,13 @@ const ( // LabelKeyOnExit is a label applied to Pods that are run from onExit nodes, so that they are not shut down when stopping a Workflow LabelKeyOnExit = workflow.WorkflowFullName + "/on-exit" + // LabelKeyConfigMapType is the label key for the type of configmap. + LabelKeyConfigMapType = "workflows.argoproj.io/configmap-type" + // LabelValueTypeConfigMapCache is a key for configmaps that are memoization cache. + LabelValueTypeConfigMapCache = "Cache" + // LabelValueTypeConfigMapParameter is a key for configmaps that contains parameter values. + LabelValueTypeConfigMapParameter = "Parameter" + // ExecutorArtifactBaseDir is the base directory in the init container in which artifacts will be copied to. // Each artifact will be named according to its input name (e.g: /argo/inputs/artifacts/CODE) ExecutorArtifactBaseDir = "/argo/inputs/artifacts" From fbb2edb03494160c28a83d2a04546323e119caff Mon Sep 17 00:00:00 2001 From: Saravanan Balasubramanian Date: Tue, 14 Dec 2021 23:42:28 -0800 Subject: [PATCH 56/64] fix: unit test Signed-off-by: Saravanan Balasubramanian --- workflow/common/util.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/workflow/common/util.go b/workflow/common/util.go index c941d21f9b80..12bc14c74d1a 100644 --- a/workflow/common/util.go +++ b/workflow/common/util.go @@ -130,8 +130,12 @@ func ProcessArgs(tmpl *wfv1.Template, args wfv1.ArgumentsProvider, globalParams, } // overwrite value from argument (if supplied) argParam := args.GetParameterByName(inParam.Name) - if argParam != nil && argParam.Value != nil { - inParam.Value = argParam.Value + if argParam != nil { + if argParam.Value != nil { + inParam.Value = argParam.Value + } else { + inParam.ValueFrom = argParam.ValueFrom + } } if inParam.ValueFrom != nil && inParam.ValueFrom.ConfigMapKeyRef != nil { if configMapInformer != nil { From 970bcc04179a98cfcce31977aeb34fbf1a68ebaf Mon Sep 17 00:00:00 2001 From: Saravanan Balasubramanian Date: Wed, 15 Dec 2021 07:37:52 -0800 Subject: [PATCH 57/64] fix: e2e testcase Signed-off-by: Saravanan Balasubramanian --- test/e2e/pod_cleanup_test.go | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/test/e2e/pod_cleanup_test.go b/test/e2e/pod_cleanup_test.go index 6142ed4a3820..f73d34549069 100644 --- a/test/e2e/pod_cleanup_test.go +++ b/test/e2e/pod_cleanup_test.go @@ -132,30 +132,6 @@ spec: }) } -func (s *PodCleanupSuite) TestOnPodSuccess() { - s.Run("SucceededPod", func() { - s.Given(). - Workflow(` -metadata: - generateName: test-pod-cleanup-on-pod-completion-label-selected- -spec: - podGC: - strategy: OnPodCompletion - labelSelector: - matchLabels: - evicted: true - entrypoint: main - templates: - - name: main - container: - image: argoproj/argosay:v2 -`). - When(). - SubmitWorkflow(). - WaitForPod(fixtures.PodCompleted) - }) -} - func (s *PodCleanupSuite) TestOnPodSuccess() { s.Run("FailedPod", func() { s.Given(). From e653e4f2f3652a95e8584488e657838f04d01f7e Mon Sep 17 00:00:00 2001 From: Saravanan Balasubramanian Date: Wed, 15 Dec 2021 08:52:54 -0800 Subject: [PATCH 58/64] fix: e2e test and codegen Signed-off-by: Saravanan Balasubramanian --- go.mod | 104 --------------- go.sum | 12 +- test/e2e/fixtures/when.go | 42 ++++++ test/e2e/pod_cleanup_test.go | 240 +++++++++++------------------------ 4 files changed, 126 insertions(+), 272 deletions(-) diff --git a/go.mod b/go.mod index dbc8d292d36a..e66a3252acf2 100644 --- a/go.mod +++ b/go.mod @@ -85,111 +85,7 @@ require ( require github.com/go-git/go-git/v5 v5.3.0 require ( - cloud.google.com/go v0.81.0 // indirect - github.com/Azure/go-autorest v14.2.0+incompatible // indirect - github.com/Azure/go-autorest/autorest v0.11.18 // indirect - github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect - github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect - github.com/Azure/go-autorest/logger v0.2.1 // indirect - github.com/Azure/go-autorest/tracing v0.6.0 // indirect - github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver/v3 v3.1.1 // indirect - github.com/Microsoft/go-winio v0.4.16 // indirect - github.com/PuerkitoBio/purell v1.1.1 // indirect - github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect - github.com/ajg/form v1.5.1 // indirect - github.com/andybalholm/brotli v1.0.1 // indirect - github.com/awalterschulze/gographviz v0.0.0-20200901124122-0eecad45bd71 // indirect - github.com/aws/aws-sdk-go v1.33.16 // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.1.1 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dustin/go-humanize v1.0.0 // indirect - github.com/emirpasic/gods v1.12.0 // indirect - github.com/felixge/httpsnoop v1.0.1 // indirect - github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect - github.com/fsnotify/fsnotify v1.4.9 // indirect - github.com/go-git/gcfg v1.5.0 // indirect - github.com/go-git/go-billy/v5 v5.1.0 // indirect - github.com/go-logr/logr v0.4.0 // indirect - github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/swag v0.19.13 // indirect - github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect - github.com/google/go-cmp v0.5.6 // indirect - github.com/google/go-querystring v1.0.0 // indirect - github.com/google/gofuzz v1.1.0 // indirect - github.com/google/uuid v1.1.2 // indirect - github.com/googleapis/gax-go/v2 v2.0.5 // indirect - github.com/googleapis/gnostic v0.5.1 // indirect - github.com/hashicorp/go-uuid v1.0.2 // indirect - github.com/hashicorp/golang-lru v0.5.4 // indirect - github.com/hashicorp/hcl v1.0.0 // indirect - github.com/huandu/xstrings v1.3.2 // indirect - github.com/imdario/mergo v0.3.12 // indirect - github.com/inconshreveable/mousetrap v1.0.0 // indirect - github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect - github.com/jcmturner/gofork v1.0.0 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/json-iterator/go v1.1.11 // indirect - github.com/jstemmer/go-junit-report v0.9.1 // indirect - github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect - github.com/klauspost/cpuid v1.2.3 // indirect - github.com/lib/pq v1.9.0 // indirect - github.com/magiconair/properties v1.8.5 // indirect - github.com/mailru/easyjson v0.7.6 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect - github.com/minio/md5-simd v1.1.0 // indirect - github.com/minio/sha256-simd v0.1.1 // indirect - github.com/mitchellh/copystructure v1.2.0 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect - github.com/mitchellh/mapstructure v1.4.1 // indirect - github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/moby/spdystream v0.2.0 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.1 // indirect - github.com/oliveagle/jsonpath v0.0.0-20180606110733-2e52cf6e6852 // indirect github.com/onsi/ginkgo v1.16.4 // indirect github.com/onsi/gomega v1.13.0 // indirect - github.com/pelletier/go-toml v1.9.3 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/procfs v0.6.0 // indirect - github.com/russross/blackfriday/v2 v2.0.1 // indirect - github.com/sergi/go-diff v1.1.0 // indirect - github.com/shopspring/decimal v1.2.0 // indirect - github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect - github.com/spf13/afero v1.6.0 // indirect - github.com/spf13/cast v1.3.1 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/stretchr/objx v0.2.0 // indirect - github.com/subosito/gotenv v1.2.0 // indirect - github.com/tidwall/match v1.0.3 // indirect - github.com/tidwall/pretty v1.1.0 // indirect - github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/xanzy/ssh-agent v0.3.0 // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 // indirect - github.com/yudai/gojsondiff v1.0.0 // indirect - github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect - go.opencensus.io v0.23.0 // indirect - golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect - golang.org/x/mod v0.4.2 // indirect - golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect - golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect - golang.org/x/text v0.3.6 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect - google.golang.org/appengine v1.6.7 // indirect google.golang.org/protobuf v1.27.1 // indirect - gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/ini.v1 v1.62.0 // indirect - gopkg.in/jcmturner/aescts.v1 v1.0.1 // indirect - gopkg.in/jcmturner/dnsutils.v1 v1.0.1 // indirect - gopkg.in/jcmturner/rpc.v0 v0.0.2 // indirect - gopkg.in/warnings.v0 v0.1.2 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect - moul.io/http2curl v1.0.1-0.20190925090545-5cd742060b0e // indirect - sigs.k8s.io/controller-runtime v0.7.0 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect ) diff --git a/go.sum b/go.sum index 66c3bf3f87af..91091367f5bc 100644 --- a/go.sum +++ b/go.sum @@ -888,8 +888,8 @@ github.com/nicksnyder/go-i18n v1.10.1-0.20190510212457-b280125b035a/go.mod h1:e4 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ= github.com/nsqio/go-nsq v1.0.8/go.mod h1:vKq36oyeVXgsS5Q8YEO7WghqidAVXQlcFxzQbQTuDEY= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= @@ -904,9 +904,9 @@ github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4= github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -914,8 +914,8 @@ github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs= github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.13.0 h1:7lLHu94wT9Ij0o6EWWclhu0aOh32VxhkwEJvzuWPeak= github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= @@ -1155,6 +1155,7 @@ github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCO github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yudai/pp v2.0.1+incompatible h1:Q4//iY4pNF6yPLZIigmvcl7k/bPgrcTPIFIcmawg5bI= github.com/yudai/pp v2.0.1+incompatible/go.mod h1:PuxR/8QJ7cyCkFp/aUDS+JY727OFEZkTdatxwunjIkc= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -1671,6 +1672,7 @@ google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc/examples v0.0.0-20201226181154-53788aa5dcb4 h1:tfxAh8kBsG9GdCdaDiSCA1qqpd8lMOqgEebUyqTtnH8= google.golang.org/grpc/examples v0.0.0-20201226181154-53788aa5dcb4/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1692,6 +1694,7 @@ gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= @@ -1710,6 +1713,7 @@ gopkg.in/jcmturner/aescts.v1 v1.0.1 h1:cVVZBK2b1zY26haWB4vbBiZrfFQnfbTVrE3xZq6hr gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= gopkg.in/jcmturner/dnsutils.v1 v1.0.1 h1:cIuC1OLRGZrld+16ZJvvZxVJeKPsvd5eUIvxfoN5hSM= gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= +gopkg.in/jcmturner/goidentity.v2 v2.0.0 h1:6Bmcdaxb0dD3HyHbo/MtJ2Q1wXLDuZJFwXZmuZvM+zw= gopkg.in/jcmturner/goidentity.v2 v2.0.0/go.mod h1:vCwK9HeXksMeUmQ4SxDd1tRz4LejrKh3KRVjQWhjvZI= gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= gopkg.in/jcmturner/gokrb5.v5 v5.3.0 h1:RS1MYApX27Hx1Xw7NECs7XxGxxrm69/4OmaRuX9kwec= @@ -1718,6 +1722,7 @@ gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuv gopkg.in/jcmturner/rpc.v0 v0.0.2 h1:wBTgrbL1qmLBUPsYVCqdJiI5aJgQhexmK+JkTHPUNJI= gopkg.in/jcmturner/rpc.v0 v0.0.2/go.mod h1:NzMq6cRzR9lipgw7WxRBHNx5N8SifBuaCQsOT1kWY/E= gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= +gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= @@ -1725,6 +1730,7 @@ gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76 gopkg.in/square/go-jose.v2 v2.4.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= diff --git a/test/e2e/fixtures/when.go b/test/e2e/fixtures/when.go index 626af22465e8..0e46f8776f34 100644 --- a/test/e2e/fixtures/when.go +++ b/test/e2e/fixtures/when.go @@ -12,6 +12,7 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" + "k8s.io/utils/pointer" wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" "github.com/argoproj/argo-workflows/v3/pkg/client/clientset/versioned/typed/workflow/v1alpha1" @@ -309,6 +310,47 @@ func (w *When) DeleteWorkflow() *When { return w } +type PodCondition func(p *corev1.Pod) bool + +var ( + PodCompleted PodCondition = func(p *corev1.Pod) bool { + return p.Labels[common.LabelKeyCompleted] == "true" + } + PodDeleted PodCondition = func(p *corev1.Pod) bool { + return !p.DeletionTimestamp.IsZero() + } +) + +func (w *When) WaitForPod(condition PodCondition) *When { + w.t.Helper() + ctx := context.Background() + timeout := defaultTimeout + watch, err := w.kubeClient.CoreV1().Pods(Namespace).Watch( + ctx, + metav1.ListOptions{LabelSelector: common.LabelKeyWorkflow + "=" + w.wf.Name, TimeoutSeconds: pointer.Int64Ptr(int64(timeout.Seconds()))}, + ) + if err != nil { + w.t.Fatal(err) + } + defer watch.Stop() + for event := range watch.ResultChan() { + p := event.Object.(*corev1.Pod) + state := p.Status.Phase + if p.Labels[common.LabelKeyCompleted] == "true" { + state = "Complete" + } + if !p.DeletionTimestamp.IsZero() { + state = "Deleted" + } + _, _ = fmt.Printf("pod %s: %s\n", p.Name, state) + if condition(p) { + _, _ = fmt.Printf("Pod condition met\n") + return w + } + } + w.t.Fatal(fmt.Errorf("timeout after %v waiting for pod", timeout)) + return w +} func (w *When) And(block func()) *When { w.t.Helper() block() diff --git a/test/e2e/pod_cleanup_test.go b/test/e2e/pod_cleanup_test.go index f73d34549069..8554a36a64ca 100644 --- a/test/e2e/pod_cleanup_test.go +++ b/test/e2e/pod_cleanup_test.go @@ -1,23 +1,20 @@ +//go:build functional // +build functional package e2e import ( "testing" - "time" "github.com/stretchr/testify/suite" "github.com/argoproj/argo-workflows/v3/test/e2e/fixtures" - "github.com/argoproj/argo-workflows/v3/workflow/common" ) type PodCleanupSuite struct { fixtures.E2ESuite } -const enoughTimeForPodCleanup = 10 * time.Second - func (s *PodCleanupSuite) TestNone() { s.Given(). Workflow(` @@ -32,19 +29,13 @@ spec: `). When(). SubmitWorkflow(). - WaitForWorkflow(). - Wait(enoughTimeForPodCleanup). - Then(). - ExpectWorkflowNode(wfv1.SucceededPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) && assert.NotNil(t, p) { - assert.Equal(t, "true", p.Labels[common.LabelKeyCompleted]) - } - }) + WaitForPod(fixtures.PodCompleted) } func (s *PodCleanupSuite) TestOnPodCompletion() { - s.Given(). - Workflow(` + s.Run("FailedPod", func() { + s.Given(). + Workflow(` metadata: generateName: test-pod-cleanup-on-pod-completion- spec: @@ -53,34 +44,32 @@ spec: entrypoint: main templates: - name: main - steps: - - - name: success - template: success - - name: failure - template: failure - - name: success container: image: argoproj/argosay:v2 - - name: failure + args: [exit, 1] +`). + When(). + SubmitWorkflow(). + WaitForPod(fixtures.PodDeleted) + }) + s.Run("SucceededPod", func() { + s.Given(). + Workflow(` +metadata: + generateName: test-pod-cleanup-on-pod-completion- +spec: + podGC: + strategy: OnPodCompletion + entrypoint: main + templates: + - name: main container: image: argoproj/argosay:v2 - args: [exit, 1] `). - When(). - SubmitWorkflow(). - WaitForWorkflow(). - Wait(enoughTimeForPodCleanup). - Then(). - ExpectWorkflowNode(wfv1.FailedPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.Nil(t, p, "failed pod is deleted") - } - }). - ExpectWorkflowNode(wfv1.SucceededPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.Nil(t, p, "successful pod is deleted") - } - }) + When(). + SubmitWorkflow(). + WaitForPod(fixtures.PodDeleted) + }) } func (s *PodCleanupSuite) TestOnPodCompletionLabelSelected() { @@ -98,15 +87,6 @@ spec: entrypoint: main templates: - name: main - steps: - - - name: success - template: success - - name: failure - template: failure - - name: success - container: - image: argoproj/argosay:v2 - - name: failure container: image: argoproj/argosay:v2 args: [exit, 1] @@ -116,19 +96,28 @@ spec: `). When(). SubmitWorkflow(). - WaitForWorkflow(). - Wait(enoughTimeForPodCleanup). - Then(). - ExpectWorkflowNode(wfv1.FailedPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.Nil(t, p, "failed pod is deleted since it matched the label selector in podGC") - } - }). - ExpectWorkflowNode(wfv1.SucceededPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.NotNil(t, p, "successful pod is not deleted since it did not match the label selector in podGC") - } - }) + WaitForPod(fixtures.PodDeleted) + }) + s.Run("SucceededPod", func() { + s.Given(). + Workflow(` +metadata: + generateName: test-pod-cleanup-on-pod-completion-label-selected- +spec: + podGC: + strategy: OnPodCompletion + labelSelector: + matchLabels: + evicted: true + entrypoint: main + templates: + - name: main + container: + image: argoproj/argosay:v2 +`). + When(). + SubmitWorkflow(). + WaitForPod(fixtures.PodCompleted) }) } @@ -144,34 +133,31 @@ spec: entrypoint: main templates: - name: main - steps: - - - name: success - template: success - - name: failure - template: failure - - name: success container: image: argoproj/argosay:v2 - - name: failure + args: [exit, 1] +`). + When(). + SubmitWorkflow(). + WaitForPod(fixtures.PodCompleted) + }) + s.Run("SucceededPod", func() { + s.Given(). + Workflow(` +metadata: + generateName: test-pod-cleanup-on-pod-success- +spec: + podGC: + strategy: OnPodSuccess + entrypoint: main + templates: + - name: main container: image: argoproj/argosay:v2 - args: [exit, 1] `). When(). SubmitWorkflow(). - WaitForWorkflow(). - Wait(enoughTimeForPodCleanup). - Then(). - ExpectWorkflowNode(wfv1.FailedPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.NotNil(t, p, "failed pod is NOT deleted") - } - }). - ExpectWorkflowNode(wfv1.SucceededPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.Nil(t, p, "successful pod is deleted") - } - }) + WaitForPod(fixtures.PodDeleted) }) } @@ -194,19 +180,7 @@ spec: `). When(). SubmitWorkflow(). - WaitForWorkflow(). - Wait(enoughTimeForPodCleanup). - Then(). - ExpectWorkflowNode(wfv1.FailedPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.NotNil(t, p, "failed pod is not deleted since it did not succeed") - } - }). - ExpectWorkflowNode(wfv1.SucceededPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.NotNil(t, p, "successful pod is not deleted since it did not match the label selector in podGC") - } - }) + WaitForPod(fixtures.PodCompleted) } func (s *PodCleanupSuite) TestOnPodSuccessLabelMatch() { @@ -246,37 +220,15 @@ spec: entrypoint: main templates: - name: main - steps: - - - name: success - template: success - - name: failure - template: failure - - name: success container: image: argoproj/argosay:v2 metadata: labels: evicted: true - - name: failure - container: - image: argoproj/argosay:v2 - args: [exit, 1] `). When(). SubmitWorkflow(). - WaitForWorkflow(). - Wait(enoughTimeForPodCleanup). - Then(). - ExpectWorkflowNode(wfv1.FailedPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.NotNil(t, p, "failed pod is not deleted since it did not succeed") - } - }). - ExpectWorkflowNode(wfv1.SucceededPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.Nil(t, p, "successful pod is deleted since it succeeded and matched the label selector in podGC") - } - }) + WaitForPod(fixtures.PodDeleted) }) } @@ -297,14 +249,7 @@ spec: `). When(). SubmitWorkflow(). - WaitForWorkflow(). - Wait(enoughTimeForPodCleanup). - Then(). - ExpectWorkflowNode(wfv1.FailedPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.Nil(t, p, "failed pod is deleted") - } - }) + WaitForPod(fixtures.PodDeleted) } func (s *PodCleanupSuite) TestOnWorkflowCompletionLabelNotMatch() { @@ -327,14 +272,7 @@ spec: `). When(). SubmitWorkflow(). - WaitForWorkflow(). - Wait(enoughTimeForPodCleanup). - Then(). - ExpectWorkflowNode(wfv1.FailedPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.NotNil(t, p, "failed pod is not deleted since it did not match the label selector in podGC") - } - }) + WaitForPod(fixtures.PodCompleted) } func (s *PodCleanupSuite) TestOnWorkflowCompletionLabelMatch() { @@ -360,14 +298,7 @@ spec: `). When(). SubmitWorkflow(). - WaitForWorkflow(). - Wait(enoughTimeForPodCleanup). - Then(). - ExpectWorkflowNode(wfv1.FailedPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.Nil(t, p, "failed pod is deleted since it matched the label selector in podGC") - } - }) + WaitForPod(fixtures.PodDeleted) } func (s *PodCleanupSuite) TestOnWorkflowSuccess() { @@ -386,14 +317,7 @@ spec: `). When(). SubmitWorkflow(). - WaitForWorkflow(). - Wait(enoughTimeForPodCleanup). - Then(). - ExpectWorkflowNode(wfv1.SucceededPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.Nil(t, p, "successful pod is deleted") - } - }) + WaitForPod(fixtures.PodDeleted) } func (s *PodCleanupSuite) TestOnWorkflowSuccessLabelNotMatch() { @@ -415,14 +339,7 @@ spec: `). When(). SubmitWorkflow(). - WaitForWorkflow(). - Wait(enoughTimeForPodCleanup). - Then(). - ExpectWorkflowNode(wfv1.SucceededPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.NotNil(t, p, "successful pod is not deleted since it did not match the label selector in podGC") - } - }) + WaitForPod(fixtures.PodCompleted) } func (s *PodCleanupSuite) TestOnWorkflowSuccessLabelMatch() { @@ -447,16 +364,9 @@ spec: `). When(). SubmitWorkflow(). - WaitForWorkflow(). - Wait(enoughTimeForPodCleanup). - Then(). - ExpectWorkflowNode(wfv1.SucceededPodNode, func(t *testing.T, n *wfv1.NodeStatus, p *corev1.Pod) { - if assert.NotNil(t, n) { - assert.Nil(t, p, "successful pod is deleted since it matched the label selector in podGC") - } - }) + WaitForPod(fixtures.PodDeleted) } func TestPodCleanupSuite(t *testing.T) { suite.Run(t, new(PodCleanupSuite)) -} +} \ No newline at end of file From c48269fe678ae74092afda498da2f897ba22d177 Mon Sep 17 00:00:00 2001 From: Saravanan Balasubramanian Date: Wed, 15 Dec 2021 11:28:17 -0800 Subject: [PATCH 59/64] fix: codegen Signed-off-by: Saravanan Balasubramanian --- pkg/apis/workflow/v1alpha1/openapi_generated.go | 1 - pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go | 1 - 2 files changed, 2 deletions(-) diff --git a/pkg/apis/workflow/v1alpha1/openapi_generated.go b/pkg/apis/workflow/v1alpha1/openapi_generated.go index 70e09b67c52d..88469c2c2dba 100644 --- a/pkg/apis/workflow/v1alpha1/openapi_generated.go +++ b/pkg/apis/workflow/v1alpha1/openapi_generated.go @@ -1,4 +1,3 @@ -//go:build !ignore_autogenerated // +build !ignore_autogenerated // Code generated by openapi-gen. DO NOT EDIT. diff --git a/pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go index f12226e4786e..23dadd4ed449 100644 --- a/pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go @@ -1,4 +1,3 @@ -//go:build !ignore_autogenerated // +build !ignore_autogenerated // Code generated by deepcopy-gen. DO NOT EDIT. From 09ac50b7dc09a8f8497897254252760739363d0d Mon Sep 17 00:00:00 2001 From: Saravanan Balasubramanian Date: Wed, 15 Dec 2021 12:01:00 -0800 Subject: [PATCH 60/64] fix: lint Signed-off-by: Saravanan Balasubramanian --- workflow/controller/operator.go | 1 - 1 file changed, 1 deletion(-) diff --git a/workflow/controller/operator.go b/workflow/controller/operator.go index 7765e5a72433..498f58d44a4b 100644 --- a/workflow/controller/operator.go +++ b/workflow/controller/operator.go @@ -46,7 +46,6 @@ import ( "github.com/argoproj/argo-workflows/v3/util/intstr" "github.com/argoproj/argo-workflows/v3/util/resource" "github.com/argoproj/argo-workflows/v3/util/retry" - argoruntime "github.com/argoproj/argo-workflows/v3/util/runtime" "github.com/argoproj/argo-workflows/v3/util/template" waitutil "github.com/argoproj/argo-workflows/v3/util/wait" From fc4c3d51e93858c2119124bbb3cb2ba1c35debcb Mon Sep 17 00:00:00 2001 From: Saravanan Balasubramanian Date: Wed, 15 Dec 2021 13:37:21 -0800 Subject: [PATCH 61/64] fix: lint Signed-off-by: Saravanan Balasubramanian --- test/e2e/pod_cleanup_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/pod_cleanup_test.go b/test/e2e/pod_cleanup_test.go index 8554a36a64ca..0813a7bd95d2 100644 --- a/test/e2e/pod_cleanup_test.go +++ b/test/e2e/pod_cleanup_test.go @@ -369,4 +369,4 @@ spec: func TestPodCleanupSuite(t *testing.T) { suite.Run(t, new(PodCleanupSuite)) -} \ No newline at end of file +} From 2a9fb706714744eff7f70dbf56703bcc67ea67e0 Mon Sep 17 00:00:00 2001 From: Alex Collins Date: Fri, 17 Dec 2021 09:56:10 -0800 Subject: [PATCH 62/64] Revert "fix(controller): default volume/mount to emissary (#7125)" This reverts commit 49b3f0cb2733dec438d8340f439467b7661b8bc2. Signed-off-by: Alex Collins --- .../controller/container_set_template_test.go | 15 +++++++++++---- workflow/controller/workflowpod.go | 8 ++++---- workflow/controller/workflowpod_test.go | 2 -- workflow/validate/validate_test.go | 4 ++-- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/workflow/controller/container_set_template_test.go b/workflow/controller/container_set_template_test.go index 46042a1bc4df..9493e4083cbf 100644 --- a/workflow/controller/container_set_template_test.go +++ b/workflow/controller/container_set_template_test.go @@ -42,8 +42,9 @@ spec: pod, err := getPod(woc, "pod") assert.NoError(t, err) + socket := corev1.HostPathSocket assert.ElementsMatch(t, []corev1.Volume{ - {Name: "var-run-argo", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, + {Name: "docker-sock", VolumeSource: corev1.VolumeSource{HostPath: &corev1.HostPathVolumeSource{Path: "/var/run/docker.sock", Type: &socket}}}, {Name: "workspace", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, }, pod.Spec.Volumes) @@ -53,7 +54,9 @@ spec: for _, c := range pod.Spec.Containers { switch c.Name { case common.WaitContainerName: - assert.ElementsMatch(t, []corev1.VolumeMount{}, c.VolumeMounts) + assert.ElementsMatch(t, []corev1.VolumeMount{ + {Name: "docker-sock", MountPath: "/var/run/docker.sock", ReadOnly: true}, + }, c.VolumeMounts) case "ctr-0": assert.ElementsMatch(t, []corev1.VolumeMount{ {Name: "workspace", MountPath: "/workspace"}, @@ -105,8 +108,9 @@ spec: pod, err := getPod(woc, "pod") assert.NoError(t, err) + socket := corev1.HostPathSocket assert.ElementsMatch(t, []corev1.Volume{ - {Name: "var-run-argo", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, + {Name: "docker-sock", VolumeSource: corev1.VolumeSource{HostPath: &corev1.HostPathVolumeSource{Path: "/var/run/docker.sock", Type: &socket}}}, {Name: "workspace", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, {Name: "input-artifacts", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, }, pod.Spec.Volumes) @@ -124,6 +128,7 @@ spec: switch c.Name { case common.WaitContainerName: assert.ElementsMatch(t, []corev1.VolumeMount{ + {Name: "docker-sock", MountPath: "/var/run/docker.sock", ReadOnly: true}, {Name: "workspace", MountPath: "/mainctrfs/workspace"}, {Name: "input-artifacts", MountPath: "/mainctrfs/in/in-0", SubPath: "in-0"}, }, c.VolumeMounts) @@ -179,8 +184,9 @@ spec: pod, err := getPod(woc, "pod") assert.NoError(t, err) + socket := corev1.HostPathSocket assert.ElementsMatch(t, []corev1.Volume{ - {Name: "var-run-argo", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, + {Name: "docker-sock", VolumeSource: corev1.VolumeSource{HostPath: &corev1.HostPathVolumeSource{Path: "/var/run/docker.sock", Type: &socket}}}, {Name: "workspace", VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}}}, }, pod.Spec.Volumes) @@ -191,6 +197,7 @@ spec: switch c.Name { case common.WaitContainerName: assert.ElementsMatch(t, []corev1.VolumeMount{ + {Name: "docker-sock", MountPath: "/var/run/docker.sock", ReadOnly: true}, {Name: "workspace", MountPath: "/mainctrfs/workspace"}, }, c.VolumeMounts) case "main": diff --git a/workflow/controller/workflowpod.go b/workflow/controller/workflowpod.go index 08b6eedeff11..112831a79d5d 100644 --- a/workflow/controller/workflowpod.go +++ b/workflow/controller/workflowpod.go @@ -535,7 +535,7 @@ func (woc *wfOperationCtx) newWaitContainer(tmpl *wfv1.Template) *apiv1.Containe // in order to SIGTERM/SIGKILL the pid ctr.SecurityContext.Privileged = pointer.BoolPtr(true) } - case common.ContainerRuntimeExecutorDocker: + case "", common.ContainerRuntimeExecutorDocker: ctr.VolumeMounts = append(ctr.VolumeMounts, woc.getVolumeMountDockerSock(tmpl)) } return ctr @@ -638,10 +638,10 @@ func (woc *wfOperationCtx) createVolumes(tmpl *wfv1.Template) []apiv1.Volume { } switch woc.getContainerRuntimeExecutor() { case common.ContainerRuntimeExecutorKubelet, common.ContainerRuntimeExecutorK8sAPI, common.ContainerRuntimeExecutorPNS: - case common.ContainerRuntimeExecutorDocker: - volumes = append(volumes, woc.getVolumeDockerSock(tmpl)) - default: + case common.ContainerRuntimeExecutorEmissary: volumes = append(volumes, volumeVarArgo) + default: + volumes = append(volumes, woc.getVolumeDockerSock(tmpl)) } volumes = append(volumes, tmpl.Volumes...) return volumes diff --git a/workflow/controller/workflowpod_test.go b/workflow/controller/workflowpod_test.go index c6a0c05b1e8a..a2ac1d008f24 100644 --- a/workflow/controller/workflowpod_test.go +++ b/workflow/controller/workflowpod_test.go @@ -1526,7 +1526,6 @@ spec: func TestHybridWfVolumesWindows(t *testing.T) { wf := wfv1.MustUnmarshalWorkflow(helloWindowsWf) woc := newWoc(*wf) - woc.controller.Config.ContainerRuntimeExecutor = common.ContainerRuntimeExecutorDocker ctx := context.Background() mainCtr := woc.execWf.Spec.Templates[0].Container @@ -1587,7 +1586,6 @@ func TestWindowsUNCPathsAreRemoved(t *testing.T) { func TestHybridWfVolumesLinux(t *testing.T) { wf := wfv1.MustUnmarshalWorkflow(helloLinuxWf) woc := newWoc(*wf) - woc.controller.Config.ContainerRuntimeExecutor = common.ContainerRuntimeExecutorDocker ctx := context.Background() mainCtr := woc.execWf.Spec.Templates[0].Container diff --git a/workflow/validate/validate_test.go b/workflow/validate/validate_test.go index afe857fe22d3..6ffd62b5ed70 100644 --- a/workflow/validate/validate_test.go +++ b/workflow/validate/validate_test.go @@ -1626,7 +1626,7 @@ func TestBaseImageOutputVerify(t *testing.T) { wfNonPathOutputParam := unmarshalWf(nonPathOutputParameter) var err error - for _, executor := range []string{common.ContainerRuntimeExecutorK8sAPI, common.ContainerRuntimeExecutorKubelet, common.ContainerRuntimeExecutorPNS, common.ContainerRuntimeExecutorDocker, common.ContainerRuntimeExecutorDocker, common.ContainerRuntimeExecutorEmissary, ""} { + for _, executor := range []string{common.ContainerRuntimeExecutorK8sAPI, common.ContainerRuntimeExecutorKubelet, common.ContainerRuntimeExecutorPNS, common.ContainerRuntimeExecutorDocker, ""} { switch executor { case common.ContainerRuntimeExecutorK8sAPI, common.ContainerRuntimeExecutorKubelet: _, err = ValidateWorkflow(wftmplGetter, cwftmplGetter, wfBaseOutArt, ValidateOpts{ContainerRuntimeExecutor: executor}) @@ -1644,7 +1644,7 @@ func TestBaseImageOutputVerify(t *testing.T) { assert.NoError(t, err) _, err = ValidateWorkflow(wftmplGetter, cwftmplGetter, wfBaseWithEmptyDirOutArt, ValidateOpts{ContainerRuntimeExecutor: executor}) assert.Error(t, err) - case common.ContainerRuntimeExecutorDocker, common.ContainerRuntimeExecutorEmissary, "": + case common.ContainerRuntimeExecutorDocker, "": _, err = ValidateWorkflow(wftmplGetter, cwftmplGetter, wfBaseOutArt, ValidateOpts{ContainerRuntimeExecutor: executor}) assert.NoError(t, err) _, err = ValidateWorkflow(wftmplGetter, cwftmplGetter, wfBaseOutParam, ValidateOpts{ContainerRuntimeExecutor: executor}) From db7d90a1f609685cfda73644155854b06fa5d28b Mon Sep 17 00:00:00 2001 From: Alex Collins Date: Fri, 17 Dec 2021 10:13:23 -0800 Subject: [PATCH 63/64] chore: fix TestSendHttpRequest/TimeoutRequest Signed-off-by: Alex Collins --- workflow/executor/http/http_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/workflow/executor/http/http_test.go b/workflow/executor/http/http_test.go index d59797196bc7..1db2b2464a82 100644 --- a/workflow/executor/http/http_test.go +++ b/workflow/executor/http/http_test.go @@ -26,11 +26,11 @@ func TestSendHttpRequest(t *testing.T) { }) t.Run("TimeoutRequest", func(t *testing.T) { // Request sleeps for 4 seconds, but timeout is 2 - request, err := http.NewRequest(http.MethodGet, "http://httpstat.us/200?sleep=4000", bytes.NewBuffer([]byte{})) + request, err := http.NewRequest(http.MethodGet, "https://httpstat.us/200?sleep=4000", bytes.NewBuffer([]byte{})) assert.NoError(t, err) response, err := SendHttpRequest(request, pointer.Int64Ptr(2)) assert.Error(t, err) assert.Empty(t, response) - assert.Equal(t, `Get "http://httpstat.us/200?sleep=4000": context deadline exceeded (Client.Timeout exceeded while awaiting headers)`, err.Error()) + assert.Equal(t, `Get "https://httpstat.us/200?sleep=4000": context deadline exceeded (Client.Timeout exceeded while awaiting headers)`, err.Error()) }) } From 0aa619c4d160c0b46fce19a514874871afdaa3e1 Mon Sep 17 00:00:00 2001 From: Denis Date: Thu, 6 Jan 2022 17:03:39 +0200 Subject: [PATCH 64/64] fix: year bug e2e Signed-off-by: Denis --- examples/expression-tag-template-workflow.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/expression-tag-template-workflow.yaml b/examples/expression-tag-template-workflow.yaml index 2435b3a573ba..87e58e40a01a 100644 --- a/examples/expression-tag-template-workflow.yaml +++ b/examples/expression-tag-template-workflow.yaml @@ -10,7 +10,7 @@ metadata: workflows.argoproj.io/verify.py: | assert status["phase"] == "Succeeded" assert nodes["task-0(0:3)"]["phase"] == "Succeeded" - assert nodes["task-0(0:3)"]["outputs"]["parameters"][0]["value"] == "hello 30 @ 2021\n" + assert nodes["task-0(0:3)"]["outputs"]["parameters"][0]["value"] == "hello 30 @ 2022\n" spec: entrypoint: main templates: