diff --git a/flytectl/cmd/delete/matchable_attribute_util.go b/flytectl/cmd/delete/matchable_attribute_util.go index b2482270e8..020a60968d 100644 --- a/flytectl/cmd/delete/matchable_attribute_util.go +++ b/flytectl/cmd/delete/matchable_attribute_util.go @@ -26,12 +26,21 @@ func deleteMatchableAttr(ctx context.Context, project, domain, workflowName stri if dryRun { fmt.Print("skipping DeleteProjectDomainAttributes request (dryRun)\n") } else { - err := deleter.DeleteProjectDomainAttributes(ctx, project, domain, rsType) - if err != nil { - return err + if len(domain) == 0 { + err := deleter.DeleteProjectAttributes(ctx, project, rsType) + if err != nil { + return err + } + fmt.Printf("Deleted matchable resources from %v project \n", project) + } else { + err := deleter.DeleteProjectDomainAttributes(ctx, project, domain, rsType) + if err != nil { + return err + } + fmt.Printf("Deleted matchable resources from %v project and domain %v\n", project, domain) } } - fmt.Printf("Deleted matchable resources from %v project and domain %v\n", project, domain) + } return nil } diff --git a/flytectl/cmd/get/get.go b/flytectl/cmd/get/get.go index 2e0792166d..7c1b5ea164 100644 --- a/flytectl/cmd/get/get.go +++ b/flytectl/cmd/get/get.go @@ -65,7 +65,7 @@ func CreateGetCommand() *cobra.Command { Long: pluginOverrideLong, PFlagProvider: pluginoverride.DefaultFetchConfig}, "workflow-execution-config": {CmdFunc: getWorkflowExecutionConfigFunc, Aliases: []string{"workflow-execution-config"}, Short: workflowExecutionConfigShort, - Long: workflowExecutionConfigLong, PFlagProvider: workflowexecutionconfig.DefaultFetchConfig}, + Long: workflowExecutionConfigLong, PFlagProvider: workflowexecutionconfig.DefaultFetchConfig, ProjectDomainNotRequired: true}, } cmdcore.AddCommands(getCmd, getResourcesFuncs) diff --git a/flytectl/cmd/get/matchable_attribute_util.go b/flytectl/cmd/get/matchable_attribute_util.go index cddfdab348..0a6358bf39 100644 --- a/flytectl/cmd/get/matchable_attribute_util.go +++ b/flytectl/cmd/get/matchable_attribute_util.go @@ -20,13 +20,22 @@ func FetchAndUnDecorateMatchableAttr(ctx context.Context, project, domain, workf // Update the shadow config with the fetched taskResourceAttribute which can then be written to a file which can then be called for an update. unDecorator.UnDecorate(workflowAttr.GetAttributes().GetMatchingAttributes()) } else { - // Fetch the project domain attribute from the admin - projectDomainAttr, err := fetcher.FetchProjectDomainAttributes(ctx, project, domain, rsType) - if err != nil { - return err + if len(domain) == 0 { + projectAttr, err := fetcher.FetchProjectAttributes(ctx, project, rsType) + if err != nil { + return err + } + // Update the shadow config with the fetched taskResourceAttribute which can then be written to a file which can then be called for an update. + unDecorator.UnDecorate(projectAttr.GetAttributes().GetMatchingAttributes()) + } else { + // Fetch the project domain attribute from the admin + projectDomainAttr, err := fetcher.FetchProjectDomainAttributes(ctx, project, domain, rsType) + if err != nil { + return err + } + // Update the shadow config with the fetched taskResourceAttribute which can then be written to a file which can then be called for an update. + unDecorator.UnDecorate(projectDomainAttr.GetAttributes().GetMatchingAttributes()) } - // Update the shadow config with the fetched taskResourceAttribute which can then be written to a file which can then be called for an update. - unDecorator.UnDecorate(projectDomainAttr.GetAttributes().GetMatchingAttributes()) } return nil } diff --git a/flytectl/cmd/update/matchable_attribute_util.go b/flytectl/cmd/update/matchable_attribute_util.go index e3f4a2d296..23efa16912 100644 --- a/flytectl/cmd/update/matchable_attribute_util.go +++ b/flytectl/cmd/update/matchable_attribute_util.go @@ -27,12 +27,21 @@ func DecorateAndUpdateMatchableAttr(ctx context.Context, project, domain, workfl if dryRun { fmt.Printf("skipping UpdateProjectDomainAttributes request (dryRun)\n") } else { - err := updater.UpdateProjectDomainAttributes(ctx, project, domain, matchingAttr) - if err != nil { - return err + if len(domain) == 0 { + err := updater.UpdateProjectAttributes(ctx, project, matchingAttr) + if err != nil { + return err + } + fmt.Printf("Updated attributes from %v project\n", project) + } else { + err := updater.UpdateProjectDomainAttributes(ctx, project, domain, matchingAttr) + if err != nil { + return err + } + fmt.Printf("Updated attributes from %v project and domain %v\n", project, domain) } } - fmt.Printf("Updated attributes from %v project and domain %v\n", project, domain) + } return nil } diff --git a/flytectl/pkg/ext/attribute_match_deleter_test.go b/flytectl/pkg/ext/attribute_match_deleter_test.go index 9c8c665b08..c0105f99ce 100644 --- a/flytectl/pkg/ext/attribute_match_deleter_test.go +++ b/flytectl/pkg/ext/attribute_match_deleter_test.go @@ -47,3 +47,17 @@ func TestDeleteProjectDomainAttributesError(t *testing.T) { err := adminDeleterExt.DeleteProjectDomainAttributes(ctx, "dummyProject", "domainValue", admin.MatchableResource_TASK_RESOURCE) assert.Equal(t, fmt.Errorf("failed"), err) } + +func TestDeleteProjectAttributes(t *testing.T) { + deleteAttributeMatchFetcherSetup() + adminClient.OnDeleteProjectAttributesMatch(mock.Anything, mock.Anything).Return(nil, nil) + err := adminDeleterExt.DeleteProjectAttributes(ctx, "dummyProject", admin.MatchableResource_TASK_RESOURCE) + assert.Nil(t, err) +} + +func TestDeleteProjectAttributesError(t *testing.T) { + deleteAttributeMatchFetcherSetup() + adminClient.OnDeleteProjectAttributesMatch(mock.Anything, mock.Anything).Return(nil, fmt.Errorf("failed")) + err := adminDeleterExt.DeleteProjectAttributes(ctx, "dummyProject", admin.MatchableResource_TASK_RESOURCE) + assert.Equal(t, fmt.Errorf("failed"), err) +} diff --git a/flytectl/pkg/ext/attribute_match_fetcher.go b/flytectl/pkg/ext/attribute_match_fetcher.go index 0af146e8e1..3e33609b3b 100644 --- a/flytectl/pkg/ext/attribute_match_fetcher.go +++ b/flytectl/pkg/ext/attribute_match_fetcher.go @@ -40,3 +40,19 @@ func (a *AdminFetcherExtClient) FetchProjectDomainAttributes(ctx context.Context } return projectDomainAttr, nil } + +func (a *AdminFetcherExtClient) FetchProjectAttributes(ctx context.Context, project string, + rsType admin.MatchableResource) (*admin.ProjectAttributesGetResponse, error) { + projectDomainAttr, err := a.AdminServiceClient().GetProjectAttributes(ctx, + &admin.ProjectAttributesGetRequest{ + Project: project, + ResourceType: rsType, + }) + if err != nil { + return nil, err + } + if projectDomainAttr.GetAttributes() == nil || projectDomainAttr.GetAttributes().GetMatchingAttributes() == nil { + return nil, fmt.Errorf("attribute doesn't exist") + } + return projectDomainAttr, nil +} diff --git a/flytectl/pkg/ext/attribute_match_fetcher_test.go b/flytectl/pkg/ext/attribute_match_fetcher_test.go index ea7f29929a..81352d6bc2 100644 --- a/flytectl/pkg/ext/attribute_match_fetcher_test.go +++ b/flytectl/pkg/ext/attribute_match_fetcher_test.go @@ -79,3 +79,20 @@ func TestFetchProjectDomainAttributesError(t *testing.T) { assert.Equal(t, fmt.Errorf("attribute doesn't exist"), err) }) } + +func TestFetchProjectAttributesError(t *testing.T) { + t.Run("failed api", func(t *testing.T) { + getAttributeMatchFetcherSetup() + adminClient.OnGetProjectAttributesMatch(mock.Anything, mock.Anything).Return(nil, fmt.Errorf("failed")) + _, err := adminFetcherExt.FetchProjectAttributes(ctx, "dummyProject", admin.MatchableResource_TASK_RESOURCE) + assert.Equal(t, fmt.Errorf("failed"), err) + }) + t.Run("empty data from api", func(t *testing.T) { + getAttributeMatchFetcherSetup() + pResp := &admin.ProjectAttributesGetResponse{} + adminClient.OnGetProjectAttributesMatch(mock.Anything, mock.Anything).Return(pResp, nil) + _, err := adminFetcherExt.FetchProjectAttributes(ctx, "dummyProject", admin.MatchableResource_TASK_RESOURCE) + assert.NotNil(t, err) + assert.Equal(t, fmt.Errorf("attribute doesn't exist"), err) + }) +} diff --git a/flytectl/pkg/ext/attribute_match_updater.go b/flytectl/pkg/ext/attribute_match_updater.go index d06e22155e..44d00c394c 100644 --- a/flytectl/pkg/ext/attribute_match_updater.go +++ b/flytectl/pkg/ext/attribute_match_updater.go @@ -29,3 +29,14 @@ func (a *AdminUpdaterExtClient) UpdateProjectDomainAttributes(ctx context.Contex }) return err } + +func (a *AdminUpdaterExtClient) UpdateProjectAttributes(ctx context.Context, project string, matchingAttr *admin.MatchingAttributes) error { + _, err := a.AdminServiceClient().UpdateProjectAttributes(ctx, + &admin.ProjectAttributesUpdateRequest{ + Attributes: &admin.ProjectAttributes{ + Project: project, + MatchingAttributes: matchingAttr, + }, + }) + return err +} diff --git a/flytectl/pkg/ext/attribute_match_updater_test.go b/flytectl/pkg/ext/attribute_match_updater_test.go index f57d86a369..0c331c9ef5 100644 --- a/flytectl/pkg/ext/attribute_match_updater_test.go +++ b/flytectl/pkg/ext/attribute_match_updater_test.go @@ -53,3 +53,20 @@ func TestUpdateProjectDomainAttributesError(t *testing.T) { err := adminUpdaterExt.UpdateProjectDomainAttributes(ctx, "dummyProject", "domainValue", nil) assert.Equal(t, fmt.Errorf("failed"), err) } + +func TestUpdateProjectAttributes(t *testing.T) { + updateAttributeMatchFetcherSetup() + matchingAttr := &admin.MatchingAttributes{ + Target: &admin.MatchingAttributes_TaskResourceAttributes{}, + } + adminClient.OnUpdateProjectAttributesMatch(mock.Anything, mock.Anything).Return(nil, nil) + err := adminUpdaterExt.UpdateProjectAttributes(ctx, "dummyProject", matchingAttr) + assert.Nil(t, err) +} + +func TestUpdateProjectAttributesError(t *testing.T) { + updateAttributeMatchFetcherSetup() + adminClient.OnUpdateProjectAttributesMatch(mock.Anything, mock.Anything).Return(nil, fmt.Errorf("failed")) + err := adminUpdaterExt.UpdateProjectAttributes(ctx, "dummyProject", nil) + assert.Equal(t, fmt.Errorf("failed"), err) +} diff --git a/flytectl/pkg/ext/attribute_matcher_deleter.go b/flytectl/pkg/ext/attribute_matcher_deleter.go index b7fdaec9b2..ef8a5730fb 100644 --- a/flytectl/pkg/ext/attribute_matcher_deleter.go +++ b/flytectl/pkg/ext/attribute_matcher_deleter.go @@ -24,3 +24,11 @@ func (a *AdminDeleterExtClient) DeleteProjectDomainAttributes(ctx context.Contex }) return err } + +func (a *AdminDeleterExtClient) DeleteProjectAttributes(ctx context.Context, project string, rsType admin.MatchableResource) error { + _, err := a.AdminServiceClient().DeleteProjectAttributes(ctx, &admin.ProjectAttributesDeleteRequest{ + Project: project, + ResourceType: rsType, + }) + return err +} diff --git a/flytectl/pkg/ext/deleter.go b/flytectl/pkg/ext/deleter.go index 03827d1079..db5d97a748 100644 --- a/flytectl/pkg/ext/deleter.go +++ b/flytectl/pkg/ext/deleter.go @@ -18,6 +18,9 @@ type AdminDeleterExtInterface interface { // DeleteProjectDomainAttributes deletes project domain attributes for a particular matchable resource DeleteProjectDomainAttributes(ctx context.Context, project, domain string, rsType admin.MatchableResource) error + + // DeleteProjectAttributes deletes project attributes for a particular matchable resource + DeleteProjectAttributes(ctx context.Context, project string, rsType admin.MatchableResource) error } // AdminDeleterExtClient is used for interacting with extended features used for deleting/archiving data in admin service diff --git a/flytectl/pkg/ext/fetcher.go b/flytectl/pkg/ext/fetcher.go index 2c40e388f6..b706bf8a53 100644 --- a/flytectl/pkg/ext/fetcher.go +++ b/flytectl/pkg/ext/fetcher.go @@ -67,6 +67,9 @@ type AdminFetcherExtInterface interface { // FetchProjectDomainAttributes fetches project domain attributes particular resource type in a project, domain FetchProjectDomainAttributes(ctx context.Context, project, domain string, rsType admin.MatchableResource) (*admin.ProjectDomainAttributesGetResponse, error) + // FetchProjectAttributes fetches project attributes particular resource type in a project + FetchProjectAttributes(ctx context.Context, project string, rsType admin.MatchableResource) (*admin.ProjectAttributesGetResponse, error) + // ListProjects fetches all projects ListProjects(ctx context.Context, filter filters.Filters) (*admin.Projects, error) } diff --git a/flytectl/pkg/ext/mocks/admin_deleter_ext_interface.go b/flytectl/pkg/ext/mocks/admin_deleter_ext_interface.go index 1456f4e3bf..414cd17f54 100644 --- a/flytectl/pkg/ext/mocks/admin_deleter_ext_interface.go +++ b/flytectl/pkg/ext/mocks/admin_deleter_ext_interface.go @@ -51,6 +51,38 @@ func (_m *AdminDeleterExtInterface) AdminServiceClient() service.AdminServiceCli return r0 } +type AdminDeleterExtInterface_DeleteProjectAttributes struct { + *mock.Call +} + +func (_m AdminDeleterExtInterface_DeleteProjectAttributes) Return(_a0 error) *AdminDeleterExtInterface_DeleteProjectAttributes { + return &AdminDeleterExtInterface_DeleteProjectAttributes{Call: _m.Call.Return(_a0)} +} + +func (_m *AdminDeleterExtInterface) OnDeleteProjectAttributes(ctx context.Context, project string, rsType admin.MatchableResource) *AdminDeleterExtInterface_DeleteProjectAttributes { + c_call := _m.On("DeleteProjectAttributes", ctx, project, rsType) + return &AdminDeleterExtInterface_DeleteProjectAttributes{Call: c_call} +} + +func (_m *AdminDeleterExtInterface) OnDeleteProjectAttributesMatch(matchers ...interface{}) *AdminDeleterExtInterface_DeleteProjectAttributes { + c_call := _m.On("DeleteProjectAttributes", matchers...) + return &AdminDeleterExtInterface_DeleteProjectAttributes{Call: c_call} +} + +// DeleteProjectAttributes provides a mock function with given fields: ctx, project, rsType +func (_m *AdminDeleterExtInterface) DeleteProjectAttributes(ctx context.Context, project string, rsType admin.MatchableResource) error { + ret := _m.Called(ctx, project, rsType) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, admin.MatchableResource) error); ok { + r0 = rf(ctx, project, rsType) + } else { + r0 = ret.Error(0) + } + + return r0 +} + type AdminDeleterExtInterface_DeleteProjectDomainAttributes struct { *mock.Call } diff --git a/flytectl/pkg/ext/mocks/admin_fetcher_ext_interface.go b/flytectl/pkg/ext/mocks/admin_fetcher_ext_interface.go index b1032f05b2..3162a6b278 100644 --- a/flytectl/pkg/ext/mocks/admin_fetcher_ext_interface.go +++ b/flytectl/pkg/ext/mocks/admin_fetcher_ext_interface.go @@ -422,6 +422,47 @@ func (_m *AdminFetcherExtInterface) FetchNodeExecutionDetails(ctx context.Contex return r0, r1 } +type AdminFetcherExtInterface_FetchProjectAttributes struct { + *mock.Call +} + +func (_m AdminFetcherExtInterface_FetchProjectAttributes) Return(_a0 *admin.ProjectAttributesGetResponse, _a1 error) *AdminFetcherExtInterface_FetchProjectAttributes { + return &AdminFetcherExtInterface_FetchProjectAttributes{Call: _m.Call.Return(_a0, _a1)} +} + +func (_m *AdminFetcherExtInterface) OnFetchProjectAttributes(ctx context.Context, project string, rsType admin.MatchableResource) *AdminFetcherExtInterface_FetchProjectAttributes { + c_call := _m.On("FetchProjectAttributes", ctx, project, rsType) + return &AdminFetcherExtInterface_FetchProjectAttributes{Call: c_call} +} + +func (_m *AdminFetcherExtInterface) OnFetchProjectAttributesMatch(matchers ...interface{}) *AdminFetcherExtInterface_FetchProjectAttributes { + c_call := _m.On("FetchProjectAttributes", matchers...) + return &AdminFetcherExtInterface_FetchProjectAttributes{Call: c_call} +} + +// FetchProjectAttributes provides a mock function with given fields: ctx, project, rsType +func (_m *AdminFetcherExtInterface) FetchProjectAttributes(ctx context.Context, project string, rsType admin.MatchableResource) (*admin.ProjectAttributesGetResponse, error) { + ret := _m.Called(ctx, project, rsType) + + var r0 *admin.ProjectAttributesGetResponse + if rf, ok := ret.Get(0).(func(context.Context, string, admin.MatchableResource) *admin.ProjectAttributesGetResponse); ok { + r0 = rf(ctx, project, rsType) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*admin.ProjectAttributesGetResponse) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, string, admin.MatchableResource) error); ok { + r1 = rf(ctx, project, rsType) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + type AdminFetcherExtInterface_FetchProjectDomainAttributes struct { *mock.Call } diff --git a/flytectl/pkg/ext/mocks/admin_updater_ext_interface.go b/flytectl/pkg/ext/mocks/admin_updater_ext_interface.go index 93f8370556..a59d8ca748 100644 --- a/flytectl/pkg/ext/mocks/admin_updater_ext_interface.go +++ b/flytectl/pkg/ext/mocks/admin_updater_ext_interface.go @@ -51,6 +51,38 @@ func (_m *AdminUpdaterExtInterface) AdminServiceClient() service.AdminServiceCli return r0 } +type AdminUpdaterExtInterface_UpdateProjectAttributes struct { + *mock.Call +} + +func (_m AdminUpdaterExtInterface_UpdateProjectAttributes) Return(_a0 error) *AdminUpdaterExtInterface_UpdateProjectAttributes { + return &AdminUpdaterExtInterface_UpdateProjectAttributes{Call: _m.Call.Return(_a0)} +} + +func (_m *AdminUpdaterExtInterface) OnUpdateProjectAttributes(ctx context.Context, project string, matchingAttr *admin.MatchingAttributes) *AdminUpdaterExtInterface_UpdateProjectAttributes { + c_call := _m.On("UpdateProjectAttributes", ctx, project, matchingAttr) + return &AdminUpdaterExtInterface_UpdateProjectAttributes{Call: c_call} +} + +func (_m *AdminUpdaterExtInterface) OnUpdateProjectAttributesMatch(matchers ...interface{}) *AdminUpdaterExtInterface_UpdateProjectAttributes { + c_call := _m.On("UpdateProjectAttributes", matchers...) + return &AdminUpdaterExtInterface_UpdateProjectAttributes{Call: c_call} +} + +// UpdateProjectAttributes provides a mock function with given fields: ctx, project, matchingAttr +func (_m *AdminUpdaterExtInterface) UpdateProjectAttributes(ctx context.Context, project string, matchingAttr *admin.MatchingAttributes) error { + ret := _m.Called(ctx, project, matchingAttr) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, *admin.MatchingAttributes) error); ok { + r0 = rf(ctx, project, matchingAttr) + } else { + r0 = ret.Error(0) + } + + return r0 +} + type AdminUpdaterExtInterface_UpdateProjectDomainAttributes struct { *mock.Call } diff --git a/flytectl/pkg/ext/updater.go b/flytectl/pkg/ext/updater.go index ddf9f5841e..a87afd4ca0 100644 --- a/flytectl/pkg/ext/updater.go +++ b/flytectl/pkg/ext/updater.go @@ -18,6 +18,9 @@ type AdminUpdaterExtInterface interface { // UpdateProjectDomainAttributes updates project domain attributes for a particular matchable resource UpdateProjectDomainAttributes(ctx context.Context, project, domain string, matchingAttr *admin.MatchingAttributes) error + + // UpdateProjectAttributes updates project attributes for a particular matchable resource + UpdateProjectAttributes(ctx context.Context, project string, matchingAttr *admin.MatchingAttributes) error } // AdminUpdaterExtClient is used for interacting with extended features used for updating data in admin service