From 40475a1193309fd192a2b212add6f31b1afa8132 Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Wed, 23 Feb 2022 15:42:32 -0800 Subject: [PATCH 01/28] feat: add retry API for archived workflows Signed-off-by: Dillen Padhiar --- api/jsonschema/schema.json | 20 + api/openapi-spec/swagger.json | 64 +++ persist/sqldb/mocks/WorkflowArchive.go | 14 + persist/sqldb/null_workflow_archive.go | 4 + persist/sqldb/workflow_archive.go | 5 + .../archived-workflows-service-client.go | 5 + .../workflowarchive/workflow-archive.pb.go | 494 ++++++++++++++++-- .../workflowarchive/workflow-archive.pb.gw.go | 139 +++++ .../workflowarchive/workflow-archive.proto | 24 + .../client/docs/ArchivedWorkflowServiceApi.md | 66 +++ ...lowV1alpha1RetryArchivedWorkflowRequest.md | 17 + .../api/archived_workflow_service_api.py | 138 +++++ ...1alpha1_retry_archived_workflow_request.py | 271 ++++++++++ .../client/argo_workflows/models/__init__.py | 1 + .../client/docs/ArchivedWorkflowServiceApi.md | 76 +++ ...lowV1alpha1RetryArchivedWorkflowRequest.md | 16 + server/apiserver/argoserver.go | 2 +- .../archived_workflow_server.go | 37 +- .../archived_workflow_server_test.go | 5 +- workflow/util/util.go | 37 +- 20 files changed, 1388 insertions(+), 47 deletions(-) create mode 100644 sdks/java/client/docs/IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest.md create mode 100644 sdks/python/client/argo_workflows/model/io_argoproj_workflow_v1alpha1_retry_archived_workflow_request.py create mode 100644 sdks/python/client/docs/IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest.md diff --git a/api/jsonschema/schema.json b/api/jsonschema/schema.json index 0b709893cd6d..4a7f641eb85e 100644 --- a/api/jsonschema/schema.json +++ b/api/jsonschema/schema.json @@ -6186,6 +6186,26 @@ }, "type": "object" }, + "io.argoproj.workflow.v1alpha1.RetryArchivedWorkflowRequest": { + "properties": { + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "nodeFieldSelector": { + "type": "string" + }, + "restartSuccessful": { + "type": "boolean" + }, + "uid": { + "type": "string" + } + }, + "type": "object" + }, "io.argoproj.workflow.v1alpha1.RetryNodeAntiAffinity": { "description": "RetryNodeAntiAffinity is a placeholder for future expansion, only empty nodeAntiAffinity is allowed. In order to prevent running steps on the same host, it uses \"kubernetes.io/hostname\".", "type": "object" diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index 0da6534bd0cf..2088454c137d 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -204,6 +204,50 @@ } } }, + "/api/v1/archived-workflows/{namespace}/{uid}/retry": { + "put": { + "tags": [ + "ArchivedWorkflowService" + ], + "operationId": "ArchivedWorkflowService_RetryArchivedWorkflow", + "parameters": [ + { + "type": "string", + "name": "namespace", + "in": "path", + "required": true + }, + { + "type": "string", + "name": "uid", + "in": "path", + "required": true + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.RetryArchivedWorkflowRequest" + } + } + ], + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.Workflow" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/grpc.gateway.runtime.Error" + } + } + } + } + }, "/api/v1/archived-workflows/{uid}": { "get": { "tags": [ @@ -10448,6 +10492,26 @@ } } }, + "io.argoproj.workflow.v1alpha1.RetryArchivedWorkflowRequest": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "namespace": { + "type": "string" + }, + "nodeFieldSelector": { + "type": "string" + }, + "restartSuccessful": { + "type": "boolean" + }, + "uid": { + "type": "string" + } + } + }, "io.argoproj.workflow.v1alpha1.RetryNodeAntiAffinity": { "description": "RetryNodeAntiAffinity is a placeholder for future expansion, only empty nodeAntiAffinity is allowed. In order to prevent running steps on the same host, it uses \"kubernetes.io/hostname\".", "type": "object" diff --git a/persist/sqldb/mocks/WorkflowArchive.go b/persist/sqldb/mocks/WorkflowArchive.go index 2d77c8335861..d6d67c0ec089 100644 --- a/persist/sqldb/mocks/WorkflowArchive.go +++ b/persist/sqldb/mocks/WorkflowArchive.go @@ -163,3 +163,17 @@ func (_m *WorkflowArchive) ListWorkflowsLabelValues(key string) (*v1alpha1.Label return r0, r1 } + +// ValidateWorkflow provides a mock function with given fields: wf +func (_m *WorkflowArchive) ValidateWorkflow(wf *v1alpha1.Workflow) error { + ret := _m.Called(wf) + + var r0 error + if rf, ok := ret.Get(0).(func(*v1alpha1.Workflow) error); ok { + r0 = rf(wf) + } else { + r0 = ret.Error(0) + } + + return r0 +} diff --git a/persist/sqldb/null_workflow_archive.go b/persist/sqldb/null_workflow_archive.go index 74218279ee64..15e3cc35d419 100644 --- a/persist/sqldb/null_workflow_archive.go +++ b/persist/sqldb/null_workflow_archive.go @@ -17,6 +17,10 @@ func (r *nullWorkflowArchive) IsEnabled() bool { return false } +func (r *nullWorkflowArchive) ValidateWorkflow(wf *wfv1.Workflow) error { + return nil +} + func (r *nullWorkflowArchive) ArchiveWorkflow(*wfv1.Workflow) error { return nil } diff --git a/persist/sqldb/workflow_archive.go b/persist/sqldb/workflow_archive.go index bbbdea4e8fa8..197a9c6124e6 100644 --- a/persist/sqldb/workflow_archive.go +++ b/persist/sqldb/workflow_archive.go @@ -58,6 +58,7 @@ type WorkflowArchive interface { IsEnabled() bool ListWorkflowsLabelKeys() (*wfv1.LabelKeys, error) ListWorkflowsLabelValues(key string) (*wfv1.LabelValues, error) + ValidateWorkflow(wf *wfv1.Workflow) error } type workflowArchive struct { @@ -72,6 +73,10 @@ func (r *workflowArchive) IsEnabled() bool { return true } +func (r *workflowArchive) ValidateWorkflow(wf *wfv1.Workflow) error { + return r.instanceIDService.Validate(wf) +} + // NewWorkflowArchive returns a new workflowArchive func NewWorkflowArchive(session sqlbuilder.Database, clusterName, managedNamespace string, instanceIDService instanceid.Service) WorkflowArchive { return &workflowArchive{session: session, clusterName: clusterName, managedNamespace: managedNamespace, instanceIDService: instanceIDService, dbType: dbTypeFor(session)} diff --git a/pkg/apiclient/http1/archived-workflows-service-client.go b/pkg/apiclient/http1/archived-workflows-service-client.go index cf26586a548c..71ea5f53fc43 100644 --- a/pkg/apiclient/http1/archived-workflows-service-client.go +++ b/pkg/apiclient/http1/archived-workflows-service-client.go @@ -46,3 +46,8 @@ func (h ArchivedWorkflowsServiceClient) ListArchivedWorkflowLabelValues(_ contex out := &wfv1.LabelValues{} return out, h.Get(in, out, "/api/v1/archived-workflows-label-values") } + +func (h ArchivedWorkflowsServiceClient) RetryArchivedWorkflow(_ context.Context, in *workflowarchivepkg.RetryArchivedWorkflowRequest, _ ...grpc.CallOption) (*wfv1.Workflow, error) { + out := &wfv1.Workflow{} + return out, h.Get(in, out, "/api/v1/archived-workflows-label-values") +} diff --git a/pkg/apiclient/workflowarchive/workflow-archive.pb.go b/pkg/apiclient/workflowarchive/workflow-archive.pb.go index b1f7b5c5fab9..9cb5b79a53a6 100644 --- a/pkg/apiclient/workflowarchive/workflow-archive.pb.go +++ b/pkg/apiclient/workflowarchive/workflow-archive.pb.go @@ -305,6 +305,85 @@ func (m *ListArchivedWorkflowLabelValuesRequest) GetListOptions() *v1.ListOption return nil } +type RetryArchivedWorkflowRequest struct { + Uid string `protobuf:"bytes,1,opt,name=uid,proto3" json:"uid,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Namespace string `protobuf:"bytes,3,opt,name=namespace,proto3" json:"namespace,omitempty"` + RestartSuccessful bool `protobuf:"varint,4,opt,name=restartSuccessful,proto3" json:"restartSuccessful,omitempty"` + NodeFieldSelector string `protobuf:"bytes,5,opt,name=nodeFieldSelector,proto3" json:"nodeFieldSelector,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *RetryArchivedWorkflowRequest) Reset() { *m = RetryArchivedWorkflowRequest{} } +func (m *RetryArchivedWorkflowRequest) String() string { return proto.CompactTextString(m) } +func (*RetryArchivedWorkflowRequest) ProtoMessage() {} +func (*RetryArchivedWorkflowRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_95ca9a2d33e8bb19, []int{6} +} +func (m *RetryArchivedWorkflowRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *RetryArchivedWorkflowRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_RetryArchivedWorkflowRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *RetryArchivedWorkflowRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_RetryArchivedWorkflowRequest.Merge(m, src) +} +func (m *RetryArchivedWorkflowRequest) XXX_Size() int { + return m.Size() +} +func (m *RetryArchivedWorkflowRequest) XXX_DiscardUnknown() { + xxx_messageInfo_RetryArchivedWorkflowRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_RetryArchivedWorkflowRequest proto.InternalMessageInfo + +func (m *RetryArchivedWorkflowRequest) GetUid() string { + if m != nil { + return m.Uid + } + return "" +} + +func (m *RetryArchivedWorkflowRequest) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *RetryArchivedWorkflowRequest) GetNamespace() string { + if m != nil { + return m.Namespace + } + return "" +} + +func (m *RetryArchivedWorkflowRequest) GetRestartSuccessful() bool { + if m != nil { + return m.RestartSuccessful + } + return false +} + +func (m *RetryArchivedWorkflowRequest) GetNodeFieldSelector() string { + if m != nil { + return m.NodeFieldSelector + } + return "" +} + func init() { proto.RegisterType((*ListArchivedWorkflowsRequest)(nil), "workflowarchive.ListArchivedWorkflowsRequest") proto.RegisterType((*GetArchivedWorkflowRequest)(nil), "workflowarchive.GetArchivedWorkflowRequest") @@ -312,6 +391,7 @@ func init() { proto.RegisterType((*ArchivedWorkflowDeletedResponse)(nil), "workflowarchive.ArchivedWorkflowDeletedResponse") proto.RegisterType((*ListArchivedWorkflowLabelKeysRequest)(nil), "workflowarchive.ListArchivedWorkflowLabelKeysRequest") proto.RegisterType((*ListArchivedWorkflowLabelValuesRequest)(nil), "workflowarchive.ListArchivedWorkflowLabelValuesRequest") + proto.RegisterType((*RetryArchivedWorkflowRequest)(nil), "workflowarchive.RetryArchivedWorkflowRequest") } func init() { @@ -319,44 +399,51 @@ func init() { } var fileDescriptor_95ca9a2d33e8bb19 = []byte{ - // 579 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x95, 0xdf, 0x6a, 0x13, 0x4f, - 0x14, 0xc7, 0x99, 0xfe, 0xe0, 0x27, 0x9d, 0x5e, 0x28, 0x23, 0x6a, 0x59, 0xd2, 0x34, 0x0e, 0xda, - 0x46, 0x65, 0x67, 0xdc, 0xb6, 0xa2, 0x97, 0x2a, 0x82, 0x60, 0xd3, 0x2a, 0x29, 0x28, 0x78, 0x23, - 0x93, 0xec, 0xe9, 0x66, 0xcc, 0x66, 0x67, 0xdd, 0x99, 0x6c, 0x2d, 0xd2, 0x1b, 0x5f, 0xa1, 0xaf, - 0xe0, 0x43, 0x88, 0x4f, 0xe0, 0xa5, 0xe8, 0x9d, 0x57, 0x12, 0xbc, 0xf2, 0x29, 0x64, 0x27, 0xd9, - 0x24, 0xe6, 0x3f, 0x58, 0xef, 0x26, 0x27, 0xe7, 0x7c, 0xe7, 0x73, 0xce, 0x7e, 0x0f, 0x83, 0x77, - 0xe2, 0x66, 0xc0, 0x45, 0x2c, 0xeb, 0xa1, 0x84, 0xc8, 0xf0, 0x23, 0x95, 0x34, 0x0f, 0x43, 0x75, - 0x24, 0x92, 0x7a, 0x43, 0xa6, 0xd0, 0xff, 0xed, 0xf6, 0x02, 0x2c, 0x4e, 0x94, 0x51, 0xe4, 0xfc, - 0x48, 0x9e, 0x53, 0x08, 0x94, 0x0a, 0x42, 0xc8, 0x94, 0xb8, 0x88, 0x22, 0x65, 0x84, 0x91, 0x2a, - 0xd2, 0xdd, 0x74, 0x67, 0xa7, 0x79, 0x4f, 0x33, 0xa9, 0xb2, 0x7f, 0x5b, 0xa2, 0xde, 0x90, 0x11, - 0x24, 0xc7, 0xbc, 0x77, 0xb1, 0xe6, 0x2d, 0x30, 0x82, 0xa7, 0x1e, 0x0f, 0x20, 0x82, 0x44, 0x18, - 0xf0, 0x7b, 0x55, 0x7b, 0x81, 0x34, 0x8d, 0x76, 0x8d, 0xd5, 0x55, 0x8b, 0x8b, 0x24, 0x50, 0x71, - 0xa2, 0x5e, 0xdb, 0x83, 0x9b, 0xdf, 0xae, 0x07, 0x22, 0x79, 0x88, 0xa7, 0x9e, 0x08, 0xe3, 0x86, - 0x18, 0x93, 0xa3, 0xa7, 0x08, 0x17, 0x2a, 0x52, 0x9b, 0x07, 0x5d, 0x64, 0xff, 0x45, 0x2e, 0x52, - 0x85, 0x37, 0x6d, 0xd0, 0x86, 0x1c, 0xe0, 0x95, 0x50, 0x6a, 0xf3, 0x34, 0xb6, 0xe8, 0xab, 0xa8, - 0x84, 0xca, 0x2b, 0x5b, 0x1e, 0xeb, 0xb2, 0xb3, 0x61, 0x76, 0x16, 0x37, 0x83, 0x2c, 0xa0, 0x59, - 0xc6, 0xce, 0x52, 0x8f, 0x55, 0x06, 0x85, 0xd5, 0x61, 0x15, 0x52, 0xc4, 0x38, 0x12, 0x2d, 0x78, - 0x96, 0xc0, 0xa1, 0x7c, 0xbb, 0xba, 0x54, 0x42, 0xe5, 0xe5, 0xea, 0x50, 0x84, 0x32, 0xec, 0x3c, - 0x86, 0x31, 0xa6, 0x1c, 0xe9, 0x02, 0xfe, 0xaf, 0x2d, 0x7d, 0x8b, 0xb2, 0x5c, 0xcd, 0x8e, 0xd4, - 0xc3, 0x6b, 0x8f, 0x20, 0x04, 0x03, 0x8b, 0x97, 0x5c, 0xc5, 0xeb, 0xa3, 0xc9, 0x5d, 0x09, 0xbf, - 0x0a, 0x3a, 0x56, 0x91, 0x06, 0xba, 0x81, 0xaf, 0x4d, 0x1a, 0x4d, 0x45, 0xd4, 0x20, 0xdc, 0x85, - 0xe3, 0x7c, 0x44, 0xf4, 0x04, 0x6f, 0x4c, 0xcd, 0x7b, 0x2e, 0xc2, 0x36, 0xfc, 0xd3, 0x61, 0x6e, - 0xfd, 0x3a, 0x87, 0xaf, 0x8c, 0xde, 0x7d, 0x00, 0x49, 0x2a, 0xeb, 0x40, 0x3e, 0x21, 0x7c, 0x69, - 0xe2, 0xe7, 0x25, 0x2e, 0x1b, 0x71, 0x2b, 0x9b, 0x65, 0x03, 0x67, 0x9f, 0x0d, 0x7c, 0xc7, 0x72, - 0xdf, 0xd9, 0xc3, 0xab, 0xbe, 0xef, 0x58, 0xba, 0x3d, 0xc0, 0xce, 0xa3, 0x2c, 0xb7, 0x1e, 0xeb, - 0xcf, 0x45, 0x6a, 0x43, 0xe9, 0xfb, 0x6f, 0x3f, 0x4f, 0x97, 0x0a, 0xc4, 0xb1, 0xcb, 0x91, 0x7a, - 0xbc, 0x47, 0xe1, 0x0f, 0x6c, 0x4c, 0x3e, 0x22, 0x7c, 0x71, 0x82, 0x0d, 0xc8, 0xad, 0x31, 0xf4, - 0xe9, 0x66, 0x71, 0x9e, 0x9c, 0x1d, 0x38, 0x2d, 0x5b, 0x68, 0x4a, 0x4a, 0xd3, 0xa1, 0xf9, 0xbb, - 0xb6, 0xf4, 0x4f, 0xc8, 0x07, 0x84, 0x2f, 0x4f, 0x76, 0x24, 0x61, 0x63, 0xf4, 0x33, 0xad, 0xeb, - 0xdc, 0x1e, 0xcb, 0x9f, 0xe7, 0xdb, 0x1e, 0xe6, 0xcd, 0xf9, 0x98, 0x5f, 0x11, 0x5e, 0x9b, 0x69, - 0x71, 0x72, 0x67, 0x21, 0x9b, 0x8c, 0xae, 0x84, 0xb3, 0xfb, 0xf7, 0x53, 0xef, 0x6b, 0x52, 0xd7, - 0xf6, 0xb3, 0x49, 0xae, 0x4f, 0xef, 0xc7, 0x0d, 0xb3, 0x6c, 0xb7, 0x99, 0x21, 0x7f, 0x47, 0x78, - 0x7d, 0xce, 0x3e, 0x92, 0xbb, 0x8b, 0xb7, 0xf5, 0xc7, 0x06, 0x3b, 0x7b, 0x67, 0xd4, 0x58, 0x57, - 0x95, 0x72, 0xdb, 0xda, 0x0d, 0xb2, 0x39, 0xb7, 0xb5, 0xd4, 0x16, 0x3c, 0xdc, 0xff, 0xdc, 0x29, - 0xa2, 0x2f, 0x9d, 0x22, 0xfa, 0xd1, 0x29, 0xa2, 0x97, 0xf7, 0x17, 0x7f, 0x0c, 0x26, 0x3f, 0x65, - 0xb5, 0xff, 0xed, 0x33, 0xb0, 0xfd, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x42, 0xe1, 0x0d, 0xc1, 0xf2, - 0x06, 0x00, 0x00, + // 697 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x96, 0xcb, 0x6e, 0xd3, 0x4c, + 0x14, 0xc7, 0x35, 0x6d, 0xbf, 0x4f, 0x64, 0xba, 0x00, 0x06, 0x15, 0x22, 0x2b, 0x4d, 0x83, 0x05, + 0x6d, 0x28, 0x64, 0x4c, 0xda, 0xa2, 0x22, 0x24, 0x24, 0x40, 0x08, 0x24, 0x7a, 0x01, 0x25, 0x12, + 0x48, 0x6c, 0xd0, 0xd4, 0x3e, 0x4d, 0x86, 0x38, 0x1e, 0x33, 0x33, 0x71, 0xa9, 0x50, 0x37, 0xbc, + 0x42, 0x5f, 0x81, 0x87, 0x40, 0x2c, 0xba, 0x66, 0xc9, 0x65, 0xc7, 0x0a, 0x55, 0x3c, 0x08, 0xb2, + 0x1d, 0x27, 0x25, 0x76, 0x2e, 0x12, 0x65, 0x95, 0xc9, 0x99, 0x33, 0x7f, 0xff, 0xce, 0xc9, 0xf9, + 0x8f, 0x83, 0xd7, 0xfc, 0x56, 0xc3, 0x62, 0x3e, 0xb7, 0x5d, 0x0e, 0x9e, 0xb6, 0xf6, 0x84, 0x6c, + 0xed, 0xba, 0x62, 0x8f, 0x49, 0xbb, 0xc9, 0x03, 0xe8, 0x7d, 0xaf, 0x74, 0x03, 0xd4, 0x97, 0x42, + 0x0b, 0x72, 0x76, 0x20, 0xcf, 0x28, 0x34, 0x84, 0x68, 0xb8, 0x10, 0x2a, 0x59, 0xcc, 0xf3, 0x84, + 0x66, 0x9a, 0x0b, 0x4f, 0xc5, 0xe9, 0xc6, 0x5a, 0xeb, 0xb6, 0xa2, 0x5c, 0x84, 0xbb, 0x6d, 0x66, + 0x37, 0xb9, 0x07, 0x72, 0xdf, 0xea, 0x3e, 0x58, 0x59, 0x6d, 0xd0, 0xcc, 0x0a, 0xaa, 0x56, 0x03, + 0x3c, 0x90, 0x4c, 0x83, 0xd3, 0x3d, 0xb5, 0xd5, 0xe0, 0xba, 0xd9, 0xd9, 0xa1, 0xb6, 0x68, 0x5b, + 0x4c, 0x36, 0x84, 0x2f, 0xc5, 0xeb, 0x68, 0x51, 0x49, 0x9e, 0xae, 0xfa, 0x22, 0x49, 0xc8, 0x0a, + 0xaa, 0xcc, 0xf5, 0x9b, 0x2c, 0x25, 0x67, 0x1e, 0x22, 0x5c, 0xd8, 0xe4, 0x4a, 0xdf, 0x8f, 0x91, + 0x9d, 0x17, 0x89, 0x48, 0x0d, 0xde, 0x74, 0x40, 0x69, 0x52, 0xc7, 0xb3, 0x2e, 0x57, 0xfa, 0xa9, + 0x1f, 0xa1, 0xe7, 0x51, 0x09, 0x95, 0x67, 0x57, 0xaa, 0x34, 0x66, 0xa7, 0x27, 0xd9, 0xa9, 0xdf, + 0x6a, 0x84, 0x01, 0x45, 0x43, 0x76, 0x1a, 0x54, 0xe9, 0x66, 0xff, 0x60, 0xed, 0xa4, 0x0a, 0x29, + 0x62, 0xec, 0xb1, 0x36, 0x3c, 0x93, 0xb0, 0xcb, 0xdf, 0xe6, 0xa7, 0x4a, 0xa8, 0x9c, 0xab, 0x9d, + 0x88, 0x98, 0x14, 0x1b, 0x8f, 0x21, 0xc5, 0x94, 0x20, 0x9d, 0xc3, 0xd3, 0x1d, 0xee, 0x44, 0x28, + 0xb9, 0x5a, 0xb8, 0x34, 0xab, 0x78, 0xfe, 0x21, 0xb8, 0xa0, 0x61, 0xf2, 0x23, 0x97, 0xf1, 0xc2, + 0x60, 0x72, 0x2c, 0xe1, 0xd4, 0x40, 0xf9, 0xc2, 0x53, 0x60, 0x2e, 0xe2, 0x2b, 0x59, 0xad, 0xd9, + 0x64, 0x3b, 0xe0, 0x6e, 0xc0, 0x7e, 0xd2, 0x22, 0xf3, 0x00, 0x2f, 0x0e, 0xcd, 0x7b, 0xce, 0xdc, + 0x0e, 0xfc, 0xd3, 0x66, 0x9a, 0x47, 0x08, 0x17, 0x6a, 0xa0, 0xe5, 0xfe, 0xc4, 0xc5, 0x13, 0x82, + 0x67, 0xc2, 0x6e, 0x77, 0x3b, 0x1f, 0xad, 0x49, 0x01, 0xe7, 0xc2, 0x4f, 0xe5, 0x33, 0x1b, 0xf2, + 0xd3, 0xd1, 0x46, 0x3f, 0x40, 0x6e, 0xe0, 0xf3, 0x12, 0x94, 0x66, 0x52, 0xd7, 0x3b, 0xb6, 0x0d, + 0x4a, 0xed, 0x76, 0xdc, 0xfc, 0x4c, 0x09, 0x95, 0xcf, 0xd4, 0xd2, 0x1b, 0x61, 0xb6, 0x27, 0x1c, + 0x78, 0xc4, 0xc1, 0x75, 0xea, 0xe0, 0x82, 0xad, 0x85, 0xcc, 0xff, 0x17, 0x69, 0xa6, 0x37, 0x56, + 0x8e, 0x72, 0xf8, 0xd2, 0x20, 0x7b, 0x1d, 0x64, 0xc0, 0x6d, 0x20, 0x9f, 0x10, 0x9e, 0xcb, 0x9c, + 0x4f, 0x52, 0xa1, 0x03, 0x76, 0xa3, 0xa3, 0xe6, 0xd8, 0xd8, 0xa6, 0x7d, 0xe3, 0xd0, 0xc4, 0x38, + 0xd1, 0xe2, 0x55, 0xcf, 0x38, 0x34, 0x58, 0xed, 0xf7, 0x3d, 0x89, 0xd2, 0xc4, 0x3b, 0xb4, 0xf7, + 0xc3, 0x72, 0xa5, 0x4d, 0xf3, 0xfd, 0xf7, 0x5f, 0x87, 0x53, 0x05, 0x62, 0x44, 0xee, 0x0e, 0xaa, + 0x56, 0x97, 0xc2, 0xe9, 0xfb, 0x90, 0x7c, 0x44, 0xf8, 0x42, 0xc6, 0x1c, 0x93, 0xeb, 0x29, 0xf4, + 0xe1, 0xd3, 0x6e, 0x3c, 0x39, 0x3d, 0x70, 0xb3, 0x1c, 0x41, 0x9b, 0xa4, 0x34, 0x1c, 0xda, 0x7a, + 0xd7, 0xe1, 0xce, 0x01, 0xf9, 0x80, 0xf0, 0xc5, 0x6c, 0x4b, 0x11, 0x9a, 0xa2, 0x1f, 0xe9, 0x3d, + 0xe3, 0x66, 0x2a, 0x7f, 0x9c, 0xf1, 0xba, 0x98, 0xcb, 0xe3, 0x31, 0xbf, 0x21, 0x3c, 0x3f, 0xd2, + 0xa3, 0xe4, 0xd6, 0x44, 0x63, 0x32, 0xe8, 0x69, 0x63, 0xe3, 0xef, 0xbb, 0xde, 0xd3, 0x34, 0x2b, + 0x51, 0x3d, 0x4b, 0xe4, 0xea, 0xf0, 0x7a, 0x2a, 0x6e, 0x98, 0x5d, 0x69, 0x85, 0xc8, 0x3f, 0x10, + 0x5e, 0x18, 0x73, 0xa1, 0x90, 0xf5, 0xc9, 0xcb, 0xfa, 0xe3, 0x0a, 0x32, 0xb6, 0x4e, 0xa9, 0xb0, + 0x58, 0xd5, 0xb4, 0xa2, 0xd2, 0xae, 0x91, 0xa5, 0xb1, 0xa5, 0x05, 0x31, 0xf8, 0x57, 0x84, 0xe7, + 0x32, 0x6f, 0xab, 0x0c, 0x43, 0x8f, 0xba, 0xd5, 0x4e, 0xd5, 0x17, 0x77, 0xa3, 0x2a, 0xd6, 0x8d, + 0x95, 0x51, 0x03, 0xd7, 0xbb, 0x0c, 0x0f, 0xe2, 0xe1, 0xb3, 0x64, 0x88, 0x77, 0x07, 0x2d, 0x3f, + 0xd8, 0xfe, 0x7c, 0x5c, 0x44, 0x5f, 0x8e, 0x8b, 0xe8, 0xe7, 0x71, 0x11, 0xbd, 0xbc, 0x37, 0xf9, + 0x1b, 0x3a, 0xfb, 0xff, 0xc5, 0xce, 0xff, 0xd1, 0xbb, 0x79, 0xf5, 0x77, 0x00, 0x00, 0x00, 0xff, + 0xff, 0xf2, 0x1e, 0x92, 0x1c, 0x87, 0x08, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -376,6 +463,7 @@ type ArchivedWorkflowServiceClient interface { DeleteArchivedWorkflow(ctx context.Context, in *DeleteArchivedWorkflowRequest, opts ...grpc.CallOption) (*ArchivedWorkflowDeletedResponse, error) ListArchivedWorkflowLabelKeys(ctx context.Context, in *ListArchivedWorkflowLabelKeysRequest, opts ...grpc.CallOption) (*v1alpha1.LabelKeys, error) ListArchivedWorkflowLabelValues(ctx context.Context, in *ListArchivedWorkflowLabelValuesRequest, opts ...grpc.CallOption) (*v1alpha1.LabelValues, error) + RetryArchivedWorkflow(ctx context.Context, in *RetryArchivedWorkflowRequest, opts ...grpc.CallOption) (*v1alpha1.Workflow, error) } type archivedWorkflowServiceClient struct { @@ -431,6 +519,15 @@ func (c *archivedWorkflowServiceClient) ListArchivedWorkflowLabelValues(ctx cont return out, nil } +func (c *archivedWorkflowServiceClient) RetryArchivedWorkflow(ctx context.Context, in *RetryArchivedWorkflowRequest, opts ...grpc.CallOption) (*v1alpha1.Workflow, error) { + out := new(v1alpha1.Workflow) + err := c.cc.Invoke(ctx, "/workflowarchive.ArchivedWorkflowService/RetryArchivedWorkflow", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // ArchivedWorkflowServiceServer is the server API for ArchivedWorkflowService service. type ArchivedWorkflowServiceServer interface { ListArchivedWorkflows(context.Context, *ListArchivedWorkflowsRequest) (*v1alpha1.WorkflowList, error) @@ -438,6 +535,7 @@ type ArchivedWorkflowServiceServer interface { DeleteArchivedWorkflow(context.Context, *DeleteArchivedWorkflowRequest) (*ArchivedWorkflowDeletedResponse, error) ListArchivedWorkflowLabelKeys(context.Context, *ListArchivedWorkflowLabelKeysRequest) (*v1alpha1.LabelKeys, error) ListArchivedWorkflowLabelValues(context.Context, *ListArchivedWorkflowLabelValuesRequest) (*v1alpha1.LabelValues, error) + RetryArchivedWorkflow(context.Context, *RetryArchivedWorkflowRequest) (*v1alpha1.Workflow, error) } // UnimplementedArchivedWorkflowServiceServer can be embedded to have forward compatible implementations. @@ -459,6 +557,9 @@ func (*UnimplementedArchivedWorkflowServiceServer) ListArchivedWorkflowLabelKeys func (*UnimplementedArchivedWorkflowServiceServer) ListArchivedWorkflowLabelValues(ctx context.Context, req *ListArchivedWorkflowLabelValuesRequest) (*v1alpha1.LabelValues, error) { return nil, status.Errorf(codes.Unimplemented, "method ListArchivedWorkflowLabelValues not implemented") } +func (*UnimplementedArchivedWorkflowServiceServer) RetryArchivedWorkflow(ctx context.Context, req *RetryArchivedWorkflowRequest) (*v1alpha1.Workflow, error) { + return nil, status.Errorf(codes.Unimplemented, "method RetryArchivedWorkflow not implemented") +} func RegisterArchivedWorkflowServiceServer(s *grpc.Server, srv ArchivedWorkflowServiceServer) { s.RegisterService(&_ArchivedWorkflowService_serviceDesc, srv) @@ -554,6 +655,24 @@ func _ArchivedWorkflowService_ListArchivedWorkflowLabelValues_Handler(srv interf return interceptor(ctx, in, info, handler) } +func _ArchivedWorkflowService_RetryArchivedWorkflow_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RetryArchivedWorkflowRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ArchivedWorkflowServiceServer).RetryArchivedWorkflow(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/workflowarchive.ArchivedWorkflowService/RetryArchivedWorkflow", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ArchivedWorkflowServiceServer).RetryArchivedWorkflow(ctx, req.(*RetryArchivedWorkflowRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _ArchivedWorkflowService_serviceDesc = grpc.ServiceDesc{ ServiceName: "workflowarchive.ArchivedWorkflowService", HandlerType: (*ArchivedWorkflowServiceServer)(nil), @@ -578,6 +697,10 @@ var _ArchivedWorkflowService_serviceDesc = grpc.ServiceDesc{ MethodName: "ListArchivedWorkflowLabelValues", Handler: _ArchivedWorkflowService_ListArchivedWorkflowLabelValues_Handler, }, + { + MethodName: "RetryArchivedWorkflow", + Handler: _ArchivedWorkflowService_RetryArchivedWorkflow_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "pkg/apiclient/workflowarchive/workflow-archive.proto", @@ -790,6 +913,71 @@ func (m *ListArchivedWorkflowLabelValuesRequest) MarshalToSizedBuffer(dAtA []byt return len(dAtA) - i, nil } +func (m *RetryArchivedWorkflowRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *RetryArchivedWorkflowRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *RetryArchivedWorkflowRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.XXX_unrecognized != nil { + i -= len(m.XXX_unrecognized) + copy(dAtA[i:], m.XXX_unrecognized) + } + if len(m.NodeFieldSelector) > 0 { + i -= len(m.NodeFieldSelector) + copy(dAtA[i:], m.NodeFieldSelector) + i = encodeVarintWorkflowArchive(dAtA, i, uint64(len(m.NodeFieldSelector))) + i-- + dAtA[i] = 0x2a + } + if m.RestartSuccessful { + i-- + if m.RestartSuccessful { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + } + if len(m.Namespace) > 0 { + i -= len(m.Namespace) + copy(dAtA[i:], m.Namespace) + i = encodeVarintWorkflowArchive(dAtA, i, uint64(len(m.Namespace))) + i-- + dAtA[i] = 0x1a + } + if len(m.Name) > 0 { + i -= len(m.Name) + copy(dAtA[i:], m.Name) + i = encodeVarintWorkflowArchive(dAtA, i, uint64(len(m.Name))) + i-- + dAtA[i] = 0x12 + } + if len(m.Uid) > 0 { + i -= len(m.Uid) + copy(dAtA[i:], m.Uid) + i = encodeVarintWorkflowArchive(dAtA, i, uint64(len(m.Uid))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintWorkflowArchive(dAtA []byte, offset int, v uint64) int { offset -= sovWorkflowArchive(v) base := offset @@ -893,6 +1081,37 @@ func (m *ListArchivedWorkflowLabelValuesRequest) Size() (n int) { return n } +func (m *RetryArchivedWorkflowRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Uid) + if l > 0 { + n += 1 + l + sovWorkflowArchive(uint64(l)) + } + l = len(m.Name) + if l > 0 { + n += 1 + l + sovWorkflowArchive(uint64(l)) + } + l = len(m.Namespace) + if l > 0 { + n += 1 + l + sovWorkflowArchive(uint64(l)) + } + if m.RestartSuccessful { + n += 2 + } + l = len(m.NodeFieldSelector) + if l > 0 { + n += 1 + l + sovWorkflowArchive(uint64(l)) + } + if m.XXX_unrecognized != nil { + n += len(m.XXX_unrecognized) + } + return n +} + func sovWorkflowArchive(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1373,6 +1592,205 @@ func (m *ListArchivedWorkflowLabelValuesRequest) Unmarshal(dAtA []byte) error { } return nil } +func (m *RetryArchivedWorkflowRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWorkflowArchive + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: RetryArchivedWorkflowRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: RetryArchivedWorkflowRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Uid", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWorkflowArchive + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthWorkflowArchive + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthWorkflowArchive + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Uid = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWorkflowArchive + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthWorkflowArchive + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthWorkflowArchive + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Name = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Namespace", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWorkflowArchive + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthWorkflowArchive + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthWorkflowArchive + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Namespace = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field RestartSuccessful", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWorkflowArchive + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.RestartSuccessful = bool(v != 0) + case 5: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NodeFieldSelector", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowWorkflowArchive + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthWorkflowArchive + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthWorkflowArchive + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NodeFieldSelector = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipWorkflowArchive(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthWorkflowArchive + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + m.XXX_unrecognized = append(m.XXX_unrecognized, dAtA[iNdEx:iNdEx+skippy]...) + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipWorkflowArchive(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/pkg/apiclient/workflowarchive/workflow-archive.pb.gw.go b/pkg/apiclient/workflowarchive/workflow-archive.pb.gw.go index 0eca7512003c..d7b1311722dc 100644 --- a/pkg/apiclient/workflowarchive/workflow-archive.pb.gw.go +++ b/pkg/apiclient/workflowarchive/workflow-archive.pb.gw.go @@ -231,6 +231,98 @@ func local_request_ArchivedWorkflowService_ListArchivedWorkflowLabelValues_0(ctx } +func request_ArchivedWorkflowService_RetryArchivedWorkflow_0(ctx context.Context, marshaler runtime.Marshaler, client ArchivedWorkflowServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq RetryArchivedWorkflowRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["namespace"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") + } + + protoReq.Namespace, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) + } + + val, ok = pathParams["uid"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "uid") + } + + protoReq.Uid, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "uid", err) + } + + msg, err := client.RetryArchivedWorkflow(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_ArchivedWorkflowService_RetryArchivedWorkflow_0(ctx context.Context, marshaler runtime.Marshaler, server ArchivedWorkflowServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq RetryArchivedWorkflowRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["namespace"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") + } + + protoReq.Namespace, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) + } + + val, ok = pathParams["uid"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "uid") + } + + protoReq.Uid, err = runtime.String(val) + + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "uid", err) + } + + msg, err := server.RetryArchivedWorkflow(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterArchivedWorkflowServiceHandlerServer registers the http handlers for service ArchivedWorkflowService to "mux". // UnaryRPC :call ArchivedWorkflowServiceServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -352,6 +444,29 @@ func RegisterArchivedWorkflowServiceHandlerServer(ctx context.Context, mux *runt }) + mux.Handle("PUT", pattern_ArchivedWorkflowService_RetryArchivedWorkflow_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_ArchivedWorkflowService_RetryArchivedWorkflow_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ArchivedWorkflowService_RetryArchivedWorkflow_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -493,6 +608,26 @@ func RegisterArchivedWorkflowServiceHandlerClient(ctx context.Context, mux *runt }) + mux.Handle("PUT", pattern_ArchivedWorkflowService_RetryArchivedWorkflow_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_ArchivedWorkflowService_RetryArchivedWorkflow_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_ArchivedWorkflowService_RetryArchivedWorkflow_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -506,6 +641,8 @@ var ( pattern_ArchivedWorkflowService_ListArchivedWorkflowLabelKeys_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "archived-workflows-label-keys"}, "", runtime.AssumeColonVerbOpt(true))) pattern_ArchivedWorkflowService_ListArchivedWorkflowLabelValues_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "archived-workflows-label-values"}, "", runtime.AssumeColonVerbOpt(true))) + + pattern_ArchivedWorkflowService_RetryArchivedWorkflow_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"api", "v1", "archived-workflows", "namespace", "uid", "retry"}, "", runtime.AssumeColonVerbOpt(true))) ) var ( @@ -518,4 +655,6 @@ var ( forward_ArchivedWorkflowService_ListArchivedWorkflowLabelKeys_0 = runtime.ForwardResponseMessage forward_ArchivedWorkflowService_ListArchivedWorkflowLabelValues_0 = runtime.ForwardResponseMessage + + forward_ArchivedWorkflowService_RetryArchivedWorkflow_0 = runtime.ForwardResponseMessage ) diff --git a/pkg/apiclient/workflowarchive/workflow-archive.proto b/pkg/apiclient/workflowarchive/workflow-archive.proto index e520d0afa021..1996e4d20724 100644 --- a/pkg/apiclient/workflowarchive/workflow-archive.proto +++ b/pkg/apiclient/workflowarchive/workflow-archive.proto @@ -24,6 +24,18 @@ message ListArchivedWorkflowLabelKeysRequest { message ListArchivedWorkflowLabelValuesRequest { k8s.io.apimachinery.pkg.apis.meta.v1.ListOptions listOptions = 1; } +message RetryArchivedWorkflowRequest { + string uid = 1; + string name = 2; + string namespace = 3; + bool restartSuccessful = 4; + string nodeFieldSelector = 5; +} +// message ResubmitArchivedWorkflowRequest { +// string uid = 1; +// string name = 2; +// string namespace = 3; +// } service ArchivedWorkflowService { rpc ListArchivedWorkflows (ListArchivedWorkflowsRequest) returns (github.com.argoproj.argo_workflows.v3.pkg.apis.workflow.v1alpha1.WorkflowList) { @@ -41,4 +53,16 @@ service ArchivedWorkflowService { rpc ListArchivedWorkflowLabelValues (ListArchivedWorkflowLabelValuesRequest) returns (github.com.argoproj.argo_workflows.v3.pkg.apis.workflow.v1alpha1.LabelValues) { option (google.api.http).get = "/api/v1/archived-workflows-label-values"; } + rpc RetryArchivedWorkflow (RetryArchivedWorkflowRequest) returns (github.com.argoproj.argo_workflows.v3.pkg.apis.workflow.v1alpha1.Workflow) { + option (google.api.http) = { + put: "/api/v1/archived-workflows/{namespace}/{uid}/retry" + body: "*" + }; + } + // rpc ResubmitArchivedWorkflow (ResubmitArchivedWorkflowRequest) returns (github.com.argoproj.argo_workflows.v3.pkg.apis.workflow.v1alpha1.Workflow) { + // option (google.api.http) = { + // put: "/api/v1/archived-workflows/{namespace}/{name}/resubmit" + // body: "*" + // }; + // } } diff --git a/sdks/java/client/docs/ArchivedWorkflowServiceApi.md b/sdks/java/client/docs/ArchivedWorkflowServiceApi.md index d55cba1d801a..74a276dc26bb 100644 --- a/sdks/java/client/docs/ArchivedWorkflowServiceApi.md +++ b/sdks/java/client/docs/ArchivedWorkflowServiceApi.md @@ -9,6 +9,7 @@ Method | HTTP request | Description [**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 | +[**archivedWorkflowServiceRetryArchivedWorkflow**](ArchivedWorkflowServiceApi.md#archivedWorkflowServiceRetryArchivedWorkflow) | **PUT** /api/v1/archived-workflows/{namespace}/{uid}/retry | @@ -346,3 +347,68 @@ No authorization required **200** | A successful response. | - | **0** | An unexpected error response. | - | + +# **archivedWorkflowServiceRetryArchivedWorkflow** +> IoArgoprojWorkflowV1alpha1Workflow archivedWorkflowServiceRetryArchivedWorkflow(namespace, uid, body) + + + +### 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 namespace = "namespace_example"; // String | + String uid = "uid_example"; // String | + IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest body = new IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest(); // IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest | + try { + IoArgoprojWorkflowV1alpha1Workflow result = apiInstance.archivedWorkflowServiceRetryArchivedWorkflow(namespace, uid, body); + System.out.println(result); + } catch (ApiException e) { + System.err.println("Exception when calling ArchivedWorkflowServiceApi#archivedWorkflowServiceRetryArchivedWorkflow"); + 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 +------------- | ------------- | ------------- | ------------- + **namespace** | **String**| | + **uid** | **String**| | + **body** | [**IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest**](IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest.md)| | + +### Return type + +[**IoArgoprojWorkflowV1alpha1Workflow**](IoArgoprojWorkflowV1alpha1Workflow.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + +### HTTP response details +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**200** | A successful response. | - | +**0** | An unexpected error response. | - | + diff --git a/sdks/java/client/docs/IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest.md b/sdks/java/client/docs/IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest.md new file mode 100644 index 000000000000..35be45e7a99d --- /dev/null +++ b/sdks/java/client/docs/IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest.md @@ -0,0 +1,17 @@ + + +# IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest + + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**name** | **String** | | [optional] +**namespace** | **String** | | [optional] +**nodeFieldSelector** | **String** | | [optional] +**restartSuccessful** | **Boolean** | | [optional] +**uid** | **String** | | [optional] + + + diff --git a/sdks/python/client/argo_workflows/api/archived_workflow_service_api.py b/sdks/python/client/argo_workflows/api/archived_workflow_service_api.py index a8fda09ae5b0..f3dbb19d514d 100644 --- a/sdks/python/client/argo_workflows/api/archived_workflow_service_api.py +++ b/sdks/python/client/argo_workflows/api/archived_workflow_service_api.py @@ -24,6 +24,7 @@ from argo_workflows.model.grpc_gateway_runtime_error import GrpcGatewayRuntimeError from argo_workflows.model.io_argoproj_workflow_v1alpha1_label_keys import IoArgoprojWorkflowV1alpha1LabelKeys from argo_workflows.model.io_argoproj_workflow_v1alpha1_label_values import IoArgoprojWorkflowV1alpha1LabelValues +from argo_workflows.model.io_argoproj_workflow_v1alpha1_retry_archived_workflow_request import IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest from argo_workflows.model.io_argoproj_workflow_v1alpha1_workflow import IoArgoprojWorkflowV1alpha1Workflow from argo_workflows.model.io_argoproj_workflow_v1alpha1_workflow_list import IoArgoprojWorkflowV1alpha1WorkflowList @@ -697,3 +698,140 @@ def __list_archived_workflows( api_client=api_client, callable=__list_archived_workflows ) + + def __retry_archived_workflow( + self, + namespace, + uid, + body, + **kwargs + ): + """retry_archived_workflow # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + + >>> thread = api.retry_archived_workflow(namespace, uid, body, async_req=True) + >>> result = thread.get() + + Args: + namespace (str): + uid (str): + body (IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest): + + Keyword Args: + _return_http_data_only (bool): response data without head status + code and headers. Default is True. + _preload_content (bool): if False, the urllib3.HTTPResponse object + will be returned without reading/decoding response data. + Default is True. + _request_timeout (int/float/tuple): timeout setting for this request. If + one number provided, it will be total request timeout. It can also + be a pair (tuple) of (connection, read) timeouts. + Default is None. + _check_input_type (bool): specifies if type checking + should be done one the data sent to the server. + Default is True. + _check_return_type (bool): specifies if type checking + should be done one the data received from the server. + Default is True. + _host_index (int/None): specifies the index of the server + that we want to use. + Default is read from the configuration. + async_req (bool): execute request asynchronously + + Returns: + IoArgoprojWorkflowV1alpha1Workflow + If the method is called asynchronously, returns the request + thread. + """ + kwargs['async_req'] = kwargs.get( + 'async_req', False + ) + kwargs['_return_http_data_only'] = kwargs.get( + '_return_http_data_only', True + ) + kwargs['_preload_content'] = kwargs.get( + '_preload_content', True + ) + kwargs['_request_timeout'] = kwargs.get( + '_request_timeout', None + ) + kwargs['_check_input_type'] = kwargs.get( + '_check_input_type', True + ) + kwargs['_check_return_type'] = kwargs.get( + '_check_return_type', True + ) + kwargs['_host_index'] = kwargs.get('_host_index') + kwargs['namespace'] = \ + namespace + kwargs['uid'] = \ + uid + kwargs['body'] = \ + body + return self.call_with_http_info(**kwargs) + + self.retry_archived_workflow = _Endpoint( + settings={ + 'response_type': (IoArgoprojWorkflowV1alpha1Workflow,), + 'auth': [], + 'endpoint_path': '/api/v1/archived-workflows/{namespace}/{uid}/retry', + 'operation_id': 'retry_archived_workflow', + 'http_method': 'PUT', + 'servers': None, + }, + params_map={ + 'all': [ + 'namespace', + 'uid', + 'body', + ], + 'required': [ + 'namespace', + 'uid', + 'body', + ], + 'nullable': [ + ], + 'enum': [ + ], + 'validation': [ + ] + }, + root_map={ + 'validations': { + }, + 'allowed_values': { + }, + 'openapi_types': { + 'namespace': + (str,), + 'uid': + (str,), + 'body': + (IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest,), + }, + 'attribute_map': { + 'namespace': 'namespace', + 'uid': 'uid', + }, + 'location_map': { + 'namespace': 'path', + 'uid': 'path', + 'body': 'body', + }, + 'collection_format_map': { + } + }, + headers_map={ + 'accept': [ + 'application/json' + ], + 'content_type': [ + 'application/json' + ] + }, + api_client=api_client, + callable=__retry_archived_workflow + ) diff --git a/sdks/python/client/argo_workflows/model/io_argoproj_workflow_v1alpha1_retry_archived_workflow_request.py b/sdks/python/client/argo_workflows/model/io_argoproj_workflow_v1alpha1_retry_archived_workflow_request.py new file mode 100644 index 000000000000..cdb9740e3312 --- /dev/null +++ b/sdks/python/client/argo_workflows/model/io_argoproj_workflow_v1alpha1_retry_archived_workflow_request.py @@ -0,0 +1,271 @@ +""" + Argo Workflows API + + Argo Workflows is an open source container-native workflow engine for orchestrating parallel jobs on Kubernetes. For more information, please see https://argoproj.github.io/argo-workflows/ # noqa: E501 + + The version of the OpenAPI document: VERSION + Generated by: https://openapi-generator.tech +""" + + +import re # noqa: F401 +import sys # noqa: F401 + +from argo_workflows.model_utils import ( # noqa: F401 + ApiTypeError, + ModelComposed, + ModelNormal, + ModelSimple, + cached_property, + change_keys_js_to_python, + convert_js_args_to_python_args, + date, + datetime, + file_type, + none_type, + validate_get_composed_info, +) +from ..model_utils import OpenApiModel +from argo_workflows.exceptions import ApiAttributeError + + + +class IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest(ModelNormal): + """NOTE: This class is auto generated by OpenAPI Generator. + Ref: https://openapi-generator.tech + + Do not edit the class manually. + + Attributes: + allowed_values (dict): The key is the tuple path to the attribute + and the for var_name this is (var_name,). The value is a dict + with a capitalized key describing the allowed value and an allowed + value. These dicts store the allowed enum values. + attribute_map (dict): The key is attribute name + and the value is json key in definition. + discriminator_value_class_map (dict): A dict to go from the discriminator + variable value to the discriminator class name. + validations (dict): The key is the tuple path to the attribute + and the for var_name this is (var_name,). The value is a dict + that stores validations for max_length, min_length, max_items, + min_items, exclusive_maximum, inclusive_maximum, exclusive_minimum, + inclusive_minimum, and regex. + additional_properties_type (tuple): A tuple of classes accepted + as additional properties values. + """ + + allowed_values = { + } + + validations = { + } + + @cached_property + def additional_properties_type(): + """ + This must be a method because a model may have properties that are + of type self, this must run after the class is loaded + """ + return (bool, date, datetime, dict, float, int, list, str, none_type,) # noqa: E501 + + _nullable = False + + @cached_property + def openapi_types(): + """ + This must be a method because a model may have properties that are + of type self, this must run after the class is loaded + + Returns + openapi_types (dict): The key is attribute name + and the value is attribute type. + """ + return { + 'name': (str,), # noqa: E501 + 'namespace': (str,), # noqa: E501 + 'node_field_selector': (str,), # noqa: E501 + 'restart_successful': (bool,), # noqa: E501 + 'uid': (str,), # noqa: E501 + } + + @cached_property + def discriminator(): + return None + + + attribute_map = { + 'name': 'name', # noqa: E501 + 'namespace': 'namespace', # noqa: E501 + 'node_field_selector': 'nodeFieldSelector', # noqa: E501 + 'restart_successful': 'restartSuccessful', # noqa: E501 + 'uid': 'uid', # noqa: E501 + } + + read_only_vars = { + } + + _composed_schemas = {} + + @classmethod + @convert_js_args_to_python_args + def _from_openapi_data(cls, *args, **kwargs): # noqa: E501 + """IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest - a model defined in OpenAPI + + Keyword Args: + _check_type (bool): if True, values for parameters in openapi_types + will be type checked and a TypeError will be + raised if the wrong type is input. + Defaults to True + _path_to_item (tuple/list): This is a list of keys or values to + drill down to the model in received_data + when deserializing a response + _spec_property_naming (bool): True if the variable names in the input data + are serialized names, as specified in the OpenAPI document. + False if the variable names in the input data + are pythonic names, e.g. snake case (default) + _configuration (Configuration): the instance to use when + deserializing a file_type parameter. + If passed, type conversion is attempted + If omitted no type conversion is done. + _visited_composed_classes (tuple): This stores a tuple of + classes that we have traveled through so that + if we see that class again we will not use its + discriminator again. + When traveling through a discriminator, the + composed schema that is + is traveled through is added to this set. + For example if Animal has a discriminator + petType and we pass in "Dog", and the class Dog + allOf includes Animal, we move through Animal + once using the discriminator, and pick Dog. + Then in Dog, we will make an instance of the + Animal class but this time we won't travel + through its discriminator because we passed in + _visited_composed_classes = (Animal,) + name (str): [optional] # noqa: E501 + namespace (str): [optional] # noqa: E501 + node_field_selector (str): [optional] # noqa: E501 + restart_successful (bool): [optional] # noqa: E501 + uid (str): [optional] # noqa: E501 + """ + + _check_type = kwargs.pop('_check_type', True) + _spec_property_naming = kwargs.pop('_spec_property_naming', False) + _path_to_item = kwargs.pop('_path_to_item', ()) + _configuration = kwargs.pop('_configuration', None) + _visited_composed_classes = kwargs.pop('_visited_composed_classes', ()) + + self = super(OpenApiModel, cls).__new__(cls) + + if args: + raise ApiTypeError( + "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % ( + args, + self.__class__.__name__, + ), + path_to_item=_path_to_item, + valid_classes=(self.__class__,), + ) + + self._data_store = {} + self._check_type = _check_type + self._spec_property_naming = _spec_property_naming + self._path_to_item = _path_to_item + self._configuration = _configuration + self._visited_composed_classes = _visited_composed_classes + (self.__class__,) + + for var_name, var_value in kwargs.items(): + if var_name not in self.attribute_map and \ + self._configuration is not None and \ + self._configuration.discard_unknown_keys and \ + self.additional_properties_type is None: + # discard variable. + continue + setattr(self, var_name, var_value) + return self + + required_properties = set([ + '_data_store', + '_check_type', + '_spec_property_naming', + '_path_to_item', + '_configuration', + '_visited_composed_classes', + ]) + + @convert_js_args_to_python_args + def __init__(self, *args, **kwargs): # noqa: E501 + """IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest - a model defined in OpenAPI + + Keyword Args: + _check_type (bool): if True, values for parameters in openapi_types + will be type checked and a TypeError will be + raised if the wrong type is input. + Defaults to True + _path_to_item (tuple/list): This is a list of keys or values to + drill down to the model in received_data + when deserializing a response + _spec_property_naming (bool): True if the variable names in the input data + are serialized names, as specified in the OpenAPI document. + False if the variable names in the input data + are pythonic names, e.g. snake case (default) + _configuration (Configuration): the instance to use when + deserializing a file_type parameter. + If passed, type conversion is attempted + If omitted no type conversion is done. + _visited_composed_classes (tuple): This stores a tuple of + classes that we have traveled through so that + if we see that class again we will not use its + discriminator again. + When traveling through a discriminator, the + composed schema that is + is traveled through is added to this set. + For example if Animal has a discriminator + petType and we pass in "Dog", and the class Dog + allOf includes Animal, we move through Animal + once using the discriminator, and pick Dog. + Then in Dog, we will make an instance of the + Animal class but this time we won't travel + through its discriminator because we passed in + _visited_composed_classes = (Animal,) + name (str): [optional] # noqa: E501 + namespace (str): [optional] # noqa: E501 + node_field_selector (str): [optional] # noqa: E501 + restart_successful (bool): [optional] # noqa: E501 + uid (str): [optional] # noqa: E501 + """ + + _check_type = kwargs.pop('_check_type', True) + _spec_property_naming = kwargs.pop('_spec_property_naming', False) + _path_to_item = kwargs.pop('_path_to_item', ()) + _configuration = kwargs.pop('_configuration', None) + _visited_composed_classes = kwargs.pop('_visited_composed_classes', ()) + + if args: + raise ApiTypeError( + "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % ( + args, + self.__class__.__name__, + ), + path_to_item=_path_to_item, + valid_classes=(self.__class__,), + ) + + self._data_store = {} + self._check_type = _check_type + self._spec_property_naming = _spec_property_naming + self._path_to_item = _path_to_item + self._configuration = _configuration + self._visited_composed_classes = _visited_composed_classes + (self.__class__,) + + for var_name, var_value in kwargs.items(): + if var_name not in self.attribute_map and \ + self._configuration is not None and \ + self._configuration.discard_unknown_keys and \ + self.additional_properties_type is None: + # discard variable. + continue + setattr(self, var_name, var_value) + if var_name in self.read_only_vars: + raise ApiAttributeError(f"`{var_name}` is a read-only attribute. Use `from_openapi_data` to instantiate " + f"class with read only attributes.") diff --git a/sdks/python/client/argo_workflows/models/__init__.py b/sdks/python/client/argo_workflows/models/__init__.py index db38693d5298..52e5bebe1dca 100644 --- a/sdks/python/client/argo_workflows/models/__init__.py +++ b/sdks/python/client/argo_workflows/models/__init__.py @@ -290,6 +290,7 @@ from argo_workflows.model.io_argoproj_workflow_v1alpha1_raw_artifact import IoArgoprojWorkflowV1alpha1RawArtifact from argo_workflows.model.io_argoproj_workflow_v1alpha1_resource_template import IoArgoprojWorkflowV1alpha1ResourceTemplate from argo_workflows.model.io_argoproj_workflow_v1alpha1_retry_affinity import IoArgoprojWorkflowV1alpha1RetryAffinity +from argo_workflows.model.io_argoproj_workflow_v1alpha1_retry_archived_workflow_request import IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest from argo_workflows.model.io_argoproj_workflow_v1alpha1_retry_strategy import IoArgoprojWorkflowV1alpha1RetryStrategy from argo_workflows.model.io_argoproj_workflow_v1alpha1_s3_artifact import IoArgoprojWorkflowV1alpha1S3Artifact from argo_workflows.model.io_argoproj_workflow_v1alpha1_s3_artifact_repository import IoArgoprojWorkflowV1alpha1S3ArtifactRepository diff --git a/sdks/python/client/docs/ArchivedWorkflowServiceApi.md b/sdks/python/client/docs/ArchivedWorkflowServiceApi.md index 8bd1555f0257..f5576f3cbca4 100644 --- a/sdks/python/client/docs/ArchivedWorkflowServiceApi.md +++ b/sdks/python/client/docs/ArchivedWorkflowServiceApi.md @@ -9,6 +9,7 @@ Method | HTTP request | Description [**list_archived_workflow_label_keys**](ArchivedWorkflowServiceApi.md#list_archived_workflow_label_keys) | **GET** /api/v1/archived-workflows-label-keys | [**list_archived_workflow_label_values**](ArchivedWorkflowServiceApi.md#list_archived_workflow_label_values) | **GET** /api/v1/archived-workflows-label-values | [**list_archived_workflows**](ArchivedWorkflowServiceApi.md#list_archived_workflows) | **GET** /api/v1/archived-workflows | +[**retry_archived_workflow**](ArchivedWorkflowServiceApi.md#retry_archived_workflow) | **PUT** /api/v1/archived-workflows/{namespace}/{uid}/retry | # **delete_archived_workflow** @@ -362,3 +363,78 @@ No authorization required [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +# **retry_archived_workflow** +> IoArgoprojWorkflowV1alpha1Workflow retry_archived_workflow(namespace, uid, body) + + + +### Example + +```python +import time +import argo_workflows +from argo_workflows.api import archived_workflow_service_api +from argo_workflows.model.grpc_gateway_runtime_error import GrpcGatewayRuntimeError +from argo_workflows.model.io_argoproj_workflow_v1alpha1_workflow import IoArgoprojWorkflowV1alpha1Workflow +from argo_workflows.model.io_argoproj_workflow_v1alpha1_retry_archived_workflow_request import IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest +from pprint import pprint +# Defining the host is optional and defaults to http://localhost:2746 +# See configuration.py for a list of all supported configuration parameters. +configuration = argo_workflows.Configuration( + host = "http://localhost:2746" +) + + +# Enter a context with an instance of the API client +with argo_workflows.ApiClient() as api_client: + # Create an instance of the API class + api_instance = archived_workflow_service_api.ArchivedWorkflowServiceApi(api_client) + namespace = "namespace_example" # str | + uid = "uid_example" # str | + body = IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest( + name="name_example", + namespace="namespace_example", + node_field_selector="node_field_selector_example", + restart_successful=True, + uid="uid_example", + ) # IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest | + + # example passing only required values which don't have defaults set + try: + api_response = api_instance.retry_archived_workflow(namespace, uid, body) + pprint(api_response) + except argo_workflows.ApiException as e: + print("Exception when calling ArchivedWorkflowServiceApi->retry_archived_workflow: %s\n" % e) +``` + + +### Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **namespace** | **str**| | + **uid** | **str**| | + **body** | [**IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest**](IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest.md)| | + +### Return type + +[**IoArgoprojWorkflowV1alpha1Workflow**](IoArgoprojWorkflowV1alpha1Workflow.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: application/json + + +### HTTP response details +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**200** | A successful response. | - | +**0** | An unexpected error response. | - | + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/sdks/python/client/docs/IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest.md b/sdks/python/client/docs/IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest.md new file mode 100644 index 000000000000..18ed50d3f9f2 --- /dev/null +++ b/sdks/python/client/docs/IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest.md @@ -0,0 +1,16 @@ +# IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest + + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**name** | **str** | | [optional] +**namespace** | **str** | | [optional] +**node_field_selector** | **str** | | [optional] +**restart_successful** | **bool** | | [optional] +**uid** | **str** | | [optional] +**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/server/apiserver/argoserver.go b/server/apiserver/argoserver.go index d1f0d0f333fe..f1bae87f978c 100644 --- a/server/apiserver/argoserver.go +++ b/server/apiserver/argoserver.go @@ -287,7 +287,7 @@ func (as *argoServer) newGRPCServer(instanceIDService instanceid.Service, offloa workflowpkg.RegisterWorkflowServiceServer(grpcServer, workflow.NewWorkflowServer(instanceIDService, offloadNodeStatusRepo)) workflowtemplatepkg.RegisterWorkflowTemplateServiceServer(grpcServer, workflowtemplate.NewWorkflowTemplateServer(instanceIDService)) cronworkflowpkg.RegisterCronWorkflowServiceServer(grpcServer, cronworkflow.NewCronWorkflowServer(instanceIDService)) - workflowarchivepkg.RegisterArchivedWorkflowServiceServer(grpcServer, workflowarchive.NewWorkflowArchiveServer(wfArchive)) + workflowarchivepkg.RegisterArchivedWorkflowServiceServer(grpcServer, workflowarchive.NewWorkflowArchiveServer(wfArchive, offloadNodeStatusRepo)) clusterwftemplatepkg.RegisterClusterWorkflowTemplateServiceServer(grpcServer, clusterworkflowtemplate.NewClusterWorkflowTemplateServer(instanceIDService)) grpc_prometheus.Register(grpcServer) return grpcServer diff --git a/server/workflowarchive/archived_workflow_server.go b/server/workflowarchive/archived_workflow_server.go index ae0c2a9e4722..559881813da8 100644 --- a/server/workflowarchive/archived_workflow_server.go +++ b/server/workflowarchive/archived_workflow_server.go @@ -19,17 +19,25 @@ import ( "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow" wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" "github.com/argoproj/argo-workflows/v3/server/auth" + "github.com/argoproj/argo-workflows/v3/workflow/hydrator" + "github.com/argoproj/argo-workflows/v3/workflow/util" ) type archivedWorkflowServer struct { - wfArchive sqldb.WorkflowArchive + wfArchive sqldb.WorkflowArchive + offloadNodeStatusRepo sqldb.OffloadNodeStatusRepo + hydrator hydrator.Interface } // NewWorkflowArchiveServer returns a new archivedWorkflowServer -func NewWorkflowArchiveServer(wfArchive sqldb.WorkflowArchive) workflowarchivepkg.ArchivedWorkflowServiceServer { - return &archivedWorkflowServer{wfArchive: wfArchive} +func NewWorkflowArchiveServer(wfArchive sqldb.WorkflowArchive, offloadNodeStatusRepo sqldb.OffloadNodeStatusRepo) workflowarchivepkg.ArchivedWorkflowServiceServer { + return &archivedWorkflowServer{wfArchive: wfArchive, offloadNodeStatusRepo: offloadNodeStatusRepo, hydrator: hydrator.New(offloadNodeStatusRepo)} } +// func NewWorkflowServer(instanceIDService instanceid.Service, offloadNodeStatusRepo sqldb.OffloadNodeStatusRepo) workflowpkg.WorkflowServiceServer { +// return &workflowServer{instanceIDService, offloadNodeStatusRepo, hydrator.New(offloadNodeStatusRepo)} +// } + func (w *archivedWorkflowServer) ListArchivedWorkflows(ctx context.Context, req *workflowarchivepkg.ListArchivedWorkflowsRequest) (*wfv1.WorkflowList, error) { options := req.ListOptions namePrefix := req.NamePrefix @@ -188,3 +196,26 @@ func (w *archivedWorkflowServer) ListArchivedWorkflowLabelValues(ctx context.Con } return labels, err } + +func (w *archivedWorkflowServer) RetryArchivedWorkflow(ctx context.Context, req *workflowarchivepkg.RetryArchivedWorkflowRequest) (*wfv1.Workflow, error) { + wfClient := auth.GetWfClient(ctx) + kubeClient := auth.GetKubeClient(ctx) + + wf, err := w.wfArchive.GetWorkflow(req.Uid) + if err != nil { + return nil, err + } + + err = w.wfArchive.ValidateWorkflow(wf) + if err != nil { + return nil, err + } + + // retry archive workflow needs wf passed + + wf, err = util.RetryArchiveWorkflow(ctx, kubeClient, w.hydrator, wfClient.ArgoprojV1alpha1().Workflows(req.Namespace), wf, wf.Name, req.RestartSuccessful, req.NodeFieldSelector) + if err != nil { + return nil, err + } + return wf, nil +} diff --git a/server/workflowarchive/archived_workflow_server_test.go b/server/workflowarchive/archived_workflow_server_test.go index b05fdfd910bb..0d07466787e3 100644 --- a/server/workflowarchive/archived_workflow_server_test.go +++ b/server/workflowarchive/archived_workflow_server_test.go @@ -27,7 +27,10 @@ func Test_archivedWorkflowServer(t *testing.T) { repo := &mocks.WorkflowArchive{} kubeClient := &kubefake.Clientset{} wfClient := &argofake.Clientset{} - w := NewWorkflowArchiveServer(repo) + offloadNodeStatusRepo := &mocks.OffloadNodeStatusRepo{} + // offloadNodeStatusRepo.On("IsEnabled", mock.Anything).Return(true) + // offloadNodeStatusRepo.On("List", mock.Anything).Return(map[sqldb.UUIDVersion]v1alpha1.Nodes{}, nil) + w := NewWorkflowArchiveServer(repo, offloadNodeStatusRepo) allowed := true kubeClient.AddReactor("create", "selfsubjectaccessreviews", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { return true, &authorizationv1.SelfSubjectAccessReview{ diff --git a/workflow/util/util.go b/workflow/util/util.go index a713c85b5937..db21019c21f9 100644 --- a/workflow/util/util.go +++ b/workflow/util/util.go @@ -739,7 +739,11 @@ func RetryWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrato var updated *wfv1.Workflow err := waitutil.Backoff(retry.DefaultRetry, func() (bool, error) { var err error - updated, err = retryWorkflow(ctx, kubeClient, hydrator, wfClient, name, restartSuccessful, nodeFieldSelector) + wf, err := wfClient.Get(ctx, name, metav1.GetOptions{}) + if err != nil { + return false, err + } + updated, err = retryWorkflow(ctx, kubeClient, hydrator, wfClient, wf, name, restartSuccessful, nodeFieldSelector, false) return !errorsutil.IsTransientErr(err), err }) if err != nil { @@ -748,17 +752,37 @@ func RetryWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrato return updated, err } -func retryWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrator hydrator.Interface, wfClient v1alpha1.WorkflowInterface, name string, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { - wf, err := wfClient.Get(ctx, name, metav1.GetOptions{}) +// RetryArchiveWF +// take archiveClient to get wf +func RetryArchiveWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrator hydrator.Interface, wfClient v1alpha1.WorkflowInterface, wf *wfv1.Workflow, name string, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { + var updated *wfv1.Workflow + err := waitutil.Backoff(retry.DefaultRetry, func() (bool, error) { + var err error + // wf, err := w.wfArchive.GetWorkflow(req.Uid) + // if err != nil { + // return nil, err + // } + updated, err = retryWorkflow(ctx, kubeClient, hydrator, wfClient, wf, name, restartSuccessful, nodeFieldSelector, true) + return !errorsutil.IsTransientErr(err), err + }) if err != nil { return nil, err } + return updated, err +} + +// retryWorkflow takes a wf in method signature instead and has boolean to determine if this is from archive or not - archive means we must create the workflow before update +func retryWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrator hydrator.Interface, wfClient v1alpha1.WorkflowInterface, wf *wfv1.Workflow, name string, restartSuccessful bool, nodeFieldSelector string, retryArchive bool) (*wfv1.Workflow, error) { + // wf, err := wfClient.Get(ctx, name, metav1.GetOptions{}) + // if err != nil { + // return nil, err + // } switch wf.Status.Phase { case wfv1.WorkflowFailed, wfv1.WorkflowError: default: return nil, errors.Errorf(errors.CodeBadRequest, "workflow must be Failed/Error to retry") } - err = hydrator.Hydrate(wf) + err := hydrator.Hydrate(wf) if err != nil { return nil, err } @@ -872,6 +896,11 @@ func retryWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrato newWF.Status.StoredTemplates[id] = tmpl } + // need to wfClient.Create() for ArchiveWorkflow as they don't exist currently + if !retryArchive { + wfClient.Create(ctx, newWF, metav1.CreateOptions{}) + } + return wfClient.Update(ctx, newWF, metav1.UpdateOptions{}) } From 4d7485479fb55adf49b4949508067666eea92415 Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Thu, 24 Feb 2022 13:36:26 -0800 Subject: [PATCH 02/28] chore: fixed lint errors and removed comments Signed-off-by: Dillen Padhiar --- .../archived_workflow_server.go | 9 ++---- .../archived_workflow_server_test.go | 6 ++-- workflow/util/util.go | 32 +++++++++---------- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/server/workflowarchive/archived_workflow_server.go b/server/workflowarchive/archived_workflow_server.go index 559881813da8..0049e8a8b65c 100644 --- a/server/workflowarchive/archived_workflow_server.go +++ b/server/workflowarchive/archived_workflow_server.go @@ -34,10 +34,6 @@ func NewWorkflowArchiveServer(wfArchive sqldb.WorkflowArchive, offloadNodeStatus return &archivedWorkflowServer{wfArchive: wfArchive, offloadNodeStatusRepo: offloadNodeStatusRepo, hydrator: hydrator.New(offloadNodeStatusRepo)} } -// func NewWorkflowServer(instanceIDService instanceid.Service, offloadNodeStatusRepo sqldb.OffloadNodeStatusRepo) workflowpkg.WorkflowServiceServer { -// return &workflowServer{instanceIDService, offloadNodeStatusRepo, hydrator.New(offloadNodeStatusRepo)} -// } - func (w *archivedWorkflowServer) ListArchivedWorkflows(ctx context.Context, req *workflowarchivepkg.ListArchivedWorkflowsRequest) (*wfv1.WorkflowList, error) { options := req.ListOptions namePrefix := req.NamePrefix @@ -211,9 +207,8 @@ func (w *archivedWorkflowServer) RetryArchivedWorkflow(ctx context.Context, req return nil, err } - // retry archive workflow needs wf passed - - wf, err = util.RetryArchiveWorkflow(ctx, kubeClient, w.hydrator, wfClient.ArgoprojV1alpha1().Workflows(req.Namespace), wf, wf.Name, req.RestartSuccessful, req.NodeFieldSelector) + // could send archive and name instead + wf, err = util.RetryArchiveWorkflow(ctx, kubeClient, w.hydrator, wfClient.ArgoprojV1alpha1().Workflows(req.Namespace), w.wfArchive, req.Uid, req.RestartSuccessful, req.NodeFieldSelector) if err != nil { return nil, err } diff --git a/server/workflowarchive/archived_workflow_server_test.go b/server/workflowarchive/archived_workflow_server_test.go index 0d07466787e3..4617c3d4195f 100644 --- a/server/workflowarchive/archived_workflow_server_test.go +++ b/server/workflowarchive/archived_workflow_server_test.go @@ -6,6 +6,7 @@ import ( "time" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" authorizationv1 "k8s.io/api/authorization/v1" @@ -16,6 +17,7 @@ import ( kubefake "k8s.io/client-go/kubernetes/fake" k8stesting "k8s.io/client-go/testing" + "github.com/argoproj/argo-workflows/v3/persist/sqldb" "github.com/argoproj/argo-workflows/v3/persist/sqldb/mocks" workflowarchivepkg "github.com/argoproj/argo-workflows/v3/pkg/apiclient/workflowarchive" wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" @@ -28,8 +30,8 @@ func Test_archivedWorkflowServer(t *testing.T) { kubeClient := &kubefake.Clientset{} wfClient := &argofake.Clientset{} offloadNodeStatusRepo := &mocks.OffloadNodeStatusRepo{} - // offloadNodeStatusRepo.On("IsEnabled", mock.Anything).Return(true) - // offloadNodeStatusRepo.On("List", mock.Anything).Return(map[sqldb.UUIDVersion]v1alpha1.Nodes{}, nil) + offloadNodeStatusRepo.On("IsEnabled", mock.Anything).Return(true) + offloadNodeStatusRepo.On("List", mock.Anything).Return(map[sqldb.UUIDVersion]wfv1.Nodes{}, nil) w := NewWorkflowArchiveServer(repo, offloadNodeStatusRepo) allowed := true kubeClient.AddReactor("create", "selfsubjectaccessreviews", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { diff --git a/workflow/util/util.go b/workflow/util/util.go index db21019c21f9..2fd3ef369e6b 100644 --- a/workflow/util/util.go +++ b/workflow/util/util.go @@ -37,6 +37,7 @@ import ( "sigs.k8s.io/yaml" "github.com/argoproj/argo-workflows/v3/errors" + "github.com/argoproj/argo-workflows/v3/persist/sqldb" "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow" wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" wfclientset "github.com/argoproj/argo-workflows/v3/pkg/client/clientset/versioned" @@ -743,7 +744,7 @@ func RetryWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrato if err != nil { return false, err } - updated, err = retryWorkflow(ctx, kubeClient, hydrator, wfClient, wf, name, restartSuccessful, nodeFieldSelector, false) + updated, err = retryWorkflow(ctx, kubeClient, hydrator, wfClient, wf, restartSuccessful, nodeFieldSelector, false) return !errorsutil.IsTransientErr(err), err }) if err != nil { @@ -752,17 +753,16 @@ func RetryWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrato return updated, err } -// RetryArchiveWF -// take archiveClient to get wf -func RetryArchiveWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrator hydrator.Interface, wfClient v1alpha1.WorkflowInterface, wf *wfv1.Workflow, name string, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { +// RetryArchiveWorkflow recreates and updates a workflow +func RetryArchiveWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrator hydrator.Interface, wfClient v1alpha1.WorkflowInterface, wfArchive sqldb.WorkflowArchive, uid string, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { var updated *wfv1.Workflow err := waitutil.Backoff(retry.DefaultRetry, func() (bool, error) { var err error - // wf, err := w.wfArchive.GetWorkflow(req.Uid) - // if err != nil { - // return nil, err - // } - updated, err = retryWorkflow(ctx, kubeClient, hydrator, wfClient, wf, name, restartSuccessful, nodeFieldSelector, true) + wf, err := wfArchive.GetWorkflow(uid) + if err != nil { + return false, err + } + updated, err = retryWorkflow(ctx, kubeClient, hydrator, wfClient, wf, restartSuccessful, nodeFieldSelector, true) return !errorsutil.IsTransientErr(err), err }) if err != nil { @@ -772,11 +772,8 @@ func RetryArchiveWorkflow(ctx context.Context, kubeClient kubernetes.Interface, } // retryWorkflow takes a wf in method signature instead and has boolean to determine if this is from archive or not - archive means we must create the workflow before update -func retryWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrator hydrator.Interface, wfClient v1alpha1.WorkflowInterface, wf *wfv1.Workflow, name string, restartSuccessful bool, nodeFieldSelector string, retryArchive bool) (*wfv1.Workflow, error) { - // wf, err := wfClient.Get(ctx, name, metav1.GetOptions{}) - // if err != nil { - // return nil, err - // } +func retryWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrator hydrator.Interface, wfClient v1alpha1.WorkflowInterface, wf *wfv1.Workflow, restartSuccessful bool, nodeFieldSelector string, retryArchive bool) (*wfv1.Workflow, error) { + switch wf.Status.Phase { case wfv1.WorkflowFailed, wfv1.WorkflowError: default: @@ -896,9 +893,12 @@ func retryWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrato newWF.Status.StoredTemplates[id] = tmpl } - // need to wfClient.Create() for ArchiveWorkflow as they don't exist currently + // workflow must be recreated on server if archived if !retryArchive { - wfClient.Create(ctx, newWF, metav1.CreateOptions{}) + newWF, err = wfClient.Create(ctx, newWF, metav1.CreateOptions{}) + if err != nil { + return nil, fmt.Errorf("unable to create workflow: %s", err) + } } return wfClient.Update(ctx, newWF, metav1.UpdateOptions{}) From 95a88c03030e8b25ec17f40a04b102985449e61f Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Thu, 24 Feb 2022 13:47:28 -0800 Subject: [PATCH 03/28] fix: retryArchive flag check was set incorrectly Signed-off-by: Dillen Padhiar --- 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 2fd3ef369e6b..a50077d375b0 100644 --- a/workflow/util/util.go +++ b/workflow/util/util.go @@ -894,7 +894,7 @@ func retryWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrato } // workflow must be recreated on server if archived - if !retryArchive { + if retryArchive { newWF, err = wfClient.Create(ctx, newWF, metav1.CreateOptions{}) if err != nil { return nil, fmt.Errorf("unable to create workflow: %s", err) From bbb14652def01c5033c086af4db6c8df08038ffa Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Fri, 25 Feb 2022 16:04:23 -0800 Subject: [PATCH 04/28] test: added test cases for retry wfarchive and wfarchiveserver Signed-off-by: Dillen Padhiar --- .../archived_workflow_server_test.go | 51 ++++++++++++++++++ workflow/util/util_test.go | 54 +++++++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/server/workflowarchive/archived_workflow_server_test.go b/server/workflowarchive/archived_workflow_server_test.go index 4617c3d4195f..56fbed5f63f7 100644 --- a/server/workflowarchive/archived_workflow_server_test.go +++ b/server/workflowarchive/archived_workflow_server_test.go @@ -23,6 +23,7 @@ import ( wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" argofake "github.com/argoproj/argo-workflows/v3/pkg/client/clientset/versioned/fake" "github.com/argoproj/argo-workflows/v3/server/auth" + "github.com/argoproj/argo-workflows/v3/workflow/common" ) func Test_archivedWorkflowServer(t *testing.T) { @@ -55,6 +56,8 @@ func Test_archivedWorkflowServer(t *testing.T) { repo.On("ListWorkflows", "", "", "", time.Time{}, time.Time{}, labels.Requirements(nil), 2, 1).Return(wfv1.Workflows{{}}, nil) minStartAt, _ := time.Parse(time.RFC3339, "2020-01-01T00:00:00Z") maxStartAt, _ := time.Parse(time.RFC3339, "2020-01-02T00:00:00Z") + createdTime := metav1.Time{Time: time.Now().UTC()} + finishedTime := metav1.Time{Time: createdTime.Add(time.Second * 2)} repo.On("ListWorkflows", "", "", "", minStartAt, maxStartAt, labels.Requirements(nil), 2, 0).Return(wfv1.Workflows{{}}, nil) repo.On("ListWorkflows", "", "my-name", "", minStartAt, maxStartAt, labels.Requirements(nil), 2, 0).Return(wfv1.Workflows{{}}, nil) repo.On("ListWorkflows", "", "", "my-", minStartAt, maxStartAt, labels.Requirements(nil), 2, 0).Return(wfv1.Workflows{{}}, nil) @@ -69,6 +72,23 @@ func Test_archivedWorkflowServer(t *testing.T) { }, }, }, nil) + repo.On("GetWorkflow", "failed-uid").Return(&wfv1.Workflow{ + ObjectMeta: metav1.ObjectMeta{ + Name: "failed-wf", + Labels: map[string]string{ + common.LabelKeyCompleted: "true", + common.LabelKeyWorkflowArchivingStatus: "Pending", + }, + }, + Status: wfv1.WorkflowStatus{ + Phase: wfv1.WorkflowFailed, + StartedAt: createdTime, + FinishedAt: finishedTime, + Nodes: map[string]wfv1.NodeStatus{ + "failed-node": {Name: "failed-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeFailed, Message: "failed"}, + "succeeded-node": {Name: "succeeded-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeSucceeded, Message: "succeeded"}}, + }, + }, nil) wfClient.AddReactor("create", "workflows", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { return true, &wfv1.Workflow{ ObjectMeta: metav1.ObjectMeta{Name: "my-name-resubmitted"}, @@ -81,6 +101,32 @@ func Test_archivedWorkflowServer(t *testing.T) { repo.On("ListWorkflowsLabelValues", "my-key").Return(&wfv1.LabelValues{ Items: []string{"my-key=foo", "my-key=bar"}, }, nil) + repo.On("ValidateWorkflow", &wfv1.Workflow{ + ObjectMeta: metav1.ObjectMeta{ + Name: "failed-wf", + Labels: map[string]string{ + common.LabelKeyCompleted: "true", + common.LabelKeyWorkflowArchivingStatus: "Pending", + }, + }, + Status: wfv1.WorkflowStatus{ + Phase: wfv1.WorkflowFailed, + StartedAt: createdTime, + FinishedAt: finishedTime, + Nodes: map[string]wfv1.NodeStatus{ + "failed-node": {Name: "failed-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeFailed, Message: "failed"}, + "succeeded-node": {Name: "succeeded-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeSucceeded, Message: "succeeded"}}, + }, + }).Return(nil) + repo.On("RetryWorkflow", "failed-uid").Return(&wfv1.Workflow{ + ObjectMeta: metav1.ObjectMeta{Name: "failed-wf"}, + Spec: wfv1.WorkflowSpec{ + Entrypoint: "my-entrypoint", + Templates: []wfv1.Template{ + {Name: "my-entrypoint", Container: &apiv1.Container{}}, + }, + }, + }, nil) ctx := context.WithValue(context.WithValue(context.TODO(), auth.WfKey, wfClient), auth.KubeKey, kubeClient) t.Run("ListArchivedWorkflows", func(t *testing.T) { @@ -148,4 +194,9 @@ func Test_archivedWorkflowServer(t *testing.T) { assert.NoError(t, err) assert.Len(t, resp.Items, 2) }) + t.Run("RetryArchivedWorkflow", func(t *testing.T) { + wf, err := w.RetryArchivedWorkflow(ctx, &workflowarchivepkg.RetryArchivedWorkflowRequest{Uid: "failed-uid"}) + assert.NoError(t, err) + assert.NotNil(t, wf) + }) } diff --git a/workflow/util/util_test.go b/workflow/util/util_test.go index 0fc224ab2842..3389fc254926 100644 --- a/workflow/util/util_test.go +++ b/workflow/util/util_test.go @@ -892,6 +892,60 @@ func TestRetryWorkflow(t *testing.T) { }) } +func TestRetryArchiveWorkflow(t *testing.T) { + ctx := context.Background() + kubeClient := kubefake.NewSimpleClientset() + wfClient := argofake.NewSimpleClientset().ArgoprojV1alpha1().Workflows("my-ns") + createdTime := metav1.Time{Time: time.Now().UTC()} + finishedTime := metav1.Time{Time: createdTime.Add(time.Second * 2)} + t.Run("Steps", func(t *testing.T) { + wf := &wfv1.Workflow{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-steps", + Labels: map[string]string{ + common.LabelKeyCompleted: "true", + common.LabelKeyWorkflowArchivingStatus: "Pending", + }, + }, + Status: wfv1.WorkflowStatus{ + Phase: wfv1.WorkflowFailed, + StartedAt: createdTime, + FinishedAt: finishedTime, + Nodes: map[string]wfv1.NodeStatus{ + "failed-node": {Name: "failed-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeFailed, Message: "failed"}, + "succeeded-node": {Name: "succeeded-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeSucceeded, Message: "succeeded"}}, + }, + } + + // simulate retrying workflow from workflowArchive + wf, err := RetryArchiveWorkflow(ctx, kubeClient, hydratorfake.Noop, wfClient, wf, false, "") + if assert.NoError(t, err) { + assert.Equal(t, wfv1.WorkflowRunning, wf.Status.Phase) + assert.Equal(t, metav1.Time{}, wf.Status.FinishedAt) + assert.True(t, wf.Status.StartedAt.After(createdTime.Time)) + assert.NotContains(t, wf.Labels, common.LabelKeyCompleted) + assert.NotContains(t, wf.Labels, common.LabelKeyWorkflowArchivingStatus) + for _, node := range wf.Status.Nodes { + switch node.Phase { + case wfv1.NodeSucceeded: + assert.Equal(t, "succeeded", node.Message) + assert.Equal(t, wfv1.NodeSucceeded, node.Phase) + assert.Equal(t, createdTime, node.StartedAt) + assert.Equal(t, finishedTime, node.FinishedAt) + case wfv1.NodeFailed: + assert.Equal(t, "", node.Message) + assert.Equal(t, wfv1.NodeRunning, node.Phase) + assert.Equal(t, metav1.Time{}, node.FinishedAt) + assert.True(t, node.StartedAt.After(createdTime.Time)) + } + } + } + // retry on workflow that already exists + _, err = RetryArchiveWorkflow(ctx, kubeClient, hydratorfake.Noop, wfClient, wf, false, "") + assert.Error(t, err) + }) +} + func TestFromUnstructuredObj(t *testing.T) { un := &unstructured.Unstructured{} wfv1.MustUnmarshal([]byte(`apiVersion: argoproj.io/v1alpha1 From 949ab6c0714ee9eef1c468ff932737417fb2bcb5 Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Fri, 25 Feb 2022 16:05:33 -0800 Subject: [PATCH 05/28] fix: changed method signature and removed comments Signed-off-by: Dillen Padhiar --- .../http1/archived-workflows-service-client.go | 2 +- pkg/apiclient/workflowarchive/workflow-archive.proto | 11 ----------- server/workflowarchive/archived_workflow_server.go | 10 ++++------ workflow/util/util.go | 12 +++++------- 4 files changed, 10 insertions(+), 25 deletions(-) diff --git a/pkg/apiclient/http1/archived-workflows-service-client.go b/pkg/apiclient/http1/archived-workflows-service-client.go index 71ea5f53fc43..ba1e0f8edd9e 100644 --- a/pkg/apiclient/http1/archived-workflows-service-client.go +++ b/pkg/apiclient/http1/archived-workflows-service-client.go @@ -49,5 +49,5 @@ func (h ArchivedWorkflowsServiceClient) ListArchivedWorkflowLabelValues(_ contex func (h ArchivedWorkflowsServiceClient) RetryArchivedWorkflow(_ context.Context, in *workflowarchivepkg.RetryArchivedWorkflowRequest, _ ...grpc.CallOption) (*wfv1.Workflow, error) { out := &wfv1.Workflow{} - return out, h.Get(in, out, "/api/v1/archived-workflows-label-values") + return out, h.Get(in, out, "/api/v1/archived-workflows/{namespace}/{uid}/retry") } diff --git a/pkg/apiclient/workflowarchive/workflow-archive.proto b/pkg/apiclient/workflowarchive/workflow-archive.proto index 1996e4d20724..ff39dfe9a464 100644 --- a/pkg/apiclient/workflowarchive/workflow-archive.proto +++ b/pkg/apiclient/workflowarchive/workflow-archive.proto @@ -31,11 +31,6 @@ message RetryArchivedWorkflowRequest { bool restartSuccessful = 4; string nodeFieldSelector = 5; } -// message ResubmitArchivedWorkflowRequest { -// string uid = 1; -// string name = 2; -// string namespace = 3; -// } service ArchivedWorkflowService { rpc ListArchivedWorkflows (ListArchivedWorkflowsRequest) returns (github.com.argoproj.argo_workflows.v3.pkg.apis.workflow.v1alpha1.WorkflowList) { @@ -59,10 +54,4 @@ service ArchivedWorkflowService { body: "*" }; } - // rpc ResubmitArchivedWorkflow (ResubmitArchivedWorkflowRequest) returns (github.com.argoproj.argo_workflows.v3.pkg.apis.workflow.v1alpha1.Workflow) { - // option (google.api.http) = { - // put: "/api/v1/archived-workflows/{namespace}/{name}/resubmit" - // body: "*" - // }; - // } } diff --git a/server/workflowarchive/archived_workflow_server.go b/server/workflowarchive/archived_workflow_server.go index 0049e8a8b65c..76a0d55da2a8 100644 --- a/server/workflowarchive/archived_workflow_server.go +++ b/server/workflowarchive/archived_workflow_server.go @@ -24,14 +24,13 @@ import ( ) type archivedWorkflowServer struct { - wfArchive sqldb.WorkflowArchive - offloadNodeStatusRepo sqldb.OffloadNodeStatusRepo - hydrator hydrator.Interface + wfArchive sqldb.WorkflowArchive + hydrator hydrator.Interface } // NewWorkflowArchiveServer returns a new archivedWorkflowServer func NewWorkflowArchiveServer(wfArchive sqldb.WorkflowArchive, offloadNodeStatusRepo sqldb.OffloadNodeStatusRepo) workflowarchivepkg.ArchivedWorkflowServiceServer { - return &archivedWorkflowServer{wfArchive: wfArchive, offloadNodeStatusRepo: offloadNodeStatusRepo, hydrator: hydrator.New(offloadNodeStatusRepo)} + return &archivedWorkflowServer{wfArchive: wfArchive, hydrator: hydrator.New(offloadNodeStatusRepo)} } func (w *archivedWorkflowServer) ListArchivedWorkflows(ctx context.Context, req *workflowarchivepkg.ListArchivedWorkflowsRequest) (*wfv1.WorkflowList, error) { @@ -207,8 +206,7 @@ func (w *archivedWorkflowServer) RetryArchivedWorkflow(ctx context.Context, req return nil, err } - // could send archive and name instead - wf, err = util.RetryArchiveWorkflow(ctx, kubeClient, w.hydrator, wfClient.ArgoprojV1alpha1().Workflows(req.Namespace), w.wfArchive, req.Uid, req.RestartSuccessful, req.NodeFieldSelector) + wf, err = util.RetryArchiveWorkflow(ctx, kubeClient, w.hydrator, wfClient.ArgoprojV1alpha1().Workflows(req.Namespace), wf, req.RestartSuccessful, req.NodeFieldSelector) if err != nil { return nil, err } diff --git a/workflow/util/util.go b/workflow/util/util.go index a50077d375b0..4992f3390b04 100644 --- a/workflow/util/util.go +++ b/workflow/util/util.go @@ -37,7 +37,6 @@ import ( "sigs.k8s.io/yaml" "github.com/argoproj/argo-workflows/v3/errors" - "github.com/argoproj/argo-workflows/v3/persist/sqldb" "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow" wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" wfclientset "github.com/argoproj/argo-workflows/v3/pkg/client/clientset/versioned" @@ -754,14 +753,10 @@ func RetryWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrato } // RetryArchiveWorkflow recreates and updates a workflow -func RetryArchiveWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrator hydrator.Interface, wfClient v1alpha1.WorkflowInterface, wfArchive sqldb.WorkflowArchive, uid string, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { +func RetryArchiveWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrator hydrator.Interface, wfClient v1alpha1.WorkflowInterface, wf *wfv1.Workflow, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { var updated *wfv1.Workflow err := waitutil.Backoff(retry.DefaultRetry, func() (bool, error) { var err error - wf, err := wfArchive.GetWorkflow(uid) - if err != nil { - return false, err - } updated, err = retryWorkflow(ctx, kubeClient, hydrator, wfClient, wf, restartSuccessful, nodeFieldSelector, true) return !errorsutil.IsTransientErr(err), err }) @@ -893,12 +888,15 @@ func retryWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrato newWF.Status.StoredTemplates[id] = tmpl } - // workflow must be recreated on server if archived if retryArchive { newWF, err = wfClient.Create(ctx, newWF, metav1.CreateOptions{}) if err != nil { + if apierr.IsAlreadyExists(err) { + return nil, fmt.Errorf("workflow already exists : %s", err) + } return nil, fmt.Errorf("unable to create workflow: %s", err) } + return newWF, nil } return wfClient.Update(ctx, newWF, metav1.UpdateOptions{}) From b46324c3d70ee4ac3dee3c19f0bd90dff9f19618 Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Mon, 28 Feb 2022 13:34:07 -0800 Subject: [PATCH 06/28] fix: removed validateWorkflow() from WorkflowArchive Signed-off-by: Dillen Padhiar --- persist/sqldb/null_workflow_archive.go | 4 --- persist/sqldb/workflow_archive.go | 5 --- .../archived_workflow_server.go | 5 --- .../archived_workflow_server_test.go | 34 +++++++++---------- 4 files changed, 17 insertions(+), 31 deletions(-) diff --git a/persist/sqldb/null_workflow_archive.go b/persist/sqldb/null_workflow_archive.go index 15e3cc35d419..74218279ee64 100644 --- a/persist/sqldb/null_workflow_archive.go +++ b/persist/sqldb/null_workflow_archive.go @@ -17,10 +17,6 @@ func (r *nullWorkflowArchive) IsEnabled() bool { return false } -func (r *nullWorkflowArchive) ValidateWorkflow(wf *wfv1.Workflow) error { - return nil -} - func (r *nullWorkflowArchive) ArchiveWorkflow(*wfv1.Workflow) error { return nil } diff --git a/persist/sqldb/workflow_archive.go b/persist/sqldb/workflow_archive.go index 197a9c6124e6..bbbdea4e8fa8 100644 --- a/persist/sqldb/workflow_archive.go +++ b/persist/sqldb/workflow_archive.go @@ -58,7 +58,6 @@ type WorkflowArchive interface { IsEnabled() bool ListWorkflowsLabelKeys() (*wfv1.LabelKeys, error) ListWorkflowsLabelValues(key string) (*wfv1.LabelValues, error) - ValidateWorkflow(wf *wfv1.Workflow) error } type workflowArchive struct { @@ -73,10 +72,6 @@ func (r *workflowArchive) IsEnabled() bool { return true } -func (r *workflowArchive) ValidateWorkflow(wf *wfv1.Workflow) error { - return r.instanceIDService.Validate(wf) -} - // NewWorkflowArchive returns a new workflowArchive func NewWorkflowArchive(session sqlbuilder.Database, clusterName, managedNamespace string, instanceIDService instanceid.Service) WorkflowArchive { return &workflowArchive{session: session, clusterName: clusterName, managedNamespace: managedNamespace, instanceIDService: instanceIDService, dbType: dbTypeFor(session)} diff --git a/server/workflowarchive/archived_workflow_server.go b/server/workflowarchive/archived_workflow_server.go index 76a0d55da2a8..8110f1131def 100644 --- a/server/workflowarchive/archived_workflow_server.go +++ b/server/workflowarchive/archived_workflow_server.go @@ -201,11 +201,6 @@ func (w *archivedWorkflowServer) RetryArchivedWorkflow(ctx context.Context, req return nil, err } - err = w.wfArchive.ValidateWorkflow(wf) - if err != nil { - return nil, err - } - wf, err = util.RetryArchiveWorkflow(ctx, kubeClient, w.hydrator, wfClient.ArgoprojV1alpha1().Workflows(req.Namespace), wf, req.RestartSuccessful, req.NodeFieldSelector) if err != nil { return nil, err diff --git a/server/workflowarchive/archived_workflow_server_test.go b/server/workflowarchive/archived_workflow_server_test.go index 56fbed5f63f7..f271152fb5ad 100644 --- a/server/workflowarchive/archived_workflow_server_test.go +++ b/server/workflowarchive/archived_workflow_server_test.go @@ -101,23 +101,23 @@ func Test_archivedWorkflowServer(t *testing.T) { repo.On("ListWorkflowsLabelValues", "my-key").Return(&wfv1.LabelValues{ Items: []string{"my-key=foo", "my-key=bar"}, }, nil) - repo.On("ValidateWorkflow", &wfv1.Workflow{ - ObjectMeta: metav1.ObjectMeta{ - Name: "failed-wf", - Labels: map[string]string{ - common.LabelKeyCompleted: "true", - common.LabelKeyWorkflowArchivingStatus: "Pending", - }, - }, - Status: wfv1.WorkflowStatus{ - Phase: wfv1.WorkflowFailed, - StartedAt: createdTime, - FinishedAt: finishedTime, - Nodes: map[string]wfv1.NodeStatus{ - "failed-node": {Name: "failed-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeFailed, Message: "failed"}, - "succeeded-node": {Name: "succeeded-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeSucceeded, Message: "succeeded"}}, - }, - }).Return(nil) + // repo.On("ValidateWorkflow", &wfv1.Workflow{ + // ObjectMeta: metav1.ObjectMeta{ + // Name: "failed-wf", + // Labels: map[string]string{ + // common.LabelKeyCompleted: "true", + // common.LabelKeyWorkflowArchivingStatus: "Pending", + // }, + // }, + // Status: wfv1.WorkflowStatus{ + // Phase: wfv1.WorkflowFailed, + // StartedAt: createdTime, + // FinishedAt: finishedTime, + // Nodes: map[string]wfv1.NodeStatus{ + // "failed-node": {Name: "failed-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeFailed, Message: "failed"}, + // "succeeded-node": {Name: "succeeded-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeSucceeded, Message: "succeeded"}}, + // }, + // }).Return(nil) repo.On("RetryWorkflow", "failed-uid").Return(&wfv1.Workflow{ ObjectMeta: metav1.ObjectMeta{Name: "failed-wf"}, Spec: wfv1.WorkflowSpec{ From fe493ac3cff62f479991f63cbac2b356f5c467f2 Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Tue, 1 Mar 2022 13:14:37 -0800 Subject: [PATCH 07/28] feat: refactored retryWorkflow into prepareWorkflowForRetry Signed-off-by: Dillen Padhiar --- persist/sqldb/mocks/WorkflowArchive.go | 14 ---- server/workflow/workflow_server.go | 7 +- .../archived_workflow_server.go | 8 ++- .../archived_workflow_server_test.go | 17 ----- workflow/util/util.go | 66 ++++++++----------- workflow/util/util_test.go | 10 +-- 6 files changed, 47 insertions(+), 75 deletions(-) diff --git a/persist/sqldb/mocks/WorkflowArchive.go b/persist/sqldb/mocks/WorkflowArchive.go index d6d67c0ec089..2d77c8335861 100644 --- a/persist/sqldb/mocks/WorkflowArchive.go +++ b/persist/sqldb/mocks/WorkflowArchive.go @@ -163,17 +163,3 @@ func (_m *WorkflowArchive) ListWorkflowsLabelValues(key string) (*v1alpha1.Label return r0, r1 } - -// ValidateWorkflow provides a mock function with given fields: wf -func (_m *WorkflowArchive) ValidateWorkflow(wf *v1alpha1.Workflow) error { - ret := _m.Called(wf) - - var r0 error - if rf, ok := ret.Get(0).(func(*v1alpha1.Workflow) error); ok { - r0 = rf(wf) - } else { - r0 = ret.Error(0) - } - - return r0 -} diff --git a/server/workflow/workflow_server.go b/server/workflow/workflow_server.go index 4d6c7e354732..0cc4731e60e9 100644 --- a/server/workflow/workflow_server.go +++ b/server/workflow/workflow_server.go @@ -319,7 +319,12 @@ func (s *workflowServer) RetryWorkflow(ctx context.Context, req *workflowpkg.Wor return nil, err } - wf, err = util.RetryWorkflow(ctx, kubeClient, s.hydrator, wfClient.ArgoprojV1alpha1().Workflows(req.Namespace), wf.Name, req.RestartSuccessful, req.NodeFieldSelector) + err = s.hydrator.Hydrate(wf) + if err != nil { + return nil, err + } + + wf, err = util.RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wfClient.ArgoprojV1alpha1().Workflows(req.Namespace), wf.Name, req.RestartSuccessful, req.NodeFieldSelector) if err != nil { return nil, err } diff --git a/server/workflowarchive/archived_workflow_server.go b/server/workflowarchive/archived_workflow_server.go index 8110f1131def..3790ebbe28a8 100644 --- a/server/workflowarchive/archived_workflow_server.go +++ b/server/workflowarchive/archived_workflow_server.go @@ -201,9 +201,15 @@ func (w *archivedWorkflowServer) RetryArchivedWorkflow(ctx context.Context, req return nil, err } - wf, err = util.RetryArchiveWorkflow(ctx, kubeClient, w.hydrator, wfClient.ArgoprojV1alpha1().Workflows(req.Namespace), wf, req.RestartSuccessful, req.NodeFieldSelector) + err = w.hydrator.Hydrate(wf) if err != nil { return nil, err } + + wf, err = util.RetryArchiveWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wfClient.ArgoprojV1alpha1().Workflows(req.Namespace), wf, req.RestartSuccessful, req.NodeFieldSelector) + if err != nil { + return nil, err + } + return wf, nil } diff --git a/server/workflowarchive/archived_workflow_server_test.go b/server/workflowarchive/archived_workflow_server_test.go index f271152fb5ad..b10170b3c7a2 100644 --- a/server/workflowarchive/archived_workflow_server_test.go +++ b/server/workflowarchive/archived_workflow_server_test.go @@ -101,23 +101,6 @@ func Test_archivedWorkflowServer(t *testing.T) { repo.On("ListWorkflowsLabelValues", "my-key").Return(&wfv1.LabelValues{ Items: []string{"my-key=foo", "my-key=bar"}, }, nil) - // repo.On("ValidateWorkflow", &wfv1.Workflow{ - // ObjectMeta: metav1.ObjectMeta{ - // Name: "failed-wf", - // Labels: map[string]string{ - // common.LabelKeyCompleted: "true", - // common.LabelKeyWorkflowArchivingStatus: "Pending", - // }, - // }, - // Status: wfv1.WorkflowStatus{ - // Phase: wfv1.WorkflowFailed, - // StartedAt: createdTime, - // FinishedAt: finishedTime, - // Nodes: map[string]wfv1.NodeStatus{ - // "failed-node": {Name: "failed-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeFailed, Message: "failed"}, - // "succeeded-node": {Name: "succeeded-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeSucceeded, Message: "succeeded"}}, - // }, - // }).Return(nil) repo.On("RetryWorkflow", "failed-uid").Return(&wfv1.Workflow{ ObjectMeta: metav1.ObjectMeta{Name: "failed-wf"}, Spec: wfv1.WorkflowSpec{ diff --git a/workflow/util/util.go b/workflow/util/util.go index 4992f3390b04..2f74cccef73c 100644 --- a/workflow/util/util.go +++ b/workflow/util/util.go @@ -31,7 +31,7 @@ import ( "k8s.io/apimachinery/pkg/util/strategicpatch" "k8s.io/client-go/dynamic" "k8s.io/client-go/informers/internalinterfaces" - "k8s.io/client-go/kubernetes" + v1 "k8s.io/client-go/kubernetes/typed/core/v1" "k8s.io/client-go/tools/cache" "k8s.io/utils/pointer" "sigs.k8s.io/yaml" @@ -735,52 +735,60 @@ func convertNodeID(newWf *wfv1.Workflow, regex *regexp.Regexp, oldNodeID string, } // RetryWorkflow updates a workflow, deleting all failed steps as well as the onExit node (and children) -func RetryWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrator hydrator.Interface, wfClient v1alpha1.WorkflowInterface, name string, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { - var updated *wfv1.Workflow +func RetryWorkflow(ctx context.Context, podIf v1.PodInterface, wfClient v1alpha1.WorkflowInterface, name string, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { + var updatedWf *wfv1.Workflow err := waitutil.Backoff(retry.DefaultRetry, func() (bool, error) { var err error wf, err := wfClient.Get(ctx, name, metav1.GetOptions{}) if err != nil { return false, err } - updated, err = retryWorkflow(ctx, kubeClient, hydrator, wfClient, wf, restartSuccessful, nodeFieldSelector, false) + updatedWf, err = prepareWorkflowForRetry(ctx, wf, podIf, restartSuccessful, nodeFieldSelector) + if err != nil { + return false, err + } + updatedWf, err = wfClient.Update(ctx, updatedWf, metav1.UpdateOptions{}) + if err != nil { + return false, err + } return !errorsutil.IsTransientErr(err), err }) - if err != nil { - return nil, err - } - return updated, err + + return updatedWf, err } // RetryArchiveWorkflow recreates and updates a workflow -func RetryArchiveWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrator hydrator.Interface, wfClient v1alpha1.WorkflowInterface, wf *wfv1.Workflow, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { +func RetryArchiveWorkflow(ctx context.Context, podIf v1.PodInterface, wfClient v1alpha1.WorkflowInterface, wf *wfv1.Workflow, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { var updated *wfv1.Workflow err := waitutil.Backoff(retry.DefaultRetry, func() (bool, error) { var err error - updated, err = retryWorkflow(ctx, kubeClient, hydrator, wfClient, wf, restartSuccessful, nodeFieldSelector, true) + updated, err = prepareWorkflowForRetry(ctx, wf, podIf, restartSuccessful, nodeFieldSelector) + if err != nil { + return false, err + } + updated, err = wfClient.Create(ctx, updated, metav1.CreateOptions{}) + if err != nil { + if apierr.IsAlreadyExists(err) { + return false, fmt.Errorf("workflow already exists : %s", err) + } + return false, fmt.Errorf("unable to create workflow: %s", err) + } return !errorsutil.IsTransientErr(err), err }) - if err != nil { - return nil, err - } + return updated, err } -// retryWorkflow takes a wf in method signature instead and has boolean to determine if this is from archive or not - archive means we must create the workflow before update -func retryWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrator hydrator.Interface, wfClient v1alpha1.WorkflowInterface, wf *wfv1.Workflow, restartSuccessful bool, nodeFieldSelector string, retryArchive bool) (*wfv1.Workflow, error) { +// should not take any client +func prepareWorkflowForRetry(ctx context.Context, wf *wfv1.Workflow, podIf v1.PodInterface, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { switch wf.Status.Phase { case wfv1.WorkflowFailed, wfv1.WorkflowError: default: return nil, errors.Errorf(errors.CodeBadRequest, "workflow must be Failed/Error to retry") } - err := hydrator.Hydrate(wf) - if err != nil { - return nil, err - } newWF := wf.DeepCopy() - podIf := kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace) // Delete/reset fields which indicate workflow completed delete(newWF.Labels, common.LabelKeyCompleted) @@ -878,28 +886,12 @@ func retryWorkflow(ctx context.Context, kubeClient kubernetes.Interface, hydrato } } - err = hydrator.Dehydrate(newWF) - if err != nil { - return nil, fmt.Errorf("unable to compress or offload workflow nodes: %s", err) - } - newWF.Status.StoredTemplates = make(map[string]wfv1.Template) for id, tmpl := range wf.Status.StoredTemplates { newWF.Status.StoredTemplates[id] = tmpl } - if retryArchive { - newWF, err = wfClient.Create(ctx, newWF, metav1.CreateOptions{}) - if err != nil { - if apierr.IsAlreadyExists(err) { - return nil, fmt.Errorf("workflow already exists : %s", err) - } - return nil, fmt.Errorf("unable to create workflow: %s", err) - } - return newWF, nil - } - - return wfClient.Update(ctx, newWF, metav1.UpdateOptions{}) + return newWF, nil } func getTemplateFromNode(node wfv1.NodeStatus) string { diff --git a/workflow/util/util_test.go b/workflow/util/util_test.go index 3389fc254926..c19dd7a37007 100644 --- a/workflow/util/util_test.go +++ b/workflow/util/util_test.go @@ -811,7 +811,7 @@ func TestDeepDeleteNodes(t *testing.T) { ctx := context.Background() wf, err := wfIf.Create(ctx, origWf, metav1.CreateOptions{}) if assert.NoError(t, err) { - newWf, err := RetryWorkflow(ctx, kubeClient, hydratorfake.Noop, wfIf, wf.Name, false, "") + newWf, err := RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wfIf, wf.Name, false, "") assert.NoError(t, err) newWfBytes, err := yaml.Marshal(newWf) assert.NoError(t, err) @@ -845,7 +845,7 @@ func TestRetryWorkflow(t *testing.T) { } _, err := wfClient.Create(ctx, wf, metav1.CreateOptions{}) assert.NoError(t, err) - wf, err = RetryWorkflow(ctx, kubeClient, hydratorfake.Noop, wfClient, wf.Name, false, "") + wf, err = RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wfClient, wf.Name, false, "") if assert.NoError(t, err) { assert.Equal(t, wfv1.WorkflowRunning, wf.Status.Phase) assert.Equal(t, metav1.Time{}, wf.Status.FinishedAt) @@ -882,7 +882,7 @@ func TestRetryWorkflow(t *testing.T) { } _, err := wfClient.Create(ctx, wf, metav1.CreateOptions{}) assert.NoError(t, err) - wf, err = RetryWorkflow(ctx, kubeClient, hydratorfake.Noop, wfClient, wf.Name, false, "") + wf, err = RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wfClient, wf.Name, false, "") if assert.NoError(t, err) { if assert.Len(t, wf.Status.Nodes, 1) { assert.Equal(t, wfv1.NodeRunning, wf.Status.Nodes[""].Phase) @@ -918,7 +918,7 @@ func TestRetryArchiveWorkflow(t *testing.T) { } // simulate retrying workflow from workflowArchive - wf, err := RetryArchiveWorkflow(ctx, kubeClient, hydratorfake.Noop, wfClient, wf, false, "") + wf, err := RetryArchiveWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wfClient, wf, false, "") if assert.NoError(t, err) { assert.Equal(t, wfv1.WorkflowRunning, wf.Status.Phase) assert.Equal(t, metav1.Time{}, wf.Status.FinishedAt) @@ -941,7 +941,7 @@ func TestRetryArchiveWorkflow(t *testing.T) { } } // retry on workflow that already exists - _, err = RetryArchiveWorkflow(ctx, kubeClient, hydratorfake.Noop, wfClient, wf, false, "") + _, err = RetryArchiveWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wfClient, wf, false, "") assert.Error(t, err) }) } From 15a2f777c45a3b8b4ec1645692e746b5a360776a Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Wed, 2 Mar 2022 10:57:06 -0800 Subject: [PATCH 08/28] refactor: remove RetryArchiveWorkflow and move wfClient update/create to service level Signed-off-by: Dillen Padhiar --- server/apiserver/argoserver.go | 2 +- server/workflow/workflow_server.go | 8 ++- .../archived_workflow_server.go | 17 +++--- .../archived_workflow_server_test.go | 7 +-- workflow/util/util.go | 46 ++------------ workflow/util/util_test.go | 60 +------------------ 6 files changed, 27 insertions(+), 113 deletions(-) diff --git a/server/apiserver/argoserver.go b/server/apiserver/argoserver.go index 33998b307e71..618c0b7473de 100644 --- a/server/apiserver/argoserver.go +++ b/server/apiserver/argoserver.go @@ -287,7 +287,7 @@ func (as *argoServer) newGRPCServer(instanceIDService instanceid.Service, offloa workflowpkg.RegisterWorkflowServiceServer(grpcServer, workflow.NewWorkflowServer(instanceIDService, offloadNodeStatusRepo)) workflowtemplatepkg.RegisterWorkflowTemplateServiceServer(grpcServer, workflowtemplate.NewWorkflowTemplateServer(instanceIDService)) cronworkflowpkg.RegisterCronWorkflowServiceServer(grpcServer, cronworkflow.NewCronWorkflowServer(instanceIDService)) - workflowarchivepkg.RegisterArchivedWorkflowServiceServer(grpcServer, workflowarchive.NewWorkflowArchiveServer(wfArchive, offloadNodeStatusRepo)) + workflowarchivepkg.RegisterArchivedWorkflowServiceServer(grpcServer, workflowarchive.NewWorkflowArchiveServer(wfArchive)) clusterwftemplatepkg.RegisterClusterWorkflowTemplateServiceServer(grpcServer, clusterworkflowtemplate.NewClusterWorkflowTemplateServer(instanceIDService)) grpc_prometheus.Register(grpcServer) return grpcServer diff --git a/server/workflow/workflow_server.go b/server/workflow/workflow_server.go index 0cc4731e60e9..13ea6d756878 100644 --- a/server/workflow/workflow_server.go +++ b/server/workflow/workflow_server.go @@ -324,10 +324,16 @@ func (s *workflowServer) RetryWorkflow(ctx context.Context, req *workflowpkg.Wor return nil, err } - wf, err = util.RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wfClient.ArgoprojV1alpha1().Workflows(req.Namespace), wf.Name, req.RestartSuccessful, req.NodeFieldSelector) + wf, err = util.RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.Namespace), wfClient.ArgoprojV1alpha1().Workflows(req.Namespace), wf, req.RestartSuccessful, req.NodeFieldSelector) if err != nil { return nil, err } + + wf, err = wfClient.ArgoprojV1alpha1().Workflows(req.Namespace).Update(ctx, wf, metav1.UpdateOptions{}) + if err != nil { + return nil, err + } + return wf, nil } diff --git a/server/workflowarchive/archived_workflow_server.go b/server/workflowarchive/archived_workflow_server.go index 3790ebbe28a8..7270981cc851 100644 --- a/server/workflowarchive/archived_workflow_server.go +++ b/server/workflowarchive/archived_workflow_server.go @@ -10,6 +10,7 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + apierr "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/selection" @@ -19,18 +20,17 @@ import ( "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow" wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" "github.com/argoproj/argo-workflows/v3/server/auth" - "github.com/argoproj/argo-workflows/v3/workflow/hydrator" "github.com/argoproj/argo-workflows/v3/workflow/util" ) type archivedWorkflowServer struct { wfArchive sqldb.WorkflowArchive - hydrator hydrator.Interface + // hydrator hydrator.Interface } // NewWorkflowArchiveServer returns a new archivedWorkflowServer -func NewWorkflowArchiveServer(wfArchive sqldb.WorkflowArchive, offloadNodeStatusRepo sqldb.OffloadNodeStatusRepo) workflowarchivepkg.ArchivedWorkflowServiceServer { - return &archivedWorkflowServer{wfArchive: wfArchive, hydrator: hydrator.New(offloadNodeStatusRepo)} +func NewWorkflowArchiveServer(wfArchive sqldb.WorkflowArchive) workflowarchivepkg.ArchivedWorkflowServiceServer { + return &archivedWorkflowServer{wfArchive: wfArchive} } func (w *archivedWorkflowServer) ListArchivedWorkflows(ctx context.Context, req *workflowarchivepkg.ListArchivedWorkflowsRequest) (*wfv1.WorkflowList, error) { @@ -201,14 +201,17 @@ func (w *archivedWorkflowServer) RetryArchivedWorkflow(ctx context.Context, req return nil, err } - err = w.hydrator.Hydrate(wf) + wf, err = util.RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.Namespace), wfClient.ArgoprojV1alpha1().Workflows(req.Namespace), wf, req.RestartSuccessful, req.NodeFieldSelector) if err != nil { return nil, err } - wf, err = util.RetryArchiveWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wfClient.ArgoprojV1alpha1().Workflows(req.Namespace), wf, req.RestartSuccessful, req.NodeFieldSelector) + wf, err = wfClient.ArgoprojV1alpha1().Workflows(req.Namespace).Create(ctx, wf, metav1.CreateOptions{}) if err != nil { - return nil, err + if apierr.IsAlreadyExists(err) { + return nil, fmt.Errorf("workflow already exists : %s", err) + } + return nil, fmt.Errorf("unable to create workflow: %s", err) } return wf, nil diff --git a/server/workflowarchive/archived_workflow_server_test.go b/server/workflowarchive/archived_workflow_server_test.go index b10170b3c7a2..dbc1b7d0c320 100644 --- a/server/workflowarchive/archived_workflow_server_test.go +++ b/server/workflowarchive/archived_workflow_server_test.go @@ -6,7 +6,6 @@ import ( "time" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" authorizationv1 "k8s.io/api/authorization/v1" @@ -17,7 +16,6 @@ import ( kubefake "k8s.io/client-go/kubernetes/fake" k8stesting "k8s.io/client-go/testing" - "github.com/argoproj/argo-workflows/v3/persist/sqldb" "github.com/argoproj/argo-workflows/v3/persist/sqldb/mocks" workflowarchivepkg "github.com/argoproj/argo-workflows/v3/pkg/apiclient/workflowarchive" wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" @@ -30,10 +28,7 @@ func Test_archivedWorkflowServer(t *testing.T) { repo := &mocks.WorkflowArchive{} kubeClient := &kubefake.Clientset{} wfClient := &argofake.Clientset{} - offloadNodeStatusRepo := &mocks.OffloadNodeStatusRepo{} - offloadNodeStatusRepo.On("IsEnabled", mock.Anything).Return(true) - offloadNodeStatusRepo.On("List", mock.Anything).Return(map[sqldb.UUIDVersion]wfv1.Nodes{}, nil) - w := NewWorkflowArchiveServer(repo, offloadNodeStatusRepo) + w := NewWorkflowArchiveServer(repo) allowed := true kubeClient.AddReactor("create", "selfsubjectaccessreviews", func(action k8stesting.Action) (handled bool, ret runtime.Object, err error) { return true, &authorizationv1.SelfSubjectAccessReview{ diff --git a/workflow/util/util.go b/workflow/util/util.go index 2f74cccef73c..487f1fb1aa6c 100644 --- a/workflow/util/util.go +++ b/workflow/util/util.go @@ -735,51 +735,15 @@ func convertNodeID(newWf *wfv1.Workflow, regex *regexp.Regexp, oldNodeID string, } // RetryWorkflow updates a workflow, deleting all failed steps as well as the onExit node (and children) -func RetryWorkflow(ctx context.Context, podIf v1.PodInterface, wfClient v1alpha1.WorkflowInterface, name string, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { - var updatedWf *wfv1.Workflow - err := waitutil.Backoff(retry.DefaultRetry, func() (bool, error) { - var err error - wf, err := wfClient.Get(ctx, name, metav1.GetOptions{}) - if err != nil { - return false, err - } - updatedWf, err = prepareWorkflowForRetry(ctx, wf, podIf, restartSuccessful, nodeFieldSelector) - if err != nil { - return false, err - } - updatedWf, err = wfClient.Update(ctx, updatedWf, metav1.UpdateOptions{}) - if err != nil { - return false, err - } - return !errorsutil.IsTransientErr(err), err - }) +func RetryWorkflow(ctx context.Context, podIf v1.PodInterface, wfClient v1alpha1.WorkflowInterface, wf *wfv1.Workflow, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { + updatedWf, err := prepareWorkflowForRetry(ctx, wf, podIf, restartSuccessful, nodeFieldSelector) + if err != nil { + return nil, err + } return updatedWf, err } -// RetryArchiveWorkflow recreates and updates a workflow -func RetryArchiveWorkflow(ctx context.Context, podIf v1.PodInterface, wfClient v1alpha1.WorkflowInterface, wf *wfv1.Workflow, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { - var updated *wfv1.Workflow - err := waitutil.Backoff(retry.DefaultRetry, func() (bool, error) { - var err error - updated, err = prepareWorkflowForRetry(ctx, wf, podIf, restartSuccessful, nodeFieldSelector) - if err != nil { - return false, err - } - updated, err = wfClient.Create(ctx, updated, metav1.CreateOptions{}) - if err != nil { - if apierr.IsAlreadyExists(err) { - return false, fmt.Errorf("workflow already exists : %s", err) - } - return false, fmt.Errorf("unable to create workflow: %s", err) - } - return !errorsutil.IsTransientErr(err), err - }) - - return updated, err -} - -// should not take any client func prepareWorkflowForRetry(ctx context.Context, wf *wfv1.Workflow, podIf v1.PodInterface, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { switch wf.Status.Phase { diff --git a/workflow/util/util_test.go b/workflow/util/util_test.go index c19dd7a37007..a788b1bbe9fd 100644 --- a/workflow/util/util_test.go +++ b/workflow/util/util_test.go @@ -811,7 +811,7 @@ func TestDeepDeleteNodes(t *testing.T) { ctx := context.Background() wf, err := wfIf.Create(ctx, origWf, metav1.CreateOptions{}) if assert.NoError(t, err) { - newWf, err := RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wfIf, wf.Name, false, "") + newWf, err := RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wfIf, wf, false, "") assert.NoError(t, err) newWfBytes, err := yaml.Marshal(newWf) assert.NoError(t, err) @@ -845,7 +845,7 @@ func TestRetryWorkflow(t *testing.T) { } _, err := wfClient.Create(ctx, wf, metav1.CreateOptions{}) assert.NoError(t, err) - wf, err = RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wfClient, wf.Name, false, "") + wf, err = RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.Namespace), wfClient, wf, false, "") if assert.NoError(t, err) { assert.Equal(t, wfv1.WorkflowRunning, wf.Status.Phase) assert.Equal(t, metav1.Time{}, wf.Status.FinishedAt) @@ -882,7 +882,7 @@ func TestRetryWorkflow(t *testing.T) { } _, err := wfClient.Create(ctx, wf, metav1.CreateOptions{}) assert.NoError(t, err) - wf, err = RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wfClient, wf.Name, false, "") + wf, err = RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wfClient, wf, false, "") if assert.NoError(t, err) { if assert.Len(t, wf.Status.Nodes, 1) { assert.Equal(t, wfv1.NodeRunning, wf.Status.Nodes[""].Phase) @@ -892,60 +892,6 @@ func TestRetryWorkflow(t *testing.T) { }) } -func TestRetryArchiveWorkflow(t *testing.T) { - ctx := context.Background() - kubeClient := kubefake.NewSimpleClientset() - wfClient := argofake.NewSimpleClientset().ArgoprojV1alpha1().Workflows("my-ns") - createdTime := metav1.Time{Time: time.Now().UTC()} - finishedTime := metav1.Time{Time: createdTime.Add(time.Second * 2)} - t.Run("Steps", func(t *testing.T) { - wf := &wfv1.Workflow{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-steps", - Labels: map[string]string{ - common.LabelKeyCompleted: "true", - common.LabelKeyWorkflowArchivingStatus: "Pending", - }, - }, - Status: wfv1.WorkflowStatus{ - Phase: wfv1.WorkflowFailed, - StartedAt: createdTime, - FinishedAt: finishedTime, - Nodes: map[string]wfv1.NodeStatus{ - "failed-node": {Name: "failed-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeFailed, Message: "failed"}, - "succeeded-node": {Name: "succeeded-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeSucceeded, Message: "succeeded"}}, - }, - } - - // simulate retrying workflow from workflowArchive - wf, err := RetryArchiveWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wfClient, wf, false, "") - if assert.NoError(t, err) { - assert.Equal(t, wfv1.WorkflowRunning, wf.Status.Phase) - assert.Equal(t, metav1.Time{}, wf.Status.FinishedAt) - assert.True(t, wf.Status.StartedAt.After(createdTime.Time)) - assert.NotContains(t, wf.Labels, common.LabelKeyCompleted) - assert.NotContains(t, wf.Labels, common.LabelKeyWorkflowArchivingStatus) - for _, node := range wf.Status.Nodes { - switch node.Phase { - case wfv1.NodeSucceeded: - assert.Equal(t, "succeeded", node.Message) - assert.Equal(t, wfv1.NodeSucceeded, node.Phase) - assert.Equal(t, createdTime, node.StartedAt) - assert.Equal(t, finishedTime, node.FinishedAt) - case wfv1.NodeFailed: - assert.Equal(t, "", node.Message) - assert.Equal(t, wfv1.NodeRunning, node.Phase) - assert.Equal(t, metav1.Time{}, node.FinishedAt) - assert.True(t, node.StartedAt.After(createdTime.Time)) - } - } - } - // retry on workflow that already exists - _, err = RetryArchiveWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wfClient, wf, false, "") - assert.Error(t, err) - }) -} - func TestFromUnstructuredObj(t *testing.T) { un := &unstructured.Unstructured{} wfv1.MustUnmarshal([]byte(`apiVersion: argoproj.io/v1alpha1 From be9b1d914d0ac308bae402f424565258c8c2c40e Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Wed, 2 Mar 2022 13:44:47 -0800 Subject: [PATCH 09/28] chore: remove comments Signed-off-by: Dillen Padhiar --- server/workflowarchive/archived_workflow_server.go | 1 - 1 file changed, 1 deletion(-) diff --git a/server/workflowarchive/archived_workflow_server.go b/server/workflowarchive/archived_workflow_server.go index 7270981cc851..ab6b3d3736f5 100644 --- a/server/workflowarchive/archived_workflow_server.go +++ b/server/workflowarchive/archived_workflow_server.go @@ -25,7 +25,6 @@ import ( type archivedWorkflowServer struct { wfArchive sqldb.WorkflowArchive - // hydrator hydrator.Interface } // NewWorkflowArchiveServer returns a new archivedWorkflowServer From cee8d76b27d3091da42c44032d4ec831202704b3 Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Wed, 2 Mar 2022 14:08:35 -0800 Subject: [PATCH 10/28] fix: ignored AlreadyExists err for idempotence Signed-off-by: Dillen Padhiar --- server/workflowarchive/archived_workflow_server.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/server/workflowarchive/archived_workflow_server.go b/server/workflowarchive/archived_workflow_server.go index ab6b3d3736f5..7bd151a20d41 100644 --- a/server/workflowarchive/archived_workflow_server.go +++ b/server/workflowarchive/archived_workflow_server.go @@ -10,7 +10,6 @@ import ( "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - apierr "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/selection" @@ -207,10 +206,7 @@ func (w *archivedWorkflowServer) RetryArchivedWorkflow(ctx context.Context, req wf, err = wfClient.ArgoprojV1alpha1().Workflows(req.Namespace).Create(ctx, wf, metav1.CreateOptions{}) if err != nil { - if apierr.IsAlreadyExists(err) { - return nil, fmt.Errorf("workflow already exists : %s", err) - } - return nil, fmt.Errorf("unable to create workflow: %s", err) + return nil, err } return wf, nil From aede75eb6fd7b5a507fbb1520460e315dcd53e6a Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Wed, 2 Mar 2022 15:04:02 -0800 Subject: [PATCH 11/28] fix: dehydrate workflow in RetryWorkflow Signed-off-by: Dillen Padhiar --- server/workflow/workflow_server.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/server/workflow/workflow_server.go b/server/workflow/workflow_server.go index 13ea6d756878..eb10b1108915 100644 --- a/server/workflow/workflow_server.go +++ b/server/workflow/workflow_server.go @@ -329,6 +329,11 @@ func (s *workflowServer) RetryWorkflow(ctx context.Context, req *workflowpkg.Wor return nil, err } + err = s.hydrator.Dehydrate(wf) + if err != nil { + return nil, err + } + wf, err = wfClient.ArgoprojV1alpha1().Workflows(req.Namespace).Update(ctx, wf, metav1.UpdateOptions{}) if err != nil { return nil, err From a8d10b779b1c02e506c21b330d7d34710371f75f Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Thu, 3 Mar 2022 08:23:35 -0800 Subject: [PATCH 12/28] test: add e2e test for RetryArchiveWorkflow Signed-off-by: Dillen Padhiar --- test/e2e/argo_server_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/e2e/argo_server_test.go b/test/e2e/argo_server_test.go index 2d264d487b4a..98d49f824747 100644 --- a/test/e2e/argo_server_test.go +++ b/test/e2e/argo_server_test.go @@ -1336,6 +1336,14 @@ spec: Equal(1) }) + s.Run("RetryArchivedWorkflow", func() { + s.e().PUT("/api/v1/archived-workflows/{uid}/retry", uid). + Expect(). + Status(200). + Path("$.metadata.name"). + NotNull() + }) + } func (s *ArgoServerSuite) TestWorkflowTemplateService() { From 7f41a18f5318ff33658c4b6b9d1ca1b87aff044e Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Thu, 3 Mar 2022 08:50:44 -0800 Subject: [PATCH 13/28] test: fix syntax error for RetryArchiveWorkflow test Signed-off-by: Dillen Padhiar --- test/e2e/argo_server_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/test/e2e/argo_server_test.go b/test/e2e/argo_server_test.go index 98d49f824747..ed21ca476ef0 100644 --- a/test/e2e/argo_server_test.go +++ b/test/e2e/argo_server_test.go @@ -1340,6 +1340,7 @@ spec: s.e().PUT("/api/v1/archived-workflows/{uid}/retry", uid). Expect(). Status(200). + JSON(). Path("$.metadata.name"). NotNull() }) From 1eff8ed6cbd440f63672ed68bdca764a08a74979 Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Thu, 3 Mar 2022 13:16:19 -0800 Subject: [PATCH 14/28] test: update test for RetryArchivedWorkflow Signed-off-by: Dillen Padhiar --- test/e2e/argo_server_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/argo_server_test.go b/test/e2e/argo_server_test.go index ed21ca476ef0..3c296eecadb2 100644 --- a/test/e2e/argo_server_test.go +++ b/test/e2e/argo_server_test.go @@ -1336,8 +1336,8 @@ spec: Equal(1) }) - s.Run("RetryArchivedWorkflow", func() { - s.e().PUT("/api/v1/archived-workflows/{uid}/retry", uid). + s.Run("Retry", func() { + s.e().PUT("/api/v1/archived-workflows/argo/{uid}/retry", uid). Expect(). Status(200). JSON(). From 3eb2c94adfe3cc5af549a642a592fb3d25e880ab Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Thu, 3 Mar 2022 15:15:05 -0800 Subject: [PATCH 15/28] fix: change request for RetryArchivedWorkflow Signed-off-by: Dillen Padhiar --- api/openapi-spec/swagger.json | 48 +++++----- .../archived-workflows-service-client.go | 2 +- .../workflowarchive/workflow-archive.pb.go | 90 +++++++++---------- .../workflowarchive/workflow-archive.pb.gw.go | 24 +---- .../workflowarchive/workflow-archive.proto | 2 +- .../client/docs/ArchivedWorkflowServiceApi.md | 8 +- .../api/archived_workflow_service_api.py | 14 +-- .../client/docs/ArchivedWorkflowServiceApi.md | 8 +- 8 files changed, 77 insertions(+), 119 deletions(-) diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index 33d544d4b859..70b4dcd07966 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -204,32 +204,18 @@ } } }, - "/api/v1/archived-workflows/{namespace}/{uid}/retry": { - "put": { + "/api/v1/archived-workflows/{uid}": { + "get": { "tags": [ "ArchivedWorkflowService" ], - "operationId": "ArchivedWorkflowService_RetryArchivedWorkflow", + "operationId": "ArchivedWorkflowService_GetArchivedWorkflow", "parameters": [ - { - "type": "string", - "name": "namespace", - "in": "path", - "required": true - }, { "type": "string", "name": "uid", "in": "path", "required": true - }, - { - "name": "body", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.RetryArchivedWorkflowRequest" - } } ], "responses": { @@ -246,14 +232,12 @@ } } } - } - }, - "/api/v1/archived-workflows/{uid}": { - "get": { + }, + "delete": { "tags": [ "ArchivedWorkflowService" ], - "operationId": "ArchivedWorkflowService_GetArchivedWorkflow", + "operationId": "ArchivedWorkflowService_DeleteArchivedWorkflow", "parameters": [ { "type": "string", @@ -266,7 +250,7 @@ "200": { "description": "A successful response.", "schema": { - "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.Workflow" + "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.ArchivedWorkflowDeletedResponse" } }, "default": { @@ -276,25 +260,35 @@ } } } - }, - "delete": { + } + }, + "/api/v1/archived-workflows/{uid}/retry": { + "put": { "tags": [ "ArchivedWorkflowService" ], - "operationId": "ArchivedWorkflowService_DeleteArchivedWorkflow", + "operationId": "ArchivedWorkflowService_RetryArchivedWorkflow", "parameters": [ { "type": "string", "name": "uid", "in": "path", "required": true + }, + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.RetryArchivedWorkflowRequest" + } } ], "responses": { "200": { "description": "A successful response.", "schema": { - "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.ArchivedWorkflowDeletedResponse" + "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.Workflow" } }, "default": { diff --git a/pkg/apiclient/http1/archived-workflows-service-client.go b/pkg/apiclient/http1/archived-workflows-service-client.go index ba1e0f8edd9e..7229c4beb56e 100644 --- a/pkg/apiclient/http1/archived-workflows-service-client.go +++ b/pkg/apiclient/http1/archived-workflows-service-client.go @@ -49,5 +49,5 @@ func (h ArchivedWorkflowsServiceClient) ListArchivedWorkflowLabelValues(_ contex func (h ArchivedWorkflowsServiceClient) RetryArchivedWorkflow(_ context.Context, in *workflowarchivepkg.RetryArchivedWorkflowRequest, _ ...grpc.CallOption) (*wfv1.Workflow, error) { out := &wfv1.Workflow{} - return out, h.Get(in, out, "/api/v1/archived-workflows/{namespace}/{uid}/retry") + return out, h.Get(in, out, "/api/v1/archived-workflows/{uid}/retry") } diff --git a/pkg/apiclient/workflowarchive/workflow-archive.pb.go b/pkg/apiclient/workflowarchive/workflow-archive.pb.go index 9cb5b79a53a6..ce205bd2f6ae 100644 --- a/pkg/apiclient/workflowarchive/workflow-archive.pb.go +++ b/pkg/apiclient/workflowarchive/workflow-archive.pb.go @@ -399,51 +399,51 @@ func init() { } var fileDescriptor_95ca9a2d33e8bb19 = []byte{ - // 697 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x96, 0xcb, 0x6e, 0xd3, 0x4c, - 0x14, 0xc7, 0x35, 0x6d, 0xbf, 0x4f, 0x64, 0xba, 0x00, 0x06, 0x15, 0x22, 0x2b, 0x4d, 0x83, 0x05, - 0x6d, 0x28, 0x64, 0x4c, 0xda, 0xa2, 0x22, 0x24, 0x24, 0x40, 0x08, 0x24, 0x7a, 0x01, 0x25, 0x12, - 0x48, 0x6c, 0xd0, 0xd4, 0x3e, 0x4d, 0x86, 0x38, 0x1e, 0x33, 0x33, 0x71, 0xa9, 0x50, 0x37, 0xbc, - 0x42, 0x5f, 0x81, 0x87, 0x40, 0x2c, 0xba, 0x66, 0xc9, 0x65, 0xc7, 0x0a, 0x55, 0x3c, 0x08, 0xb2, - 0x1d, 0x27, 0x25, 0x76, 0x2e, 0x12, 0x65, 0x95, 0xc9, 0x99, 0x33, 0x7f, 0xff, 0xce, 0xc9, 0xf9, - 0x8f, 0x83, 0xd7, 0xfc, 0x56, 0xc3, 0x62, 0x3e, 0xb7, 0x5d, 0x0e, 0x9e, 0xb6, 0xf6, 0x84, 0x6c, - 0xed, 0xba, 0x62, 0x8f, 0x49, 0xbb, 0xc9, 0x03, 0xe8, 0x7d, 0xaf, 0x74, 0x03, 0xd4, 0x97, 0x42, - 0x0b, 0x72, 0x76, 0x20, 0xcf, 0x28, 0x34, 0x84, 0x68, 0xb8, 0x10, 0x2a, 0x59, 0xcc, 0xf3, 0x84, - 0x66, 0x9a, 0x0b, 0x4f, 0xc5, 0xe9, 0xc6, 0x5a, 0xeb, 0xb6, 0xa2, 0x5c, 0x84, 0xbb, 0x6d, 0x66, - 0x37, 0xb9, 0x07, 0x72, 0xdf, 0xea, 0x3e, 0x58, 0x59, 0x6d, 0xd0, 0xcc, 0x0a, 0xaa, 0x56, 0x03, - 0x3c, 0x90, 0x4c, 0x83, 0xd3, 0x3d, 0xb5, 0xd5, 0xe0, 0xba, 0xd9, 0xd9, 0xa1, 0xb6, 0x68, 0x5b, - 0x4c, 0x36, 0x84, 0x2f, 0xc5, 0xeb, 0x68, 0x51, 0x49, 0x9e, 0xae, 0xfa, 0x22, 0x49, 0xc8, 0x0a, - 0xaa, 0xcc, 0xf5, 0x9b, 0x2c, 0x25, 0x67, 0x1e, 0x22, 0x5c, 0xd8, 0xe4, 0x4a, 0xdf, 0x8f, 0x91, - 0x9d, 0x17, 0x89, 0x48, 0x0d, 0xde, 0x74, 0x40, 0x69, 0x52, 0xc7, 0xb3, 0x2e, 0x57, 0xfa, 0xa9, - 0x1f, 0xa1, 0xe7, 0x51, 0x09, 0x95, 0x67, 0x57, 0xaa, 0x34, 0x66, 0xa7, 0x27, 0xd9, 0xa9, 0xdf, - 0x6a, 0x84, 0x01, 0x45, 0x43, 0x76, 0x1a, 0x54, 0xe9, 0x66, 0xff, 0x60, 0xed, 0xa4, 0x0a, 0x29, - 0x62, 0xec, 0xb1, 0x36, 0x3c, 0x93, 0xb0, 0xcb, 0xdf, 0xe6, 0xa7, 0x4a, 0xa8, 0x9c, 0xab, 0x9d, - 0x88, 0x98, 0x14, 0x1b, 0x8f, 0x21, 0xc5, 0x94, 0x20, 0x9d, 0xc3, 0xd3, 0x1d, 0xee, 0x44, 0x28, - 0xb9, 0x5a, 0xb8, 0x34, 0xab, 0x78, 0xfe, 0x21, 0xb8, 0xa0, 0x61, 0xf2, 0x23, 0x97, 0xf1, 0xc2, - 0x60, 0x72, 0x2c, 0xe1, 0xd4, 0x40, 0xf9, 0xc2, 0x53, 0x60, 0x2e, 0xe2, 0x2b, 0x59, 0xad, 0xd9, - 0x64, 0x3b, 0xe0, 0x6e, 0xc0, 0x7e, 0xd2, 0x22, 0xf3, 0x00, 0x2f, 0x0e, 0xcd, 0x7b, 0xce, 0xdc, - 0x0e, 0xfc, 0xd3, 0x66, 0x9a, 0x47, 0x08, 0x17, 0x6a, 0xa0, 0xe5, 0xfe, 0xc4, 0xc5, 0x13, 0x82, - 0x67, 0xc2, 0x6e, 0x77, 0x3b, 0x1f, 0xad, 0x49, 0x01, 0xe7, 0xc2, 0x4f, 0xe5, 0x33, 0x1b, 0xf2, - 0xd3, 0xd1, 0x46, 0x3f, 0x40, 0x6e, 0xe0, 0xf3, 0x12, 0x94, 0x66, 0x52, 0xd7, 0x3b, 0xb6, 0x0d, - 0x4a, 0xed, 0x76, 0xdc, 0xfc, 0x4c, 0x09, 0x95, 0xcf, 0xd4, 0xd2, 0x1b, 0x61, 0xb6, 0x27, 0x1c, - 0x78, 0xc4, 0xc1, 0x75, 0xea, 0xe0, 0x82, 0xad, 0x85, 0xcc, 0xff, 0x17, 0x69, 0xa6, 0x37, 0x56, - 0x8e, 0x72, 0xf8, 0xd2, 0x20, 0x7b, 0x1d, 0x64, 0xc0, 0x6d, 0x20, 0x9f, 0x10, 0x9e, 0xcb, 0x9c, - 0x4f, 0x52, 0xa1, 0x03, 0x76, 0xa3, 0xa3, 0xe6, 0xd8, 0xd8, 0xa6, 0x7d, 0xe3, 0xd0, 0xc4, 0x38, - 0xd1, 0xe2, 0x55, 0xcf, 0x38, 0x34, 0x58, 0xed, 0xf7, 0x3d, 0x89, 0xd2, 0xc4, 0x3b, 0xb4, 0xf7, - 0xc3, 0x72, 0xa5, 0x4d, 0xf3, 0xfd, 0xf7, 0x5f, 0x87, 0x53, 0x05, 0x62, 0x44, 0xee, 0x0e, 0xaa, - 0x56, 0x97, 0xc2, 0xe9, 0xfb, 0x90, 0x7c, 0x44, 0xf8, 0x42, 0xc6, 0x1c, 0x93, 0xeb, 0x29, 0xf4, - 0xe1, 0xd3, 0x6e, 0x3c, 0x39, 0x3d, 0x70, 0xb3, 0x1c, 0x41, 0x9b, 0xa4, 0x34, 0x1c, 0xda, 0x7a, - 0xd7, 0xe1, 0xce, 0x01, 0xf9, 0x80, 0xf0, 0xc5, 0x6c, 0x4b, 0x11, 0x9a, 0xa2, 0x1f, 0xe9, 0x3d, - 0xe3, 0x66, 0x2a, 0x7f, 0x9c, 0xf1, 0xba, 0x98, 0xcb, 0xe3, 0x31, 0xbf, 0x21, 0x3c, 0x3f, 0xd2, - 0xa3, 0xe4, 0xd6, 0x44, 0x63, 0x32, 0xe8, 0x69, 0x63, 0xe3, 0xef, 0xbb, 0xde, 0xd3, 0x34, 0x2b, - 0x51, 0x3d, 0x4b, 0xe4, 0xea, 0xf0, 0x7a, 0x2a, 0x6e, 0x98, 0x5d, 0x69, 0x85, 0xc8, 0x3f, 0x10, - 0x5e, 0x18, 0x73, 0xa1, 0x90, 0xf5, 0xc9, 0xcb, 0xfa, 0xe3, 0x0a, 0x32, 0xb6, 0x4e, 0xa9, 0xb0, - 0x58, 0xd5, 0xb4, 0xa2, 0xd2, 0xae, 0x91, 0xa5, 0xb1, 0xa5, 0x05, 0x31, 0xf8, 0x57, 0x84, 0xe7, - 0x32, 0x6f, 0xab, 0x0c, 0x43, 0x8f, 0xba, 0xd5, 0x4e, 0xd5, 0x17, 0x77, 0xa3, 0x2a, 0xd6, 0x8d, - 0x95, 0x51, 0x03, 0xd7, 0xbb, 0x0c, 0x0f, 0xe2, 0xe1, 0xb3, 0x64, 0x88, 0x77, 0x07, 0x2d, 0x3f, - 0xd8, 0xfe, 0x7c, 0x5c, 0x44, 0x5f, 0x8e, 0x8b, 0xe8, 0xe7, 0x71, 0x11, 0xbd, 0xbc, 0x37, 0xf9, - 0x1b, 0x3a, 0xfb, 0xff, 0xc5, 0xce, 0xff, 0xd1, 0xbb, 0x79, 0xf5, 0x77, 0x00, 0x00, 0x00, 0xff, - 0xff, 0xf2, 0x1e, 0x92, 0x1c, 0x87, 0x08, 0x00, 0x00, + // 690 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x96, 0xcd, 0x6e, 0xd3, 0x40, + 0x10, 0xc7, 0xb5, 0x6d, 0x41, 0x64, 0x7b, 0x00, 0x16, 0x15, 0x22, 0x2b, 0x4d, 0x83, 0x05, 0x6d, + 0x68, 0xc9, 0x9a, 0xb4, 0x45, 0x20, 0x4e, 0x80, 0x10, 0x48, 0xf4, 0x03, 0x94, 0x48, 0x20, 0x71, + 0x41, 0x5b, 0x7b, 0x9a, 0x2c, 0x71, 0xbc, 0x66, 0x77, 0xed, 0x52, 0xa1, 0x5e, 0x78, 0x85, 0xbe, + 0x02, 0x4f, 0xc0, 0x09, 0x71, 0xe0, 0x86, 0xc4, 0x11, 0xc1, 0x8d, 0x13, 0xaa, 0x78, 0x10, 0x64, + 0x27, 0x4e, 0x4a, 0xec, 0x7c, 0x48, 0x94, 0x53, 0x36, 0xb3, 0xb3, 0x7f, 0xff, 0x66, 0x32, 0xff, + 0x75, 0xf0, 0xba, 0xdf, 0x6a, 0x58, 0xcc, 0xe7, 0xb6, 0xcb, 0xc1, 0xd3, 0xd6, 0x9e, 0x90, 0xad, + 0x5d, 0x57, 0xec, 0x31, 0x69, 0x37, 0x79, 0x08, 0xbd, 0xef, 0x95, 0x6e, 0x80, 0xfa, 0x52, 0x68, + 0x41, 0xce, 0x0e, 0xe4, 0x19, 0x85, 0x86, 0x10, 0x0d, 0x17, 0x22, 0x25, 0x8b, 0x79, 0x9e, 0xd0, + 0x4c, 0x73, 0xe1, 0xa9, 0x4e, 0xba, 0xb1, 0xde, 0xba, 0xad, 0x28, 0x17, 0xd1, 0x6e, 0x9b, 0xd9, + 0x4d, 0xee, 0x81, 0xdc, 0xb7, 0xba, 0x0f, 0x56, 0x56, 0x1b, 0x34, 0xb3, 0xc2, 0xaa, 0xd5, 0x00, + 0x0f, 0x24, 0xd3, 0xe0, 0x74, 0x4f, 0x6d, 0x35, 0xb8, 0x6e, 0x06, 0x3b, 0xd4, 0x16, 0x6d, 0x8b, + 0xc9, 0x86, 0xf0, 0xa5, 0x78, 0x15, 0x2f, 0x2a, 0xc9, 0xd3, 0x55, 0x5f, 0x24, 0x09, 0x59, 0x61, + 0x95, 0xb9, 0x7e, 0x93, 0xa5, 0xe4, 0xcc, 0x43, 0x84, 0x0b, 0x9b, 0x5c, 0xe9, 0x7b, 0x1d, 0x64, + 0xe7, 0x79, 0x22, 0x52, 0x83, 0xd7, 0x01, 0x28, 0x4d, 0xea, 0x78, 0xd6, 0xe5, 0x4a, 0x3f, 0xf1, + 0x63, 0xf4, 0x3c, 0x2a, 0xa1, 0xf2, 0xec, 0x6a, 0x95, 0x76, 0xd8, 0xe9, 0x71, 0x76, 0xea, 0xb7, + 0x1a, 0x51, 0x40, 0xd1, 0x88, 0x9d, 0x86, 0x55, 0xba, 0xd9, 0x3f, 0x58, 0x3b, 0xae, 0x42, 0x8a, + 0x18, 0x7b, 0xac, 0x0d, 0x4f, 0x25, 0xec, 0xf2, 0x37, 0xf9, 0xa9, 0x12, 0x2a, 0xe7, 0x6a, 0xc7, + 0x22, 0x26, 0xc5, 0xc6, 0x23, 0x48, 0x31, 0x25, 0x48, 0xe7, 0xf0, 0x74, 0xc0, 0x9d, 0x18, 0x25, + 0x57, 0x8b, 0x96, 0x66, 0x15, 0xcf, 0x3f, 0x00, 0x17, 0x34, 0x4c, 0x7e, 0xe4, 0x32, 0x5e, 0x18, + 0x4c, 0xee, 0x48, 0x38, 0x35, 0x50, 0xbe, 0xf0, 0x14, 0x98, 0x8b, 0xf8, 0x4a, 0x56, 0x6b, 0x36, + 0xd9, 0x0e, 0xb8, 0x1b, 0xb0, 0x9f, 0xb4, 0xc8, 0x3c, 0xc0, 0x8b, 0x43, 0xf3, 0x9e, 0x31, 0x37, + 0x80, 0xff, 0xda, 0x4c, 0xf3, 0x33, 0xc2, 0x85, 0x1a, 0x68, 0xb9, 0x3f, 0x71, 0xf1, 0x84, 0xe0, + 0x99, 0xa8, 0xdb, 0xdd, 0xce, 0xc7, 0x6b, 0x52, 0xc0, 0xb9, 0xe8, 0x53, 0xf9, 0xcc, 0x86, 0xfc, + 0x74, 0xbc, 0xd1, 0x0f, 0x90, 0xeb, 0xf8, 0xbc, 0x04, 0xa5, 0x99, 0xd4, 0xf5, 0xc0, 0xb6, 0x41, + 0xa9, 0xdd, 0xc0, 0xcd, 0xcf, 0x94, 0x50, 0xf9, 0x4c, 0x2d, 0xbd, 0x11, 0x65, 0x7b, 0xc2, 0x81, + 0x87, 0x1c, 0x5c, 0xa7, 0x0e, 0x2e, 0xd8, 0x5a, 0xc8, 0xfc, 0xa9, 0x58, 0x33, 0xbd, 0xb1, 0xfa, + 0x21, 0x87, 0x2f, 0x0d, 0xb2, 0xd7, 0x41, 0x86, 0xdc, 0x06, 0xf2, 0x09, 0xe1, 0xb9, 0xcc, 0xf9, + 0x24, 0x15, 0x3a, 0x60, 0x37, 0x3a, 0x6a, 0x8e, 0x8d, 0x6d, 0xda, 0x37, 0x0e, 0x4d, 0x8c, 0x13, + 0x2f, 0x5e, 0xf6, 0x8c, 0x43, 0xc3, 0xb5, 0x7e, 0xdf, 0x93, 0x28, 0x4d, 0xbc, 0x43, 0x7b, 0x3f, + 0x2c, 0x57, 0xda, 0x34, 0xdf, 0xfd, 0xf8, 0x7d, 0x38, 0x55, 0x20, 0x46, 0xec, 0xee, 0xb0, 0x6a, + 0x75, 0x29, 0x9c, 0xbe, 0x0f, 0xc9, 0x47, 0x84, 0x2f, 0x64, 0xcc, 0x31, 0x59, 0x49, 0xa1, 0x0f, + 0x9f, 0x76, 0xe3, 0xf1, 0xc9, 0x81, 0x9b, 0xe5, 0x18, 0xda, 0x24, 0xa5, 0xe1, 0xd0, 0xd6, 0xdb, + 0x80, 0x3b, 0x07, 0xe4, 0x3d, 0xc2, 0x17, 0xb3, 0x2d, 0x45, 0x68, 0x8a, 0x7e, 0xa4, 0xf7, 0x8c, + 0x1b, 0xa9, 0xfc, 0x71, 0xc6, 0xeb, 0x62, 0x2e, 0x8f, 0xc7, 0xfc, 0x8e, 0xf0, 0xfc, 0x48, 0x8f, + 0x92, 0x9b, 0x13, 0x8d, 0xc9, 0xa0, 0xa7, 0x8d, 0x8d, 0x7f, 0xef, 0x7a, 0x4f, 0xd3, 0xac, 0xc4, + 0xf5, 0x2c, 0x91, 0xab, 0xc3, 0xeb, 0xa9, 0xb8, 0x51, 0x76, 0xa5, 0x15, 0x21, 0xff, 0x44, 0x78, + 0x61, 0xcc, 0x85, 0x42, 0x6e, 0x4d, 0x5e, 0xd6, 0x5f, 0x57, 0x90, 0xb1, 0x75, 0x42, 0x85, 0x75, + 0x54, 0x4d, 0x2b, 0x2e, 0xed, 0x1a, 0x59, 0x1a, 0x5b, 0x5a, 0xd8, 0x01, 0xff, 0x82, 0xf0, 0x5c, + 0xe6, 0x6d, 0x95, 0x61, 0xe8, 0x51, 0xb7, 0xda, 0x89, 0xfa, 0xa2, 0x1a, 0x57, 0xb1, 0x62, 0x2c, + 0x8e, 0x1b, 0x38, 0x4b, 0x46, 0x48, 0x77, 0xd0, 0xf2, 0xfd, 0xed, 0xaf, 0x47, 0x45, 0xf4, 0xed, + 0xa8, 0x88, 0x7e, 0x1d, 0x15, 0xd1, 0x8b, 0xbb, 0x93, 0xbf, 0x95, 0xb3, 0xff, 0x53, 0xec, 0x9c, + 0x8e, 0xdf, 0xc7, 0x6b, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xd8, 0x37, 0x16, 0xc9, 0x7b, 0x08, + 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. diff --git a/pkg/apiclient/workflowarchive/workflow-archive.pb.gw.go b/pkg/apiclient/workflowarchive/workflow-archive.pb.gw.go index d7b1311722dc..874e28443662 100644 --- a/pkg/apiclient/workflowarchive/workflow-archive.pb.gw.go +++ b/pkg/apiclient/workflowarchive/workflow-archive.pb.gw.go @@ -250,17 +250,6 @@ func request_ArchivedWorkflowService_RetryArchivedWorkflow_0(ctx context.Context _ = err ) - val, ok = pathParams["namespace"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") - } - - protoReq.Namespace, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) - } - val, ok = pathParams["uid"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "uid") @@ -296,17 +285,6 @@ func local_request_ArchivedWorkflowService_RetryArchivedWorkflow_0(ctx context.C _ = err ) - val, ok = pathParams["namespace"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "namespace") - } - - protoReq.Namespace, err = runtime.String(val) - - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "namespace", err) - } - val, ok = pathParams["uid"] if !ok { return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "uid") @@ -642,7 +620,7 @@ var ( pattern_ArchivedWorkflowService_ListArchivedWorkflowLabelValues_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"api", "v1", "archived-workflows-label-values"}, "", runtime.AssumeColonVerbOpt(true))) - pattern_ArchivedWorkflowService_RetryArchivedWorkflow_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 1, 0, 4, 1, 5, 4, 2, 5}, []string{"api", "v1", "archived-workflows", "namespace", "uid", "retry"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_ArchivedWorkflowService_RetryArchivedWorkflow_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4}, []string{"api", "v1", "archived-workflows", "uid", "retry"}, "", runtime.AssumeColonVerbOpt(true))) ) var ( diff --git a/pkg/apiclient/workflowarchive/workflow-archive.proto b/pkg/apiclient/workflowarchive/workflow-archive.proto index ff39dfe9a464..f8411d96589e 100644 --- a/pkg/apiclient/workflowarchive/workflow-archive.proto +++ b/pkg/apiclient/workflowarchive/workflow-archive.proto @@ -50,7 +50,7 @@ service ArchivedWorkflowService { } rpc RetryArchivedWorkflow (RetryArchivedWorkflowRequest) returns (github.com.argoproj.argo_workflows.v3.pkg.apis.workflow.v1alpha1.Workflow) { option (google.api.http) = { - put: "/api/v1/archived-workflows/{namespace}/{uid}/retry" + put: "/api/v1/archived-workflows/{uid}/retry" body: "*" }; } diff --git a/sdks/java/client/docs/ArchivedWorkflowServiceApi.md b/sdks/java/client/docs/ArchivedWorkflowServiceApi.md index 97cba1baae22..9d7c44905e3e 100644 --- a/sdks/java/client/docs/ArchivedWorkflowServiceApi.md +++ b/sdks/java/client/docs/ArchivedWorkflowServiceApi.md @@ -9,7 +9,7 @@ Method | HTTP request | Description [**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 | -[**archivedWorkflowServiceRetryArchivedWorkflow**](ArchivedWorkflowServiceApi.md#archivedWorkflowServiceRetryArchivedWorkflow) | **PUT** /api/v1/archived-workflows/{namespace}/{uid}/retry | +[**archivedWorkflowServiceRetryArchivedWorkflow**](ArchivedWorkflowServiceApi.md#archivedWorkflowServiceRetryArchivedWorkflow) | **PUT** /api/v1/archived-workflows/{uid}/retry | @@ -349,7 +349,7 @@ No authorization required # **archivedWorkflowServiceRetryArchivedWorkflow** -> IoArgoprojWorkflowV1alpha1Workflow archivedWorkflowServiceRetryArchivedWorkflow(namespace, uid, body) +> IoArgoprojWorkflowV1alpha1Workflow archivedWorkflowServiceRetryArchivedWorkflow(uid, body) @@ -368,11 +368,10 @@ public class Example { defaultClient.setBasePath("http://localhost:2746"); ArchivedWorkflowServiceApi apiInstance = new ArchivedWorkflowServiceApi(defaultClient); - String namespace = "namespace_example"; // String | String uid = "uid_example"; // String | IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest body = new IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest(); // IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest | try { - IoArgoprojWorkflowV1alpha1Workflow result = apiInstance.archivedWorkflowServiceRetryArchivedWorkflow(namespace, uid, body); + IoArgoprojWorkflowV1alpha1Workflow result = apiInstance.archivedWorkflowServiceRetryArchivedWorkflow(uid, body); System.out.println(result); } catch (ApiException e) { System.err.println("Exception when calling ArchivedWorkflowServiceApi#archivedWorkflowServiceRetryArchivedWorkflow"); @@ -389,7 +388,6 @@ public class Example { Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **namespace** | **String**| | **uid** | **String**| | **body** | [**IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest**](IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest.md)| | diff --git a/sdks/python/client/argo_workflows/api/archived_workflow_service_api.py b/sdks/python/client/argo_workflows/api/archived_workflow_service_api.py index 1e0fefce5f0a..89c15d9409b1 100644 --- a/sdks/python/client/argo_workflows/api/archived_workflow_service_api.py +++ b/sdks/python/client/argo_workflows/api/archived_workflow_service_api.py @@ -701,7 +701,6 @@ def __list_archived_workflows( def __retry_archived_workflow( self, - namespace, uid, body, **kwargs @@ -711,11 +710,10 @@ def __retry_archived_workflow( This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async_req=True - >>> thread = api.retry_archived_workflow(namespace, uid, body, async_req=True) + >>> thread = api.retry_archived_workflow(uid, body, async_req=True) >>> result = thread.get() Args: - namespace (str): uid (str): body (IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest): @@ -764,8 +762,6 @@ def __retry_archived_workflow( '_check_return_type', True ) kwargs['_host_index'] = kwargs.get('_host_index') - kwargs['namespace'] = \ - namespace kwargs['uid'] = \ uid kwargs['body'] = \ @@ -776,19 +772,17 @@ def __retry_archived_workflow( settings={ 'response_type': (IoArgoprojWorkflowV1alpha1Workflow,), 'auth': [], - 'endpoint_path': '/api/v1/archived-workflows/{namespace}/{uid}/retry', + 'endpoint_path': '/api/v1/archived-workflows/{uid}/retry', 'operation_id': 'retry_archived_workflow', 'http_method': 'PUT', 'servers': None, }, params_map={ 'all': [ - 'namespace', 'uid', 'body', ], 'required': [ - 'namespace', 'uid', 'body', ], @@ -805,19 +799,15 @@ def __retry_archived_workflow( 'allowed_values': { }, 'openapi_types': { - 'namespace': - (str,), 'uid': (str,), 'body': (IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest,), }, 'attribute_map': { - 'namespace': 'namespace', 'uid': 'uid', }, 'location_map': { - 'namespace': 'path', 'uid': 'path', 'body': 'body', }, diff --git a/sdks/python/client/docs/ArchivedWorkflowServiceApi.md b/sdks/python/client/docs/ArchivedWorkflowServiceApi.md index 7e426e754072..9fa88bda5c86 100644 --- a/sdks/python/client/docs/ArchivedWorkflowServiceApi.md +++ b/sdks/python/client/docs/ArchivedWorkflowServiceApi.md @@ -9,7 +9,7 @@ Method | HTTP request | Description [**list_archived_workflow_label_keys**](ArchivedWorkflowServiceApi.md#list_archived_workflow_label_keys) | **GET** /api/v1/archived-workflows-label-keys | [**list_archived_workflow_label_values**](ArchivedWorkflowServiceApi.md#list_archived_workflow_label_values) | **GET** /api/v1/archived-workflows-label-values | [**list_archived_workflows**](ArchivedWorkflowServiceApi.md#list_archived_workflows) | **GET** /api/v1/archived-workflows | -[**retry_archived_workflow**](ArchivedWorkflowServiceApi.md#retry_archived_workflow) | **PUT** /api/v1/archived-workflows/{namespace}/{uid}/retry | +[**retry_archived_workflow**](ArchivedWorkflowServiceApi.md#retry_archived_workflow) | **PUT** /api/v1/archived-workflows/{uid}/retry | # **delete_archived_workflow** @@ -364,7 +364,7 @@ No authorization required [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) # **retry_archived_workflow** -> IoArgoprojWorkflowV1alpha1Workflow retry_archived_workflow(namespace, uid, body) +> IoArgoprojWorkflowV1alpha1Workflow retry_archived_workflow(uid, body) @@ -389,7 +389,6 @@ configuration = argo_workflows.Configuration( with argo_workflows.ApiClient() as api_client: # Create an instance of the API class api_instance = archived_workflow_service_api.ArchivedWorkflowServiceApi(api_client) - namespace = "namespace_example" # str | uid = "uid_example" # str | body = IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest( name="name_example", @@ -401,7 +400,7 @@ with argo_workflows.ApiClient() as api_client: # example passing only required values which don't have defaults set try: - api_response = api_instance.retry_archived_workflow(namespace, uid, body) + api_response = api_instance.retry_archived_workflow(uid, body) pprint(api_response) except argo_workflows.ApiException as e: print("Exception when calling ArchivedWorkflowServiceApi->retry_archived_workflow: %s\n" % e) @@ -412,7 +411,6 @@ with argo_workflows.ApiClient() as api_client: Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **namespace** | **str**| | **uid** | **str**| | **body** | [**IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest**](IoArgoprojWorkflowV1alpha1RetryArchivedWorkflowRequest.md)| | From 0efff12f1f59f6769a5e1c379d5ec549cf4c7465 Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Thu, 3 Mar 2022 15:38:05 -0800 Subject: [PATCH 16/28] test: edited RetryArchivedWorkflow test Signed-off-by: Dillen Padhiar --- test/e2e/argo_server_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/argo_server_test.go b/test/e2e/argo_server_test.go index 3c296eecadb2..db6f277c57b3 100644 --- a/test/e2e/argo_server_test.go +++ b/test/e2e/argo_server_test.go @@ -1337,7 +1337,7 @@ spec: }) s.Run("Retry", func() { - s.e().PUT("/api/v1/archived-workflows/argo/{uid}/retry", uid). + s.e().PUT("/api/v1/archived-workflows/{uid}/retry", uid). Expect(). Status(200). JSON(). From 349aa9acf5039c0269e09256628c8c1241163fff Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Thu, 3 Mar 2022 17:10:57 -0800 Subject: [PATCH 17/28] test: moved retry test before delete Signed-off-by: Dillen Padhiar --- test/e2e/argo_server_test.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/e2e/argo_server_test.go b/test/e2e/argo_server_test.go index db6f277c57b3..6217d903e7ab 100644 --- a/test/e2e/argo_server_test.go +++ b/test/e2e/argo_server_test.go @@ -1302,6 +1302,15 @@ spec: NotNull() }) + s.Run("Retry", func() { + s.e().PUT("/api/v1/archived-workflows/{uid}/retry", uid). + Expect(). + Status(200). + JSON(). + Path("$.metadata.name"). + NotNull() + }) + s.Run("Delete", func() { s.e().DELETE("/api/v1/archived-workflows/{uid}", uid). Expect(). @@ -1336,15 +1345,6 @@ spec: Equal(1) }) - s.Run("Retry", func() { - s.e().PUT("/api/v1/archived-workflows/{uid}/retry", uid). - Expect(). - Status(200). - JSON(). - Path("$.metadata.name"). - NotNull() - }) - } func (s *ArgoServerSuite) TestWorkflowTemplateService() { From bc29411a31bee956a29c0c55e304324613d69a96 Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Fri, 4 Mar 2022 17:23:09 -0800 Subject: [PATCH 18/28] test: added failed workflow for testing RetryWorkflowArchive Signed-off-by: Dillen Padhiar --- .../archived_workflow_server.go | 2 +- test/e2e/argo_server_test.go | 26 ++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/server/workflowarchive/archived_workflow_server.go b/server/workflowarchive/archived_workflow_server.go index 7bd151a20d41..3cc4be87baa6 100644 --- a/server/workflowarchive/archived_workflow_server.go +++ b/server/workflowarchive/archived_workflow_server.go @@ -194,7 +194,7 @@ func (w *archivedWorkflowServer) RetryArchivedWorkflow(ctx context.Context, req wfClient := auth.GetWfClient(ctx) kubeClient := auth.GetKubeClient(ctx) - wf, err := w.wfArchive.GetWorkflow(req.Uid) + wf, err := w.GetArchivedWorkflow(ctx, &workflowarchivepkg.GetArchivedWorkflowRequest{Uid: req.Uid}) if err != nil { return nil, err } diff --git a/test/e2e/argo_server_test.go b/test/e2e/argo_server_test.go index 6217d903e7ab..99ee661f17f4 100644 --- a/test/e2e/argo_server_test.go +++ b/test/e2e/argo_server_test.go @@ -1193,6 +1193,28 @@ spec: ExpectWorkflow(func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { uid = metadata.UID }) + var failedUid types.UID + s.Given(). + Workflow(` +metadata: + generateName: archie- + labels: + foo: 1 +spec: + entrypoint: run-archie + templates: + - name: run-archie + container: + image: argoproj/argosay:v2 + command: [sh, -c] + args: ["echo intentional failure; exit 1"]`). + When(). + SubmitWorkflow(). + WaitForWorkflow(fixtures.ToBeArchived). + Then(). + ExpectWorkflow(func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + failedUid = metadata.UID + }) s.Given(). Workflow(` metadata: @@ -1303,7 +1325,9 @@ spec: }) s.Run("Retry", func() { - s.e().PUT("/api/v1/archived-workflows/{uid}/retry", uid). + s.Need(fixtures.BaseLayerArtifacts) + s.e().PUT("/api/v1/archived-workflows/{uid}/retry", failedUid). + WithBytes([]byte(`{"namespace": "argo", "restartSuccessful": false, "nodeFieldSelector": ""}`)). Expect(). Status(200). JSON(). From 0611e7411e32f82c592331f322f0886b46bbbab8 Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Mon, 7 Mar 2022 15:56:17 -0800 Subject: [PATCH 19/28] test: delete workflow before retrying from archive Signed-off-by: Dillen Padhiar --- .../http1/archived-workflows-service-client.go | 2 +- test/e2e/argo_server_test.go | 18 +++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/pkg/apiclient/http1/archived-workflows-service-client.go b/pkg/apiclient/http1/archived-workflows-service-client.go index 7229c4beb56e..bc61a798cb30 100644 --- a/pkg/apiclient/http1/archived-workflows-service-client.go +++ b/pkg/apiclient/http1/archived-workflows-service-client.go @@ -49,5 +49,5 @@ func (h ArchivedWorkflowsServiceClient) ListArchivedWorkflowLabelValues(_ contex func (h ArchivedWorkflowsServiceClient) RetryArchivedWorkflow(_ context.Context, in *workflowarchivepkg.RetryArchivedWorkflowRequest, _ ...grpc.CallOption) (*wfv1.Workflow, error) { out := &wfv1.Workflow{} - return out, h.Get(in, out, "/api/v1/archived-workflows/{uid}/retry") + return out, h.Put(in, out, "/api/v1/archived-workflows/{uid}/retry") } diff --git a/test/e2e/argo_server_test.go b/test/e2e/argo_server_test.go index 99ee661f17f4..b9c6b3153a2a 100644 --- a/test/e2e/argo_server_test.go +++ b/test/e2e/argo_server_test.go @@ -1194,16 +1194,17 @@ spec: uid = metadata.UID }) var failedUid types.UID + var name string s.Given(). Workflow(` metadata: - generateName: archie- + generateName: jughead- labels: foo: 1 spec: - entrypoint: run-archie + entrypoint: run-jughead templates: - - name: run-archie + - name: run-jughead container: image: argoproj/argosay:v2 command: [sh, -c] @@ -1213,6 +1214,7 @@ spec: WaitForWorkflow(fixtures.ToBeArchived). Then(). ExpectWorkflow(func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + name = metadata.Name failedUid = metadata.UID }) s.Given(). @@ -1324,6 +1326,16 @@ spec: NotNull() }) + // we have to delete wf from namespace before retrying + s.Run("Delete", func() { + s.e().DELETE("/api/v1/workflows/argo/" + name). + Expect(). + Status(200) + s.e().DELETE("/api/v1/workflows/argo/not-found"). + Expect(). + Status(404) + }) + s.Run("Retry", func() { s.Need(fixtures.BaseLayerArtifacts) s.e().PUT("/api/v1/archived-workflows/{uid}/retry", failedUid). From 4cf79b067d2687ae68eafc2ce47ee15d2a45deba Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Tue, 8 Mar 2022 10:54:17 -0800 Subject: [PATCH 20/28] fix: resourceVersion must be set to nil to retry archivedWf Signed-off-by: Dillen Padhiar --- server/workflowarchive/archived_workflow_server.go | 2 ++ test/e2e/argo_server_test.go | 14 +++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/server/workflowarchive/archived_workflow_server.go b/server/workflowarchive/archived_workflow_server.go index 3cc4be87baa6..b0a0f87ca6a8 100644 --- a/server/workflowarchive/archived_workflow_server.go +++ b/server/workflowarchive/archived_workflow_server.go @@ -199,6 +199,8 @@ func (w *archivedWorkflowServer) RetryArchivedWorkflow(ctx context.Context, req return nil, err } + wf.ObjectMeta.ResourceVersion = "" + wf, err = util.RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.Namespace), wfClient.ArgoprojV1alpha1().Workflows(req.Namespace), wf, req.RestartSuccessful, req.NodeFieldSelector) if err != nil { return nil, err diff --git a/test/e2e/argo_server_test.go b/test/e2e/argo_server_test.go index b9c6b3153a2a..8fa45164b133 100644 --- a/test/e2e/argo_server_test.go +++ b/test/e2e/argo_server_test.go @@ -1200,7 +1200,7 @@ spec: metadata: generateName: jughead- labels: - foo: 1 + foo: 3 spec: entrypoint: run-jughead templates: @@ -1242,11 +1242,11 @@ spec: {"ListEquals", "foo=1", 1}, {"ListDoubleEquals", "foo==1", 1}, {"ListIn", "foo in (1)", 1}, - {"ListNotEquals", "foo!=1", 1}, - {"ListNotIn", "foo notin (1)", 1}, - {"ListExists", "foo", 2}, - {"ListGreaterThan0", "foo>0", 2}, - {"ListGreaterThan1", "foo>1", 1}, + {"ListNotEquals", "foo!=1", 2}, + {"ListNotIn", "foo notin (1)", 2}, + {"ListExists", "foo", 3}, + {"ListGreaterThan0", "foo>0", 3}, + {"ListGreaterThan1", "foo>1", 2}, {"ListLessThan1", "foo<1", 0}, {"ListLessThan2", "foo<2", 1}, } { @@ -1339,7 +1339,7 @@ spec: s.Run("Retry", func() { s.Need(fixtures.BaseLayerArtifacts) s.e().PUT("/api/v1/archived-workflows/{uid}/retry", failedUid). - WithBytes([]byte(`{"namespace": "argo", "restartSuccessful": false, "nodeFieldSelector": ""}`)). + WithBytes([]byte(`{"namespace": "argo"}`)). Expect(). Status(200). JSON(). From 19b48ef810da21ab8b1dae7ea02b4832f21c0ba7 Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Tue, 8 Mar 2022 11:59:52 -0800 Subject: [PATCH 21/28] refactor: set resourceVersion to nil in util/RetryArchivedWorkflow Signed-off-by: Dillen Padhiar --- server/workflowarchive/archived_workflow_server.go | 4 +--- test/e2e/argo_server_test.go | 5 +---- workflow/util/util.go | 11 +++++++++++ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/server/workflowarchive/archived_workflow_server.go b/server/workflowarchive/archived_workflow_server.go index b0a0f87ca6a8..a90061e04f5e 100644 --- a/server/workflowarchive/archived_workflow_server.go +++ b/server/workflowarchive/archived_workflow_server.go @@ -199,9 +199,7 @@ func (w *archivedWorkflowServer) RetryArchivedWorkflow(ctx context.Context, req return nil, err } - wf.ObjectMeta.ResourceVersion = "" - - wf, err = util.RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.Namespace), wfClient.ArgoprojV1alpha1().Workflows(req.Namespace), wf, req.RestartSuccessful, req.NodeFieldSelector) + wf, err = util.RetryArchivedWorkflow(ctx, kubeClient.CoreV1().Pods(wf.Namespace), wfClient.ArgoprojV1alpha1().Workflows(req.Namespace), wf, req.RestartSuccessful, req.NodeFieldSelector) if err != nil { return nil, err } diff --git a/test/e2e/argo_server_test.go b/test/e2e/argo_server_test.go index 8fa45164b133..793330b6896e 100644 --- a/test/e2e/argo_server_test.go +++ b/test/e2e/argo_server_test.go @@ -1327,13 +1327,10 @@ spec: }) // we have to delete wf from namespace before retrying - s.Run("Delete", func() { + s.Run("DeleteForRetry", func() { s.e().DELETE("/api/v1/workflows/argo/" + name). Expect(). Status(200) - s.e().DELETE("/api/v1/workflows/argo/not-found"). - Expect(). - Status(404) }) s.Run("Retry", func() { diff --git a/workflow/util/util.go b/workflow/util/util.go index 487f1fb1aa6c..e23d1afa7cf9 100644 --- a/workflow/util/util.go +++ b/workflow/util/util.go @@ -744,6 +744,17 @@ func RetryWorkflow(ctx context.Context, podIf v1.PodInterface, wfClient v1alpha1 return updatedWf, err } +// RetryWorkflow creates a workflow from the workflow archive +func RetryArchivedWorkflow(ctx context.Context, podIf v1.PodInterface, wfClient v1alpha1.WorkflowInterface, wf *wfv1.Workflow, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { + wf.ObjectMeta.ResourceVersion = "" + updatedWf, err := prepareWorkflowForRetry(ctx, wf, podIf, restartSuccessful, nodeFieldSelector) + if err != nil { + return nil, err + } + + return updatedWf, err +} + func prepareWorkflowForRetry(ctx context.Context, wf *wfv1.Workflow, podIf v1.PodInterface, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { switch wf.Status.Phase { From 4a4493e652579712a118478f7d736c8d157d8509 Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Thu, 10 Mar 2022 11:58:13 -0800 Subject: [PATCH 22/28] test: added RetryArchivedWorkflow test Signed-off-by: Dillen Padhiar --- test/e2e/argo_server_test.go | 1 - workflow/util/util_test.go | 57 ++++++++++++++++++++++++++++++++++-- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/test/e2e/argo_server_test.go b/test/e2e/argo_server_test.go index c6349c8c3c19..4a8ecda6dcf1 100644 --- a/test/e2e/argo_server_test.go +++ b/test/e2e/argo_server_test.go @@ -1326,7 +1326,6 @@ spec: NotNull() }) - // we have to delete wf from namespace before retrying s.Run("DeleteForRetry", func() { s.e().DELETE("/api/v1/workflows/argo/" + name). Expect(). diff --git a/workflow/util/util_test.go b/workflow/util/util_test.go index a788b1bbe9fd..955603297031 100644 --- a/workflow/util/util_test.go +++ b/workflow/util/util_test.go @@ -811,7 +811,7 @@ func TestDeepDeleteNodes(t *testing.T) { ctx := context.Background() wf, err := wfIf.Create(ctx, origWf, metav1.CreateOptions{}) if assert.NoError(t, err) { - newWf, err := RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wfIf, wf, false, "") + newWf, err := RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wf, false, "") assert.NoError(t, err) newWfBytes, err := yaml.Marshal(newWf) assert.NoError(t, err) @@ -845,7 +845,7 @@ func TestRetryWorkflow(t *testing.T) { } _, err := wfClient.Create(ctx, wf, metav1.CreateOptions{}) assert.NoError(t, err) - wf, err = RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.Namespace), wfClient, wf, false, "") + wf, err = RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.Namespace), wf, false, "") if assert.NoError(t, err) { assert.Equal(t, wfv1.WorkflowRunning, wf.Status.Phase) assert.Equal(t, metav1.Time{}, wf.Status.FinishedAt) @@ -882,7 +882,7 @@ func TestRetryWorkflow(t *testing.T) { } _, err := wfClient.Create(ctx, wf, metav1.CreateOptions{}) assert.NoError(t, err) - wf, err = RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wfClient, wf, false, "") + wf, err = RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wf, false, "") if assert.NoError(t, err) { if assert.Len(t, wf.Status.Nodes, 1) { assert.Equal(t, wfv1.NodeRunning, wf.Status.Nodes[""].Phase) @@ -892,6 +892,57 @@ func TestRetryWorkflow(t *testing.T) { }) } +func TestRetryArchivedWorkflow(t *testing.T) { + ctx := context.Background() + kubeClient := kubefake.NewSimpleClientset() + wfClient := argofake.NewSimpleClientset().ArgoprojV1alpha1().Workflows("my-ns") + createdTime := metav1.Time{Time: time.Now().UTC()} + finishedTime := metav1.Time{Time: createdTime.Add(time.Second * 2)} + t.Run("Steps", func(t *testing.T) { + wf := &wfv1.Workflow{ + ObjectMeta: metav1.ObjectMeta{ + Name: "my-steps", + Labels: map[string]string{ + common.LabelKeyCompleted: "true", + common.LabelKeyWorkflowArchivingStatus: "Pending", + }, + }, + Status: wfv1.WorkflowStatus{ + Phase: wfv1.WorkflowFailed, + StartedAt: createdTime, + FinishedAt: finishedTime, + Nodes: map[string]wfv1.NodeStatus{ + "failed-node": {Name: "failed-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeFailed, Message: "failed"}, + "succeeded-node": {Name: "succeeded-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeSucceeded, Message: "succeeded"}}, + }, + } + _, err := wfClient.Create(ctx, wf, metav1.CreateOptions{}) + assert.NoError(t, err) + wf, err = RetryArchivedWorkflow(ctx, kubeClient.CoreV1().Pods(wf.Namespace), wf, false, "") + if assert.NoError(t, err) { + assert.Equal(t, wfv1.WorkflowRunning, wf.Status.Phase) + assert.Equal(t, metav1.Time{}, wf.Status.FinishedAt) + assert.True(t, wf.Status.StartedAt.After(createdTime.Time)) + assert.NotContains(t, wf.Labels, common.LabelKeyCompleted) + assert.NotContains(t, wf.Labels, common.LabelKeyWorkflowArchivingStatus) + for _, node := range wf.Status.Nodes { + switch node.Phase { + case wfv1.NodeSucceeded: + assert.Equal(t, "succeeded", node.Message) + assert.Equal(t, wfv1.NodeSucceeded, node.Phase) + assert.Equal(t, createdTime, node.StartedAt) + assert.Equal(t, finishedTime, node.FinishedAt) + case wfv1.NodeFailed: + assert.Equal(t, "", node.Message) + assert.Equal(t, wfv1.NodeRunning, node.Phase) + assert.Equal(t, metav1.Time{}, node.FinishedAt) + assert.True(t, node.StartedAt.After(createdTime.Time)) + } + } + } + }) +} + func TestFromUnstructuredObj(t *testing.T) { un := &unstructured.Unstructured{} wfv1.MustUnmarshal([]byte(`apiVersion: argoproj.io/v1alpha1 From 51c4b5d23afdb9c6d803760b5eda98b1fd245114 Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Thu, 10 Mar 2022 11:58:55 -0800 Subject: [PATCH 23/28] chore: remove wfClient from RetryWorkflow/RetryArchivedWorkflow methods Signed-off-by: Dillen Padhiar --- docs/fields.md | 12 ++++++++++++ server/workflow/workflow_server.go | 2 +- server/workflowarchive/archived_workflow_server.go | 2 +- workflow/util/util.go | 4 ++-- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/docs/fields.md b/docs/fields.md index 80a111d33ceb..f6bd337b377b 100644 --- a/docs/fields.md +++ b/docs/fields.md @@ -396,6 +396,8 @@ WorkflowTemplate is the definition of a workflow template resource - [`dag-inline-workflowtemplate.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/dag-inline-workflowtemplate.yaml) +- [`issue-template.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/issue-template.yaml) + - [`event-consumer-workflowtemplate.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/workflow-event-binding/event-consumer-workflowtemplate.yaml) - [`templates.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/workflow-template/templates.yaml) @@ -599,6 +601,8 @@ WorkflowSpec is the specification of a Workflow. - [`input-artifact-s3.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/input-artifact-s3.yaml) +- [`issue-template.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/issue-template.yaml) + - [`k8s-json-patch-workflow.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/k8s-json-patch-workflow.yaml) - [`k8s-owner-reference.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/k8s-owner-reference.yaml) @@ -1018,6 +1022,8 @@ CronWorkflowSpec is the specification of a CronWorkflow - [`input-artifact-s3.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/input-artifact-s3.yaml) +- [`issue-template.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/issue-template.yaml) + - [`k8s-json-patch-workflow.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/k8s-json-patch-workflow.yaml) - [`k8s-owner-reference.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/k8s-owner-reference.yaml) @@ -4414,6 +4420,8 @@ ObjectMeta is metadata that all persisted resources must have, which includes al - [`input-artifact-s3.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/input-artifact-s3.yaml) +- [`issue-template.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/issue-template.yaml) + - [`k8s-json-patch-workflow.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/k8s-json-patch-workflow.yaml) - [`k8s-owner-reference.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/k8s-owner-reference.yaml) @@ -5004,6 +5012,8 @@ A single application container that you want to run within a pod. - [`input-artifact-s3.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/input-artifact-s3.yaml) +- [`issue-template.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/issue-template.yaml) + - [`k8s-owner-reference.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/k8s-owner-reference.yaml) - [`k8s-wait-wf.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/k8s-wait-wf.yaml) @@ -5703,6 +5713,8 @@ PersistentVolumeClaimSpec describes the common attributes of storage devices and - [`input-artifact-s3.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/input-artifact-s3.yaml) +- [`issue-template.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/issue-template.yaml) + - [`k8s-json-patch-workflow.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/k8s-json-patch-workflow.yaml) - [`k8s-owner-reference.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/k8s-owner-reference.yaml) diff --git a/server/workflow/workflow_server.go b/server/workflow/workflow_server.go index eb10b1108915..732b86cc68ff 100644 --- a/server/workflow/workflow_server.go +++ b/server/workflow/workflow_server.go @@ -324,7 +324,7 @@ func (s *workflowServer) RetryWorkflow(ctx context.Context, req *workflowpkg.Wor return nil, err } - wf, err = util.RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.Namespace), wfClient.ArgoprojV1alpha1().Workflows(req.Namespace), wf, req.RestartSuccessful, req.NodeFieldSelector) + wf, err = util.RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.Namespace), wf, req.RestartSuccessful, req.NodeFieldSelector) if err != nil { return nil, err } diff --git a/server/workflowarchive/archived_workflow_server.go b/server/workflowarchive/archived_workflow_server.go index 4b9dac0a32cf..be351975fa96 100644 --- a/server/workflowarchive/archived_workflow_server.go +++ b/server/workflowarchive/archived_workflow_server.go @@ -219,7 +219,7 @@ func (w *archivedWorkflowServer) RetryArchivedWorkflow(ctx context.Context, req return nil, err } - wf, err = util.RetryArchivedWorkflow(ctx, kubeClient.CoreV1().Pods(wf.Namespace), wfClient.ArgoprojV1alpha1().Workflows(req.Namespace), wf, req.RestartSuccessful, req.NodeFieldSelector) + wf, err = util.RetryArchivedWorkflow(ctx, kubeClient.CoreV1().Pods(wf.Namespace), wf, req.RestartSuccessful, req.NodeFieldSelector) if err != nil { return nil, err } diff --git a/workflow/util/util.go b/workflow/util/util.go index e23d1afa7cf9..fc94eca413c2 100644 --- a/workflow/util/util.go +++ b/workflow/util/util.go @@ -735,7 +735,7 @@ func convertNodeID(newWf *wfv1.Workflow, regex *regexp.Regexp, oldNodeID string, } // RetryWorkflow updates a workflow, deleting all failed steps as well as the onExit node (and children) -func RetryWorkflow(ctx context.Context, podIf v1.PodInterface, wfClient v1alpha1.WorkflowInterface, wf *wfv1.Workflow, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { +func RetryWorkflow(ctx context.Context, podIf v1.PodInterface, wf *wfv1.Workflow, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { updatedWf, err := prepareWorkflowForRetry(ctx, wf, podIf, restartSuccessful, nodeFieldSelector) if err != nil { return nil, err @@ -745,7 +745,7 @@ func RetryWorkflow(ctx context.Context, podIf v1.PodInterface, wfClient v1alpha1 } // RetryWorkflow creates a workflow from the workflow archive -func RetryArchivedWorkflow(ctx context.Context, podIf v1.PodInterface, wfClient v1alpha1.WorkflowInterface, wf *wfv1.Workflow, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { +func RetryArchivedWorkflow(ctx context.Context, podIf v1.PodInterface, wf *wfv1.Workflow, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { wf.ObjectMeta.ResourceVersion = "" updatedWf, err := prepareWorkflowForRetry(ctx, wf, podIf, restartSuccessful, nodeFieldSelector) if err != nil { From 7fba704e6ad3160bc0daf6ca0fc11faa8ed4eed0 Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Thu, 10 Mar 2022 13:40:18 -0800 Subject: [PATCH 24/28] chore: rerun codegen -B Signed-off-by: Dillen Padhiar --- docs/fields.md | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/docs/fields.md b/docs/fields.md index f6bd337b377b..80a111d33ceb 100644 --- a/docs/fields.md +++ b/docs/fields.md @@ -396,8 +396,6 @@ WorkflowTemplate is the definition of a workflow template resource - [`dag-inline-workflowtemplate.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/dag-inline-workflowtemplate.yaml) -- [`issue-template.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/issue-template.yaml) - - [`event-consumer-workflowtemplate.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/workflow-event-binding/event-consumer-workflowtemplate.yaml) - [`templates.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/workflow-template/templates.yaml) @@ -601,8 +599,6 @@ WorkflowSpec is the specification of a Workflow. - [`input-artifact-s3.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/input-artifact-s3.yaml) -- [`issue-template.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/issue-template.yaml) - - [`k8s-json-patch-workflow.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/k8s-json-patch-workflow.yaml) - [`k8s-owner-reference.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/k8s-owner-reference.yaml) @@ -1022,8 +1018,6 @@ CronWorkflowSpec is the specification of a CronWorkflow - [`input-artifact-s3.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/input-artifact-s3.yaml) -- [`issue-template.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/issue-template.yaml) - - [`k8s-json-patch-workflow.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/k8s-json-patch-workflow.yaml) - [`k8s-owner-reference.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/k8s-owner-reference.yaml) @@ -4420,8 +4414,6 @@ ObjectMeta is metadata that all persisted resources must have, which includes al - [`input-artifact-s3.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/input-artifact-s3.yaml) -- [`issue-template.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/issue-template.yaml) - - [`k8s-json-patch-workflow.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/k8s-json-patch-workflow.yaml) - [`k8s-owner-reference.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/k8s-owner-reference.yaml) @@ -5012,8 +5004,6 @@ A single application container that you want to run within a pod. - [`input-artifact-s3.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/input-artifact-s3.yaml) -- [`issue-template.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/issue-template.yaml) - - [`k8s-owner-reference.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/k8s-owner-reference.yaml) - [`k8s-wait-wf.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/k8s-wait-wf.yaml) @@ -5713,8 +5703,6 @@ PersistentVolumeClaimSpec describes the common attributes of storage devices and - [`input-artifact-s3.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/input-artifact-s3.yaml) -- [`issue-template.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/issue-template.yaml) - - [`k8s-json-patch-workflow.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/k8s-json-patch-workflow.yaml) - [`k8s-owner-reference.yaml`](https://github.com/argoproj/argo-workflows/blob/master/examples/k8s-owner-reference.yaml) From 8add77ef2f3ad22129c943caed5dbdcbced67c9a Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Wed, 16 Mar 2022 15:34:00 -0700 Subject: [PATCH 25/28] refactor: move pod deletion to server side and rename prepareWorkflowForRetry to FormulateRetryWorkflow Signed-off-by: Dillen Padhiar --- server/workflow/workflow_server.go | 10 +- .../archived_workflow_server.go | 23 +++- test/e2e/argo_server_test.go | 9 -- workflow/util/util.go | 38 ++---- workflow/util/util_test.go | 111 +++++++++--------- 5 files changed, 95 insertions(+), 96 deletions(-) diff --git a/server/workflow/workflow_server.go b/server/workflow/workflow_server.go index 732b86cc68ff..5299db439d00 100644 --- a/server/workflow/workflow_server.go +++ b/server/workflow/workflow_server.go @@ -324,11 +324,19 @@ func (s *workflowServer) RetryWorkflow(ctx context.Context, req *workflowpkg.Wor return nil, err } - wf, err = util.RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.Namespace), wf, req.RestartSuccessful, req.NodeFieldSelector) + wf, podsToDelete, err := util.RetryWorkflow(ctx, wf, req.RestartSuccessful, req.NodeFieldSelector) if err != nil { return nil, err } + for _, podName := range podsToDelete { + log.Infof("Deleting pod: %s", podName) + err := kubeClient.CoreV1().Pods(wf.Namespace).Delete(ctx, podName, metav1.DeleteOptions{}) + if err != nil && !apierr.IsNotFound(err) { + return nil, errors.InternalWrapError(err) + } + } + err = s.hydrator.Dehydrate(wf) if err != nil { return nil, err diff --git a/server/workflowarchive/archived_workflow_server.go b/server/workflowarchive/archived_workflow_server.go index be351975fa96..7276b459bee2 100644 --- a/server/workflowarchive/archived_workflow_server.go +++ b/server/workflowarchive/archived_workflow_server.go @@ -8,12 +8,15 @@ import ( "strings" "time" + log "github.com/sirupsen/logrus" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + apierr "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/selection" + "github.com/argoproj/argo-workflows/v3/errors" "github.com/argoproj/argo-workflows/v3/persist/sqldb" workflowarchivepkg "github.com/argoproj/argo-workflows/v3/pkg/apiclient/workflowarchive" "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow" @@ -219,14 +222,26 @@ func (w *archivedWorkflowServer) RetryArchivedWorkflow(ctx context.Context, req return nil, err } - wf, err = util.RetryArchivedWorkflow(ctx, kubeClient.CoreV1().Pods(wf.Namespace), wf, req.RestartSuccessful, req.NodeFieldSelector) + wf, podsToDelete, err := util.RetryWorkflow(ctx, wf, req.RestartSuccessful, req.NodeFieldSelector) if err != nil { return nil, err } - wf, err = wfClient.ArgoprojV1alpha1().Workflows(req.Namespace).Create(ctx, wf, metav1.CreateOptions{}) - if err != nil { - return nil, err + for _, podName := range podsToDelete { + log.Infof("Deleting pod: %s", podName) + err := kubeClient.CoreV1().Pods(wf.Namespace).Delete(ctx, podName, metav1.DeleteOptions{}) + if err != nil && !apierr.IsNotFound(err) { + return nil, errors.InternalWrapError(err) + } + } + + wf, err = wfClient.ArgoprojV1alpha1().Workflows(req.Namespace).Update(ctx, wf, metav1.UpdateOptions{}) + if apierr.IsAlreadyExists(err) { + wf.ObjectMeta.ResourceVersion = "" + wf, err = wfClient.ArgoprojV1alpha1().Workflows(req.Namespace).Create(ctx, wf, metav1.CreateOptions{}) + if err != nil { + return nil, err + } } return wf, nil diff --git a/test/e2e/argo_server_test.go b/test/e2e/argo_server_test.go index 4a8ecda6dcf1..45b39bf0b650 100644 --- a/test/e2e/argo_server_test.go +++ b/test/e2e/argo_server_test.go @@ -1194,7 +1194,6 @@ spec: uid = metadata.UID }) var failedUid types.UID - var name string s.Given(). Workflow(` metadata: @@ -1214,7 +1213,6 @@ spec: WaitForWorkflow(fixtures.ToBeArchived). Then(). ExpectWorkflow(func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { - name = metadata.Name failedUid = metadata.UID }) s.Given(). @@ -1326,12 +1324,6 @@ spec: NotNull() }) - s.Run("DeleteForRetry", func() { - s.e().DELETE("/api/v1/workflows/argo/" + name). - Expect(). - Status(200) - }) - s.Run("Retry", func() { s.Need(fixtures.BaseLayerArtifacts) s.e().PUT("/api/v1/archived-workflows/{uid}/retry", failedUid). @@ -1339,7 +1331,6 @@ spec: Expect(). Status(200). JSON(). - Path("$.metadata.name"). NotNull() }) diff --git a/workflow/util/util.go b/workflow/util/util.go index fc94eca413c2..4192fef668e5 100644 --- a/workflow/util/util.go +++ b/workflow/util/util.go @@ -31,7 +31,6 @@ import ( "k8s.io/apimachinery/pkg/util/strategicpatch" "k8s.io/client-go/dynamic" "k8s.io/client-go/informers/internalinterfaces" - v1 "k8s.io/client-go/kubernetes/typed/core/v1" "k8s.io/client-go/tools/cache" "k8s.io/utils/pointer" "sigs.k8s.io/yaml" @@ -735,32 +734,21 @@ func convertNodeID(newWf *wfv1.Workflow, regex *regexp.Regexp, oldNodeID string, } // RetryWorkflow updates a workflow, deleting all failed steps as well as the onExit node (and children) -func RetryWorkflow(ctx context.Context, podIf v1.PodInterface, wf *wfv1.Workflow, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { - updatedWf, err := prepareWorkflowForRetry(ctx, wf, podIf, restartSuccessful, nodeFieldSelector) +func RetryWorkflow(ctx context.Context, wf *wfv1.Workflow, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, []string, error) { + updatedWf, podsToDelete, err := FormulateRetryWorkflow(ctx, wf, restartSuccessful, nodeFieldSelector) if err != nil { - return nil, err - } - - return updatedWf, err -} - -// RetryWorkflow creates a workflow from the workflow archive -func RetryArchivedWorkflow(ctx context.Context, podIf v1.PodInterface, wf *wfv1.Workflow, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { - wf.ObjectMeta.ResourceVersion = "" - updatedWf, err := prepareWorkflowForRetry(ctx, wf, podIf, restartSuccessful, nodeFieldSelector) - if err != nil { - return nil, err + return nil, nil, err } - return updatedWf, err + return updatedWf, podsToDelete, err } -func prepareWorkflowForRetry(ctx context.Context, wf *wfv1.Workflow, podIf v1.PodInterface, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, error) { +func FormulateRetryWorkflow(ctx context.Context, wf *wfv1.Workflow, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, []string, error) { switch wf.Status.Phase { case wfv1.WorkflowFailed, wfv1.WorkflowError: default: - return nil, errors.Errorf(errors.CodeBadRequest, "workflow must be Failed/Error to retry") + return nil, nil, errors.Errorf(errors.CodeBadRequest, "workflow must be Failed/Error to retry") } newWF := wf.DeepCopy() @@ -785,11 +773,12 @@ func prepareWorkflowForRetry(ctx context.Context, wf *wfv1.Workflow, podIf v1.Po // Get all children of nodes that match filter nodeIDsToReset, err := getNodeIDsToReset(restartSuccessful, nodeFieldSelector, wf.Status.Nodes) if err != nil { - return nil, err + return nil, nil, err } // Iterate the previous nodes. If it was successful Pod carry it forward deletedNodes := make(map[string]bool) + var podsToDelete []string for _, node := range wf.Status.Nodes { doForceResetNode := false if _, present := nodeIDsToReset[node.ID]; present { @@ -817,17 +806,14 @@ func prepareWorkflowForRetry(ctx context.Context, wf *wfv1.Workflow, podIf v1.Po // do not add this status to the node. pretend as if this node never existed. default: // Do not allow retry of workflows with pods in Running/Pending phase - return nil, errors.InternalErrorf("Workflow cannot be retried with node %s in %s phase", node.Name, node.Phase) + return nil, nil, errors.InternalErrorf("Workflow cannot be retried with node %s in %s phase", node.Name, node.Phase) } + if node.Type == wfv1.NodeTypePod { templateName := getTemplateFromNode(node) version := GetWorkflowPodNameVersion(wf) podName := PodName(wf.Name, node.Name, templateName, node.ID, version) - log.Infof("Deleting pod: %s", podName) - err := podIf.Delete(ctx, podName, metav1.DeleteOptions{}) - if err != nil && !apierr.IsNotFound(err) { - return nil, errors.InternalWrapError(err) - } + podsToDelete = append(podsToDelete, podName) } else if node.Name == wf.ObjectMeta.Name { newNode := node.DeepCopy() newNode.Phase = wfv1.NodeRunning @@ -866,7 +852,7 @@ func prepareWorkflowForRetry(ctx context.Context, wf *wfv1.Workflow, podIf v1.Po newWF.Status.StoredTemplates[id] = tmpl } - return newWF, nil + return newWF, podsToDelete, nil } func getTemplateFromNode(node wfv1.NodeStatus) string { diff --git a/workflow/util/util_test.go b/workflow/util/util_test.go index 955603297031..ab7ea8c19042 100644 --- a/workflow/util/util_test.go +++ b/workflow/util/util_test.go @@ -13,7 +13,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/fields" - kubefake "k8s.io/client-go/kubernetes/fake" "sigs.k8s.io/yaml" "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow" @@ -805,13 +804,13 @@ status: func TestDeepDeleteNodes(t *testing.T) { wfIf := argofake.NewSimpleClientset().ArgoprojV1alpha1().Workflows("") - kubeClient := &kubefake.Clientset{} + // kubeClient := &kubefake.Clientset{} origWf := wfv1.MustUnmarshalWorkflow(deepDeleteOfNodes) ctx := context.Background() wf, err := wfIf.Create(ctx, origWf, metav1.CreateOptions{}) if assert.NoError(t, err) { - newWf, err := RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wf, false, "") + newWf, _, err := RetryWorkflow(ctx, wf, false, "") assert.NoError(t, err) newWfBytes, err := yaml.Marshal(newWf) assert.NoError(t, err) @@ -821,7 +820,7 @@ func TestDeepDeleteNodes(t *testing.T) { func TestRetryWorkflow(t *testing.T) { ctx := context.Background() - kubeClient := kubefake.NewSimpleClientset() + // kubeClient := kubefake.NewSimpleClientset() wfClient := argofake.NewSimpleClientset().ArgoprojV1alpha1().Workflows("my-ns") createdTime := metav1.Time{Time: time.Now().UTC()} finishedTime := metav1.Time{Time: createdTime.Add(time.Second * 2)} @@ -845,7 +844,7 @@ func TestRetryWorkflow(t *testing.T) { } _, err := wfClient.Create(ctx, wf, metav1.CreateOptions{}) assert.NoError(t, err) - wf, err = RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.Namespace), wf, false, "") + wf, _, err = RetryWorkflow(ctx, wf, false, "") if assert.NoError(t, err) { assert.Equal(t, wfv1.WorkflowRunning, wf.Status.Phase) assert.Equal(t, metav1.Time{}, wf.Status.FinishedAt) @@ -882,7 +881,7 @@ func TestRetryWorkflow(t *testing.T) { } _, err := wfClient.Create(ctx, wf, metav1.CreateOptions{}) assert.NoError(t, err) - wf, err = RetryWorkflow(ctx, kubeClient.CoreV1().Pods(wf.ObjectMeta.Namespace), wf, false, "") + wf, _, err = RetryWorkflow(ctx, wf, false, "") if assert.NoError(t, err) { if assert.Len(t, wf.Status.Nodes, 1) { assert.Equal(t, wfv1.NodeRunning, wf.Status.Nodes[""].Phase) @@ -892,56 +891,56 @@ func TestRetryWorkflow(t *testing.T) { }) } -func TestRetryArchivedWorkflow(t *testing.T) { - ctx := context.Background() - kubeClient := kubefake.NewSimpleClientset() - wfClient := argofake.NewSimpleClientset().ArgoprojV1alpha1().Workflows("my-ns") - createdTime := metav1.Time{Time: time.Now().UTC()} - finishedTime := metav1.Time{Time: createdTime.Add(time.Second * 2)} - t.Run("Steps", func(t *testing.T) { - wf := &wfv1.Workflow{ - ObjectMeta: metav1.ObjectMeta{ - Name: "my-steps", - Labels: map[string]string{ - common.LabelKeyCompleted: "true", - common.LabelKeyWorkflowArchivingStatus: "Pending", - }, - }, - Status: wfv1.WorkflowStatus{ - Phase: wfv1.WorkflowFailed, - StartedAt: createdTime, - FinishedAt: finishedTime, - Nodes: map[string]wfv1.NodeStatus{ - "failed-node": {Name: "failed-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeFailed, Message: "failed"}, - "succeeded-node": {Name: "succeeded-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeSucceeded, Message: "succeeded"}}, - }, - } - _, err := wfClient.Create(ctx, wf, metav1.CreateOptions{}) - assert.NoError(t, err) - wf, err = RetryArchivedWorkflow(ctx, kubeClient.CoreV1().Pods(wf.Namespace), wf, false, "") - if assert.NoError(t, err) { - assert.Equal(t, wfv1.WorkflowRunning, wf.Status.Phase) - assert.Equal(t, metav1.Time{}, wf.Status.FinishedAt) - assert.True(t, wf.Status.StartedAt.After(createdTime.Time)) - assert.NotContains(t, wf.Labels, common.LabelKeyCompleted) - assert.NotContains(t, wf.Labels, common.LabelKeyWorkflowArchivingStatus) - for _, node := range wf.Status.Nodes { - switch node.Phase { - case wfv1.NodeSucceeded: - assert.Equal(t, "succeeded", node.Message) - assert.Equal(t, wfv1.NodeSucceeded, node.Phase) - assert.Equal(t, createdTime, node.StartedAt) - assert.Equal(t, finishedTime, node.FinishedAt) - case wfv1.NodeFailed: - assert.Equal(t, "", node.Message) - assert.Equal(t, wfv1.NodeRunning, node.Phase) - assert.Equal(t, metav1.Time{}, node.FinishedAt) - assert.True(t, node.StartedAt.After(createdTime.Time)) - } - } - } - }) -} +// func TestRetryArchivedWorkflow(t *testing.T) { +// ctx := context.Background() +// kubeClient := kubefake.NewSimpleClientset() +// wfClient := argofake.NewSimpleClientset().ArgoprojV1alpha1().Workflows("my-ns") +// createdTime := metav1.Time{Time: time.Now().UTC()} +// finishedTime := metav1.Time{Time: createdTime.Add(time.Second * 2)} +// t.Run("Steps", func(t *testing.T) { +// wf := &wfv1.Workflow{ +// ObjectMeta: metav1.ObjectMeta{ +// Name: "my-steps", +// Labels: map[string]string{ +// common.LabelKeyCompleted: "true", +// common.LabelKeyWorkflowArchivingStatus: "Pending", +// }, +// }, +// Status: wfv1.WorkflowStatus{ +// Phase: wfv1.WorkflowFailed, +// StartedAt: createdTime, +// FinishedAt: finishedTime, +// Nodes: map[string]wfv1.NodeStatus{ +// "failed-node": {Name: "failed-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeFailed, Message: "failed"}, +// "succeeded-node": {Name: "succeeded-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeSucceeded, Message: "succeeded"}}, +// }, +// } +// _, err := wfClient.Create(ctx, wf, metav1.CreateOptions{}) +// assert.NoError(t, err) +// wf, err = RetryArchivedWorkflow(ctx, kubeClient.CoreV1().Pods(wf.Namespace), wf, false, "") +// if assert.NoError(t, err) { +// assert.Equal(t, wfv1.WorkflowRunning, wf.Status.Phase) +// assert.Equal(t, metav1.Time{}, wf.Status.FinishedAt) +// assert.True(t, wf.Status.StartedAt.After(createdTime.Time)) +// assert.NotContains(t, wf.Labels, common.LabelKeyCompleted) +// assert.NotContains(t, wf.Labels, common.LabelKeyWorkflowArchivingStatus) +// for _, node := range wf.Status.Nodes { +// switch node.Phase { +// case wfv1.NodeSucceeded: +// assert.Equal(t, "succeeded", node.Message) +// assert.Equal(t, wfv1.NodeSucceeded, node.Phase) +// assert.Equal(t, createdTime, node.StartedAt) +// assert.Equal(t, finishedTime, node.FinishedAt) +// case wfv1.NodeFailed: +// assert.Equal(t, "", node.Message) +// assert.Equal(t, wfv1.NodeRunning, node.Phase) +// assert.Equal(t, metav1.Time{}, node.FinishedAt) +// assert.True(t, node.StartedAt.After(createdTime.Time)) +// } +// } +// } +// }) +// } func TestFromUnstructuredObj(t *testing.T) { un := &unstructured.Unstructured{} From d619ebb61bf59b5ab10337d0059a6489df3a0b7b Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Wed, 16 Mar 2022 16:54:03 -0700 Subject: [PATCH 26/28] test: clean up Signed-off-by: Dillen Padhiar --- test/e2e/argo_server_test.go | 1 - workflow/util/util_test.go | 51 ------------------------------------ 2 files changed, 52 deletions(-) diff --git a/test/e2e/argo_server_test.go b/test/e2e/argo_server_test.go index 45b39bf0b650..e2185d2cb9ab 100644 --- a/test/e2e/argo_server_test.go +++ b/test/e2e/argo_server_test.go @@ -1325,7 +1325,6 @@ spec: }) s.Run("Retry", func() { - s.Need(fixtures.BaseLayerArtifacts) s.e().PUT("/api/v1/archived-workflows/{uid}/retry", failedUid). WithBytes([]byte(`{"namespace": "argo"}`)). Expect(). diff --git a/workflow/util/util_test.go b/workflow/util/util_test.go index ab7ea8c19042..ae962ed6578a 100644 --- a/workflow/util/util_test.go +++ b/workflow/util/util_test.go @@ -891,57 +891,6 @@ func TestRetryWorkflow(t *testing.T) { }) } -// func TestRetryArchivedWorkflow(t *testing.T) { -// ctx := context.Background() -// kubeClient := kubefake.NewSimpleClientset() -// wfClient := argofake.NewSimpleClientset().ArgoprojV1alpha1().Workflows("my-ns") -// createdTime := metav1.Time{Time: time.Now().UTC()} -// finishedTime := metav1.Time{Time: createdTime.Add(time.Second * 2)} -// t.Run("Steps", func(t *testing.T) { -// wf := &wfv1.Workflow{ -// ObjectMeta: metav1.ObjectMeta{ -// Name: "my-steps", -// Labels: map[string]string{ -// common.LabelKeyCompleted: "true", -// common.LabelKeyWorkflowArchivingStatus: "Pending", -// }, -// }, -// Status: wfv1.WorkflowStatus{ -// Phase: wfv1.WorkflowFailed, -// StartedAt: createdTime, -// FinishedAt: finishedTime, -// Nodes: map[string]wfv1.NodeStatus{ -// "failed-node": {Name: "failed-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeFailed, Message: "failed"}, -// "succeeded-node": {Name: "succeeded-node", StartedAt: createdTime, FinishedAt: finishedTime, Phase: wfv1.NodeSucceeded, Message: "succeeded"}}, -// }, -// } -// _, err := wfClient.Create(ctx, wf, metav1.CreateOptions{}) -// assert.NoError(t, err) -// wf, err = RetryArchivedWorkflow(ctx, kubeClient.CoreV1().Pods(wf.Namespace), wf, false, "") -// if assert.NoError(t, err) { -// assert.Equal(t, wfv1.WorkflowRunning, wf.Status.Phase) -// assert.Equal(t, metav1.Time{}, wf.Status.FinishedAt) -// assert.True(t, wf.Status.StartedAt.After(createdTime.Time)) -// assert.NotContains(t, wf.Labels, common.LabelKeyCompleted) -// assert.NotContains(t, wf.Labels, common.LabelKeyWorkflowArchivingStatus) -// for _, node := range wf.Status.Nodes { -// switch node.Phase { -// case wfv1.NodeSucceeded: -// assert.Equal(t, "succeeded", node.Message) -// assert.Equal(t, wfv1.NodeSucceeded, node.Phase) -// assert.Equal(t, createdTime, node.StartedAt) -// assert.Equal(t, finishedTime, node.FinishedAt) -// case wfv1.NodeFailed: -// assert.Equal(t, "", node.Message) -// assert.Equal(t, wfv1.NodeRunning, node.Phase) -// assert.Equal(t, metav1.Time{}, node.FinishedAt) -// assert.True(t, node.StartedAt.After(createdTime.Time)) -// } -// } -// } -// }) -// } - func TestFromUnstructuredObj(t *testing.T) { un := &unstructured.Unstructured{} wfv1.MustUnmarshal([]byte(`apiVersion: argoproj.io/v1alpha1 From 9cd4ab7dabe89d18d5d29db9a5d69f11ad939533 Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Thu, 17 Mar 2022 11:27:23 -0700 Subject: [PATCH 27/28] refactor: added structured logging and changed error check Signed-off-by: Dillen Padhiar --- server/workflow/workflow_server.go | 4 ++-- server/workflowarchive/archived_workflow_server.go | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/server/workflow/workflow_server.go b/server/workflow/workflow_server.go index 5299db439d00..9d1419945dd7 100644 --- a/server/workflow/workflow_server.go +++ b/server/workflow/workflow_server.go @@ -330,10 +330,10 @@ func (s *workflowServer) RetryWorkflow(ctx context.Context, req *workflowpkg.Wor } for _, podName := range podsToDelete { - log.Infof("Deleting pod: %s", podName) + log.WithFields(log.Fields{"podDeleted": podName}).Info("Deleting pod") err := kubeClient.CoreV1().Pods(wf.Namespace).Delete(ctx, podName, metav1.DeleteOptions{}) if err != nil && !apierr.IsNotFound(err) { - return nil, errors.InternalWrapError(err) + return nil, err } } diff --git a/server/workflowarchive/archived_workflow_server.go b/server/workflowarchive/archived_workflow_server.go index 7276b459bee2..b420265d5754 100644 --- a/server/workflowarchive/archived_workflow_server.go +++ b/server/workflowarchive/archived_workflow_server.go @@ -16,7 +16,6 @@ import ( "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/selection" - "github.com/argoproj/argo-workflows/v3/errors" "github.com/argoproj/argo-workflows/v3/persist/sqldb" workflowarchivepkg "github.com/argoproj/argo-workflows/v3/pkg/apiclient/workflowarchive" "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow" @@ -228,15 +227,15 @@ func (w *archivedWorkflowServer) RetryArchivedWorkflow(ctx context.Context, req } for _, podName := range podsToDelete { - log.Infof("Deleting pod: %s", podName) + log.WithFields(log.Fields{"podDeleted": podName}).Info("Deleting pod") err := kubeClient.CoreV1().Pods(wf.Namespace).Delete(ctx, podName, metav1.DeleteOptions{}) if err != nil && !apierr.IsNotFound(err) { - return nil, errors.InternalWrapError(err) + return nil, err } } wf, err = wfClient.ArgoprojV1alpha1().Workflows(req.Namespace).Update(ctx, wf, metav1.UpdateOptions{}) - if apierr.IsAlreadyExists(err) { + if apierr.IsNotFound(err) { wf.ObjectMeta.ResourceVersion = "" wf, err = wfClient.ArgoprojV1alpha1().Workflows(req.Namespace).Create(ctx, wf, metav1.CreateOptions{}) if err != nil { From 68caea6ffb0db1690b68d09be53e35f4e9ae1883 Mon Sep 17 00:00:00 2001 From: Dillen Padhiar Date: Thu, 17 Mar 2022 13:36:00 -0700 Subject: [PATCH 28/28] refactor: remove RetryWorkflow Signed-off-by: Dillen Padhiar --- server/workflow/workflow_server.go | 2 +- server/workflowarchive/archived_workflow_server.go | 2 +- workflow/util/util.go | 11 +---------- workflow/util/util_test.go | 10 ++++------ 4 files changed, 7 insertions(+), 18 deletions(-) diff --git a/server/workflow/workflow_server.go b/server/workflow/workflow_server.go index 9d1419945dd7..40f50e2ded7d 100644 --- a/server/workflow/workflow_server.go +++ b/server/workflow/workflow_server.go @@ -324,7 +324,7 @@ func (s *workflowServer) RetryWorkflow(ctx context.Context, req *workflowpkg.Wor return nil, err } - wf, podsToDelete, err := util.RetryWorkflow(ctx, wf, req.RestartSuccessful, req.NodeFieldSelector) + wf, podsToDelete, err := util.FormulateRetryWorkflow(ctx, wf, req.RestartSuccessful, req.NodeFieldSelector) if err != nil { return nil, err } diff --git a/server/workflowarchive/archived_workflow_server.go b/server/workflowarchive/archived_workflow_server.go index b420265d5754..4f8594f1e12c 100644 --- a/server/workflowarchive/archived_workflow_server.go +++ b/server/workflowarchive/archived_workflow_server.go @@ -221,7 +221,7 @@ func (w *archivedWorkflowServer) RetryArchivedWorkflow(ctx context.Context, req return nil, err } - wf, podsToDelete, err := util.RetryWorkflow(ctx, wf, req.RestartSuccessful, req.NodeFieldSelector) + wf, podsToDelete, err := util.FormulateRetryWorkflow(ctx, wf, req.RestartSuccessful, req.NodeFieldSelector) if err != nil { return nil, err } diff --git a/workflow/util/util.go b/workflow/util/util.go index 4192fef668e5..d97d91db9892 100644 --- a/workflow/util/util.go +++ b/workflow/util/util.go @@ -733,16 +733,7 @@ func convertNodeID(newWf *wfv1.Workflow, regex *regexp.Regexp, oldNodeID string, return newWf.NodeID(newNodeName) } -// RetryWorkflow updates a workflow, deleting all failed steps as well as the onExit node (and children) -func RetryWorkflow(ctx context.Context, wf *wfv1.Workflow, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, []string, error) { - updatedWf, podsToDelete, err := FormulateRetryWorkflow(ctx, wf, restartSuccessful, nodeFieldSelector) - if err != nil { - return nil, nil, err - } - - return updatedWf, podsToDelete, err -} - +// FormulateRetryWorkflow formulates a previous workflow to be retried, deleting all failed steps as well as the onExit node (and children) func FormulateRetryWorkflow(ctx context.Context, wf *wfv1.Workflow, restartSuccessful bool, nodeFieldSelector string) (*wfv1.Workflow, []string, error) { switch wf.Status.Phase { diff --git a/workflow/util/util_test.go b/workflow/util/util_test.go index ae962ed6578a..4c22b0f9939f 100644 --- a/workflow/util/util_test.go +++ b/workflow/util/util_test.go @@ -804,13 +804,12 @@ status: func TestDeepDeleteNodes(t *testing.T) { wfIf := argofake.NewSimpleClientset().ArgoprojV1alpha1().Workflows("") - // kubeClient := &kubefake.Clientset{} origWf := wfv1.MustUnmarshalWorkflow(deepDeleteOfNodes) ctx := context.Background() wf, err := wfIf.Create(ctx, origWf, metav1.CreateOptions{}) if assert.NoError(t, err) { - newWf, _, err := RetryWorkflow(ctx, wf, false, "") + newWf, _, err := FormulateRetryWorkflow(ctx, wf, false, "") assert.NoError(t, err) newWfBytes, err := yaml.Marshal(newWf) assert.NoError(t, err) @@ -818,9 +817,8 @@ func TestDeepDeleteNodes(t *testing.T) { } } -func TestRetryWorkflow(t *testing.T) { +func TestFormulateRetryWorkflow(t *testing.T) { ctx := context.Background() - // kubeClient := kubefake.NewSimpleClientset() wfClient := argofake.NewSimpleClientset().ArgoprojV1alpha1().Workflows("my-ns") createdTime := metav1.Time{Time: time.Now().UTC()} finishedTime := metav1.Time{Time: createdTime.Add(time.Second * 2)} @@ -844,7 +842,7 @@ func TestRetryWorkflow(t *testing.T) { } _, err := wfClient.Create(ctx, wf, metav1.CreateOptions{}) assert.NoError(t, err) - wf, _, err = RetryWorkflow(ctx, wf, false, "") + wf, _, err = FormulateRetryWorkflow(ctx, wf, false, "") if assert.NoError(t, err) { assert.Equal(t, wfv1.WorkflowRunning, wf.Status.Phase) assert.Equal(t, metav1.Time{}, wf.Status.FinishedAt) @@ -881,7 +879,7 @@ func TestRetryWorkflow(t *testing.T) { } _, err := wfClient.Create(ctx, wf, metav1.CreateOptions{}) assert.NoError(t, err) - wf, _, err = RetryWorkflow(ctx, wf, false, "") + wf, _, err = FormulateRetryWorkflow(ctx, wf, false, "") if assert.NoError(t, err) { if assert.Len(t, wf.Status.Nodes, 1) { assert.Equal(t, wfv1.NodeRunning, wf.Status.Nodes[""].Phase)