From 8b91781a0493a0f5cadad09d064124daadbd9593 Mon Sep 17 00:00:00 2001 From: Yuvraj Date: Sat, 5 Jun 2021 10:25:23 +0530 Subject: [PATCH] Added filters flag (#82) --- flytectl/cmd/config/config_flags.go | 11 +- flytectl/cmd/config/config_flags_test.go | 28 ++- .../subcommand/execution/config_flags.go | 58 ++++++ .../subcommand/execution/config_flags_test.go | 158 ++++++++++++++++ .../subcommand/execution/execution_config.go | 17 ++ .../subcommand/launchplan/config_flags.go | 62 +++++++ .../launchplan/config_flags_test.go} | 110 ++++++++---- .../launchplan/launchplan_config.go | 20 +++ .../config/subcommand/project/config_flags.go | 58 ++++++ .../subcommand/project/config_flags_test.go | 158 ++++++++++++++++ .../subcommand/project/project_config.go | 17 ++ .../config/subcommand/task/config_flags.go | 62 +++++++ .../subcommand/task/config_flags_test.go} | 110 ++++++++---- .../cmd/config/subcommand/task/task_config.go | 18 ++ .../subcommand/workflow/config_flags.go | 18 +- .../subcommand/workflow/config_flags_test.go | 70 ++++++-- .../subcommand/workflow/workflow_config.go | 11 +- flytectl/cmd/get/execution.go | 32 ++-- flytectl/cmd/get/get.go | 12 +- flytectl/cmd/get/launch_plan.go | 74 +++++--- flytectl/cmd/get/launch_plan_test.go | 86 ++++----- flytectl/cmd/get/launchplanconfig_flags.go | 48 ----- flytectl/cmd/get/named_entity.go | 11 -- flytectl/cmd/get/project.go | 21 ++- flytectl/cmd/get/project_test.go | 83 +++++++++ flytectl/cmd/get/task.go | 58 +++--- flytectl/cmd/get/task_test.go | 121 ++++++++----- flytectl/cmd/get/taskconfig_flags.go | 48 ----- flytectl/cmd/get/workflow.go | 45 ++++- flytectl/cmd/get/workflow_test.go | 59 +++++- flytectl/docs/source/gen/flytectl.rst | 2 - flytectl/docs/source/gen/flytectl_config.rst | 2 - .../source/gen/flytectl_config_discover.rst | 2 - .../source/gen/flytectl_config_validate.rst | 2 - flytectl/docs/source/gen/flytectl_create.rst | 2 - .../source/gen/flytectl_create_execution.rst | 2 - .../source/gen/flytectl_create_project.rst | 2 - flytectl/docs/source/gen/flytectl_delete.rst | 2 - ...ectl_delete_cluster-resource-attribute.rst | 2 - ...lytectl_delete_execution-cluster-label.rst | 2 - ...tectl_delete_execution-queue-attribute.rst | 2 - .../source/gen/flytectl_delete_execution.rst | 2 - .../gen/flytectl_delete_plugin-override.rst | 2 - ...lytectl_delete_task-resource-attribute.rst | 2 - flytectl/docs/source/gen/flytectl_get.rst | 2 - ...lytectl_get_cluster-resource-attribute.rst | 2 - .../flytectl_get_execution-cluster-label.rst | 2 - ...flytectl_get_execution-queue-attribute.rst | 2 - .../source/gen/flytectl_get_execution.rst | 25 ++- .../source/gen/flytectl_get_launchplan.rst | 32 +++- .../gen/flytectl_get_plugin-override.rst | 2 - .../docs/source/gen/flytectl_get_project.rst | 19 +- .../flytectl_get_task-resource-attribute.rst | 2 - .../docs/source/gen/flytectl_get_task.rst | 33 ++-- .../docs/source/gen/flytectl_get_workflow.rst | 26 ++- .../docs/source/gen/flytectl_register.rst | 2 - .../source/gen/flytectl_register_files.rst | 2 - flytectl/docs/source/gen/flytectl_update.rst | 2 - ...ectl_update_cluster-resource-attribute.rst | 2 - ...lytectl_update_execution-cluster-label.rst | 2 - ...tectl_update_execution-queue-attribute.rst | 2 - .../source/gen/flytectl_update_launchplan.rst | 2 - .../gen/flytectl_update_plugin-override.rst | 2 - .../source/gen/flytectl_update_project.rst | 2 - ...lytectl_update_task-resource-attribute.rst | 2 - .../docs/source/gen/flytectl_update_task.rst | 2 - .../source/gen/flytectl_update_workflow.rst | 2 - flytectl/docs/source/gen/flytectl_version.rst | 2 - flytectl/pkg/ext/deleter_test.go | 17 ++ flytectl/pkg/ext/fetcher.go | 14 +- flytectl/pkg/ext/fetcher_test.go | 17 ++ flytectl/pkg/ext/launch_plan_fetcher.go | 25 ++- flytectl/pkg/ext/launch_plan_fetcher_test.go | 32 +++- .../ext/mocks/admin_fetcher_ext_interface.go | 110 ++++++------ flytectl/pkg/ext/task_fetcher.go | 25 ++- flytectl/pkg/ext/task_fetcher_test.go | 34 +++- flytectl/pkg/ext/updater_test.go | 17 ++ flytectl/pkg/ext/workflow_fetcher.go | 25 ++- flytectl/pkg/ext/workflow_fetcher_test.go | 14 +- flytectl/pkg/filters/coverage.out | 68 +++++++ flytectl/pkg/filters/filters.go | 168 ++++++++++++++++++ flytectl/pkg/filters/filters_test.go | 73 ++++++++ flytectl/pkg/filters/operator.go | 12 ++ flytectl/pkg/filters/type.go | 17 ++ flytectl/pkg/filters/util.go | 54 ++++++ flytectl/pkg/filters/util_test.go | 111 ++++++++++++ 86 files changed, 2094 insertions(+), 624 deletions(-) create mode 100755 flytectl/cmd/config/subcommand/execution/config_flags.go create mode 100755 flytectl/cmd/config/subcommand/execution/config_flags_test.go create mode 100644 flytectl/cmd/config/subcommand/execution/execution_config.go create mode 100755 flytectl/cmd/config/subcommand/launchplan/config_flags.go rename flytectl/cmd/{get/taskconfig_flags_test.go => config/subcommand/launchplan/config_flags_test.go} (55%) create mode 100644 flytectl/cmd/config/subcommand/launchplan/launchplan_config.go create mode 100755 flytectl/cmd/config/subcommand/project/config_flags.go create mode 100755 flytectl/cmd/config/subcommand/project/config_flags_test.go create mode 100644 flytectl/cmd/config/subcommand/project/project_config.go create mode 100755 flytectl/cmd/config/subcommand/task/config_flags.go rename flytectl/cmd/{get/launchplanconfig_flags_test.go => config/subcommand/task/config_flags_test.go} (55%) create mode 100644 flytectl/cmd/config/subcommand/task/task_config.go delete mode 100755 flytectl/cmd/get/launchplanconfig_flags.go delete mode 100644 flytectl/cmd/get/named_entity.go create mode 100644 flytectl/cmd/get/project_test.go delete mode 100755 flytectl/cmd/get/taskconfig_flags.go create mode 100644 flytectl/pkg/ext/deleter_test.go create mode 100644 flytectl/pkg/ext/fetcher_test.go create mode 100644 flytectl/pkg/ext/updater_test.go create mode 100644 flytectl/pkg/filters/coverage.out create mode 100644 flytectl/pkg/filters/filters.go create mode 100644 flytectl/pkg/filters/filters_test.go create mode 100644 flytectl/pkg/filters/operator.go create mode 100644 flytectl/pkg/filters/type.go create mode 100644 flytectl/pkg/filters/util.go create mode 100644 flytectl/pkg/filters/util_test.go diff --git a/flytectl/cmd/config/config_flags.go b/flytectl/cmd/config/config_flags.go index 2722dde8f87..3a1616b7e69 100755 --- a/flytectl/cmd/config/config_flags.go +++ b/flytectl/cmd/config/config_flags.go @@ -28,6 +28,15 @@ func (Config) elemValueOrNil(v interface{}) interface{} { return v } +func (Config) mustJsonMarshal(v interface{}) string { + raw, err := json.Marshal(v) + if err != nil { + panic(err) + } + + return string(raw) +} + func (Config) mustMarshalJSON(v json.Marshaler) string { raw, err := v.MarshalJSON() if err != nil { @@ -43,6 +52,6 @@ func (cfg Config) GetPFlagSet(prefix string) *pflag.FlagSet { cmdFlags := pflag.NewFlagSet("Config", pflag.ExitOnError) cmdFlags.String(fmt.Sprintf("%v%v", prefix, "project"), defaultConfig.Project, "Specifies the project to work on.") cmdFlags.String(fmt.Sprintf("%v%v", prefix, "domain"), defaultConfig.Domain, "Specified the domain to work on.") - cmdFlags.String(fmt.Sprintf("%v%v", prefix, "output"), defaultConfig.Domain, "Specified the output type.") + cmdFlags.String(fmt.Sprintf("%v%v", prefix, "output"), defaultConfig.Output, "Specified the output type.") return cmdFlags } diff --git a/flytectl/cmd/config/config_flags_test.go b/flytectl/cmd/config/config_flags_test.go index 1297f830326..88446ff3e35 100755 --- a/flytectl/cmd/config/config_flags_test.go +++ b/flytectl/cmd/config/config_flags_test.go @@ -84,7 +84,7 @@ func testDecodeJson_Config(t *testing.T, val, result interface{}) { assert.NoError(t, decode_Config(val, result)) } -func testDecodeSlice_Config(t *testing.T, vStringSlice, result interface{}) { +func testDecodeRaw_Config(t *testing.T, vStringSlice, result interface{}) { assert.NoError(t, decode_Config(vStringSlice, result)) } @@ -100,14 +100,6 @@ func TestConfig_SetFlags(t *testing.T) { assert.True(t, cmdFlags.HasFlags()) t.Run("Test_project", func(t *testing.T) { - t.Run("DefaultValue", func(t *testing.T) { - // Test that default value is set properly - if vString, err := cmdFlags.GetString("project"); err == nil { - assert.Equal(t, string(defaultConfig.Project), vString) - } else { - assert.FailNow(t, err.Error()) - } - }) t.Run("Override", func(t *testing.T) { testValue := "1" @@ -122,21 +114,27 @@ func TestConfig_SetFlags(t *testing.T) { }) }) t.Run("Test_domain", func(t *testing.T) { - t.Run("DefaultValue", func(t *testing.T) { - // Test that default value is set properly + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("domain", testValue) if vString, err := cmdFlags.GetString("domain"); err == nil { - assert.Equal(t, string(defaultConfig.Domain), vString) + testDecodeJson_Config(t, fmt.Sprintf("%v", vString), &actual.Domain) + } else { assert.FailNow(t, err.Error()) } }) + }) + t.Run("Test_output", func(t *testing.T) { t.Run("Override", func(t *testing.T) { testValue := "1" - cmdFlags.Set("domain", testValue) - if vString, err := cmdFlags.GetString("domain"); err == nil { - testDecodeJson_Config(t, fmt.Sprintf("%v", vString), &actual.Domain) + cmdFlags.Set("output", testValue) + if vString, err := cmdFlags.GetString("output"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vString), &actual.Output) } else { assert.FailNow(t, err.Error()) diff --git a/flytectl/cmd/config/subcommand/execution/config_flags.go b/flytectl/cmd/config/subcommand/execution/config_flags.go new file mode 100755 index 00000000000..5fcc9b332cc --- /dev/null +++ b/flytectl/cmd/config/subcommand/execution/config_flags.go @@ -0,0 +1,58 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots. + +package execution + +import ( + "encoding/json" + "reflect" + + "fmt" + + "github.com/spf13/pflag" +) + +// If v is a pointer, it will get its element value or the zero value of the element type. +// If v is not a pointer, it will return it as is. +func (Config) elemValueOrNil(v interface{}) interface{} { + if t := reflect.TypeOf(v); t.Kind() == reflect.Ptr { + if reflect.ValueOf(v).IsNil() { + return reflect.Zero(t.Elem()).Interface() + } else { + return reflect.ValueOf(v).Interface() + } + } else if v == nil { + return reflect.Zero(t).Interface() + } + + return v +} + +func (Config) mustJsonMarshal(v interface{}) string { + raw, err := json.Marshal(v) + if err != nil { + panic(err) + } + + return string(raw) +} + +func (Config) mustMarshalJSON(v json.Marshaler) string { + raw, err := v.MarshalJSON() + if err != nil { + panic(err) + } + + return string(raw) +} + +// GetPFlagSet will return strongly types pflags for all fields in Config and its nested types. The format of the +// flags is json-name.json-sub-name... etc. +func (cfg Config) GetPFlagSet(prefix string) *pflag.FlagSet { + cmdFlags := pflag.NewFlagSet("Config", pflag.ExitOnError) + cmdFlags.StringVar(&(DefaultConfig.Filter.FieldSelector), fmt.Sprintf("%v%v", prefix, "filter.field-selector"), *new(string), "Specifies the Field selector") + cmdFlags.StringVar((&DefaultConfig.Filter.SortBy), fmt.Sprintf("%v%v", prefix, "filter.sort-by"), *new(string), "Specifies which field to sort result by ") + cmdFlags.Int32Var((&DefaultConfig.Filter.Limit), fmt.Sprintf("%v%v", prefix, "filter.limit"), 100, "Specifies the limit") + cmdFlags.BoolVar((&DefaultConfig.Filter.Asc), fmt.Sprintf("%v%v", prefix, "filter.asc"), false, "Specifies the sorting order. By default flytectl sort result in descending order") + return cmdFlags +} diff --git a/flytectl/cmd/config/subcommand/execution/config_flags_test.go b/flytectl/cmd/config/subcommand/execution/config_flags_test.go new file mode 100755 index 00000000000..7be80b6d676 --- /dev/null +++ b/flytectl/cmd/config/subcommand/execution/config_flags_test.go @@ -0,0 +1,158 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots. + +package execution + +import ( + "encoding/json" + "fmt" + "reflect" + "strings" + "testing" + + "github.com/mitchellh/mapstructure" + "github.com/stretchr/testify/assert" +) + +var dereferencableKindsConfig = map[reflect.Kind]struct{}{ + reflect.Array: {}, reflect.Chan: {}, reflect.Map: {}, reflect.Ptr: {}, reflect.Slice: {}, +} + +// Checks if t is a kind that can be dereferenced to get its underlying type. +func canGetElementConfig(t reflect.Kind) bool { + _, exists := dereferencableKindsConfig[t] + return exists +} + +// This decoder hook tests types for json unmarshaling capability. If implemented, it uses json unmarshal to build the +// object. Otherwise, it'll just pass on the original data. +func jsonUnmarshalerHookConfig(_, to reflect.Type, data interface{}) (interface{}, error) { + unmarshalerType := reflect.TypeOf((*json.Unmarshaler)(nil)).Elem() + if to.Implements(unmarshalerType) || reflect.PtrTo(to).Implements(unmarshalerType) || + (canGetElementConfig(to.Kind()) && to.Elem().Implements(unmarshalerType)) { + + raw, err := json.Marshal(data) + if err != nil { + fmt.Printf("Failed to marshal Data: %v. Error: %v. Skipping jsonUnmarshalHook", data, err) + return data, nil + } + + res := reflect.New(to).Interface() + err = json.Unmarshal(raw, &res) + if err != nil { + fmt.Printf("Failed to umarshal Data: %v. Error: %v. Skipping jsonUnmarshalHook", data, err) + return data, nil + } + + return res, nil + } + + return data, nil +} + +func decode_Config(input, result interface{}) error { + config := &mapstructure.DecoderConfig{ + TagName: "json", + WeaklyTypedInput: true, + Result: result, + DecodeHook: mapstructure.ComposeDecodeHookFunc( + mapstructure.StringToTimeDurationHookFunc(), + mapstructure.StringToSliceHookFunc(","), + jsonUnmarshalerHookConfig, + ), + } + + decoder, err := mapstructure.NewDecoder(config) + if err != nil { + return err + } + + return decoder.Decode(input) +} + +func join_Config(arr interface{}, sep string) string { + listValue := reflect.ValueOf(arr) + strs := make([]string, 0, listValue.Len()) + for i := 0; i < listValue.Len(); i++ { + strs = append(strs, fmt.Sprintf("%v", listValue.Index(i))) + } + + return strings.Join(strs, sep) +} + +func testDecodeJson_Config(t *testing.T, val, result interface{}) { + assert.NoError(t, decode_Config(val, result)) +} + +func testDecodeRaw_Config(t *testing.T, vStringSlice, result interface{}) { + assert.NoError(t, decode_Config(vStringSlice, result)) +} + +func TestConfig_GetPFlagSet(t *testing.T) { + val := Config{} + cmdFlags := val.GetPFlagSet("") + assert.True(t, cmdFlags.HasFlags()) +} + +func TestConfig_SetFlags(t *testing.T) { + actual := Config{} + cmdFlags := actual.GetPFlagSet("") + assert.True(t, cmdFlags.HasFlags()) + + t.Run("Test_filter.field-selector", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("filter.field-selector", testValue) + if vString, err := cmdFlags.GetString("filter.field-selector"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vString), &actual.Filter.FieldSelector) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_filter.sort-by", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("filter.sort-by", testValue) + if vString, err := cmdFlags.GetString("filter.sort-by"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vString), &actual.Filter.SortBy) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_filter.limit", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("filter.limit", testValue) + if vInt32, err := cmdFlags.GetInt32("filter.limit"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vInt32), &actual.Filter.Limit) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_filter.asc", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("filter.asc", testValue) + if vBool, err := cmdFlags.GetBool("filter.asc"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vBool), &actual.Filter.Asc) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) +} diff --git a/flytectl/cmd/config/subcommand/execution/execution_config.go b/flytectl/cmd/config/subcommand/execution/execution_config.go new file mode 100644 index 00000000000..b0737aee648 --- /dev/null +++ b/flytectl/cmd/config/subcommand/execution/execution_config.go @@ -0,0 +1,17 @@ +package execution + +import ( + "github.com/flyteorg/flytectl/pkg/filters" +) + +//go:generate pflags Config --default-var DefaultConfig +var ( + DefaultConfig = &Config{ + Filter: filters.DefaultFilter, + } +) + +// Config +type Config struct { + Filter filters.Filters `json:"filter" pflag:","` +} diff --git a/flytectl/cmd/config/subcommand/launchplan/config_flags.go b/flytectl/cmd/config/subcommand/launchplan/config_flags.go new file mode 100755 index 00000000000..db572d98ea7 --- /dev/null +++ b/flytectl/cmd/config/subcommand/launchplan/config_flags.go @@ -0,0 +1,62 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots. + +package launchplan + +import ( + "encoding/json" + "reflect" + + "fmt" + + "github.com/spf13/pflag" +) + +// If v is a pointer, it will get its element value or the zero value of the element type. +// If v is not a pointer, it will return it as is. +func (Config) elemValueOrNil(v interface{}) interface{} { + if t := reflect.TypeOf(v); t.Kind() == reflect.Ptr { + if reflect.ValueOf(v).IsNil() { + return reflect.Zero(t.Elem()).Interface() + } else { + return reflect.ValueOf(v).Interface() + } + } else if v == nil { + return reflect.Zero(t).Interface() + } + + return v +} + +func (Config) mustJsonMarshal(v interface{}) string { + raw, err := json.Marshal(v) + if err != nil { + panic(err) + } + + return string(raw) +} + +func (Config) mustMarshalJSON(v json.Marshaler) string { + raw, err := v.MarshalJSON() + if err != nil { + panic(err) + } + + return string(raw) +} + +// GetPFlagSet will return strongly types pflags for all fields in Config and its nested types. The format of the +// flags is json-name.json-sub-name... etc. +func (cfg Config) GetPFlagSet(prefix string) *pflag.FlagSet { + cmdFlags := pflag.NewFlagSet("Config", pflag.ExitOnError) + cmdFlags.StringVar(&(DefaultConfig.ExecFile), fmt.Sprintf("%v%v", prefix, "execFile"), DefaultConfig.ExecFile, "execution file name to be used for generating execution spec of a single launchplan.") + cmdFlags.StringVar(&(DefaultConfig.Version), fmt.Sprintf("%v%v", prefix, "version"), DefaultConfig.Version, "version of the launchplan to be fetched.") + cmdFlags.BoolVar(&(DefaultConfig.Latest), fmt.Sprintf("%v%v", prefix, "latest"), DefaultConfig.Latest, "flag to indicate to fetch the latest version, version flag will be ignored in this case") + + cmdFlags.StringVar(&(DefaultConfig.Filter.FieldSelector), fmt.Sprintf("%v%v", prefix, "filter.field-selector"), *new(string), "Specifies the Field selector") + cmdFlags.StringVar((&DefaultConfig.Filter.SortBy), fmt.Sprintf("%v%v", prefix, "filter.sort-by"), *new(string), "Specifies which field to sort result by ") + cmdFlags.Int32Var((&DefaultConfig.Filter.Limit), fmt.Sprintf("%v%v", prefix, "filter.limit"), 100, "Specifies the limit") + cmdFlags.BoolVar((&DefaultConfig.Filter.Asc), fmt.Sprintf("%v%v", prefix, "filter.asc"), false, "Specifies the sorting order. By default flytectl sort result in descending order") + return cmdFlags +} diff --git a/flytectl/cmd/get/taskconfig_flags_test.go b/flytectl/cmd/config/subcommand/launchplan/config_flags_test.go similarity index 55% rename from flytectl/cmd/get/taskconfig_flags_test.go rename to flytectl/cmd/config/subcommand/launchplan/config_flags_test.go index b945e786196..ec536464bce 100755 --- a/flytectl/cmd/get/taskconfig_flags_test.go +++ b/flytectl/cmd/config/subcommand/launchplan/config_flags_test.go @@ -1,7 +1,7 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots. -package get +package launchplan import ( "encoding/json" @@ -14,22 +14,22 @@ import ( "github.com/stretchr/testify/assert" ) -var dereferencableKindsTaskConfig = map[reflect.Kind]struct{}{ +var dereferencableKindsConfig = map[reflect.Kind]struct{}{ reflect.Array: {}, reflect.Chan: {}, reflect.Map: {}, reflect.Ptr: {}, reflect.Slice: {}, } // Checks if t is a kind that can be dereferenced to get its underlying type. -func canGetElementTaskConfig(t reflect.Kind) bool { - _, exists := dereferencableKindsTaskConfig[t] +func canGetElementConfig(t reflect.Kind) bool { + _, exists := dereferencableKindsConfig[t] return exists } // This decoder hook tests types for json unmarshaling capability. If implemented, it uses json unmarshal to build the // object. Otherwise, it'll just pass on the original data. -func jsonUnmarshalerHookTaskConfig(_, to reflect.Type, data interface{}) (interface{}, error) { +func jsonUnmarshalerHookConfig(_, to reflect.Type, data interface{}) (interface{}, error) { unmarshalerType := reflect.TypeOf((*json.Unmarshaler)(nil)).Elem() if to.Implements(unmarshalerType) || reflect.PtrTo(to).Implements(unmarshalerType) || - (canGetElementTaskConfig(to.Kind()) && to.Elem().Implements(unmarshalerType)) { + (canGetElementConfig(to.Kind()) && to.Elem().Implements(unmarshalerType)) { raw, err := json.Marshal(data) if err != nil { @@ -50,7 +50,7 @@ func jsonUnmarshalerHookTaskConfig(_, to reflect.Type, data interface{}) (interf return data, nil } -func decode_TaskConfig(input, result interface{}) error { +func decode_Config(input, result interface{}) error { config := &mapstructure.DecoderConfig{ TagName: "json", WeaklyTypedInput: true, @@ -58,7 +58,7 @@ func decode_TaskConfig(input, result interface{}) error { DecodeHook: mapstructure.ComposeDecodeHookFunc( mapstructure.StringToTimeDurationHookFunc(), mapstructure.StringToSliceHookFunc(","), - jsonUnmarshalerHookTaskConfig, + jsonUnmarshalerHookConfig, ), } @@ -70,7 +70,7 @@ func decode_TaskConfig(input, result interface{}) error { return decoder.Decode(input) } -func join_TaskConfig(arr interface{}, sep string) string { +func join_Config(arr interface{}, sep string) string { listValue := reflect.ValueOf(arr) strs := make([]string, 0, listValue.Len()) for i := 0; i < listValue.Len(); i++ { @@ -80,85 +80,117 @@ func join_TaskConfig(arr interface{}, sep string) string { return strings.Join(strs, sep) } -func testDecodeJson_TaskConfig(t *testing.T, val, result interface{}) { - assert.NoError(t, decode_TaskConfig(val, result)) +func testDecodeJson_Config(t *testing.T, val, result interface{}) { + assert.NoError(t, decode_Config(val, result)) } -func testDecodeSlice_TaskConfig(t *testing.T, vStringSlice, result interface{}) { - assert.NoError(t, decode_TaskConfig(vStringSlice, result)) +func testDecodeRaw_Config(t *testing.T, vStringSlice, result interface{}) { + assert.NoError(t, decode_Config(vStringSlice, result)) } -func TestTaskConfig_GetPFlagSet(t *testing.T) { - val := TaskConfig{} +func TestConfig_GetPFlagSet(t *testing.T) { + val := Config{} cmdFlags := val.GetPFlagSet("") assert.True(t, cmdFlags.HasFlags()) } -func TestTaskConfig_SetFlags(t *testing.T) { - actual := TaskConfig{} +func TestConfig_SetFlags(t *testing.T) { + actual := Config{} cmdFlags := actual.GetPFlagSet("") assert.True(t, cmdFlags.HasFlags()) t.Run("Test_execFile", func(t *testing.T) { - t.Run("DefaultValue", func(t *testing.T) { - // Test that default value is set properly + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("execFile", testValue) if vString, err := cmdFlags.GetString("execFile"); err == nil { - assert.Equal(t, string(taskConfig.ExecFile), vString) + testDecodeJson_Config(t, fmt.Sprintf("%v", vString), &actual.ExecFile) + } else { assert.FailNow(t, err.Error()) } }) + }) + t.Run("Test_version", func(t *testing.T) { t.Run("Override", func(t *testing.T) { testValue := "1" - cmdFlags.Set("execFile", testValue) - if vString, err := cmdFlags.GetString("execFile"); err == nil { - testDecodeJson_TaskConfig(t, fmt.Sprintf("%v", vString), &actual.ExecFile) + cmdFlags.Set("version", testValue) + if vString, err := cmdFlags.GetString("version"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vString), &actual.Version) } else { assert.FailNow(t, err.Error()) } }) }) - t.Run("Test_version", func(t *testing.T) { - t.Run("DefaultValue", func(t *testing.T) { - // Test that default value is set properly - if vString, err := cmdFlags.GetString("version"); err == nil { - assert.Equal(t, string(taskConfig.Version), vString) + t.Run("Test_latest", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("latest", testValue) + if vBool, err := cmdFlags.GetBool("latest"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vBool), &actual.Latest) + } else { assert.FailNow(t, err.Error()) } }) + }) + t.Run("Test_filter.field-selector", func(t *testing.T) { t.Run("Override", func(t *testing.T) { testValue := "1" - cmdFlags.Set("version", testValue) - if vString, err := cmdFlags.GetString("version"); err == nil { - testDecodeJson_TaskConfig(t, fmt.Sprintf("%v", vString), &actual.Version) + cmdFlags.Set("filter.field-selector", testValue) + if vString, err := cmdFlags.GetString("filter.field-selector"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vString), &actual.Filter.FieldSelector) } else { assert.FailNow(t, err.Error()) } }) }) - t.Run("Test_latest", func(t *testing.T) { - t.Run("DefaultValue", func(t *testing.T) { - // Test that default value is set properly - if vBool, err := cmdFlags.GetBool("latest"); err == nil { - assert.Equal(t, bool(taskConfig.Latest), vBool) + t.Run("Test_filter.sort-by", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("filter.sort-by", testValue) + if vString, err := cmdFlags.GetString("filter.sort-by"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vString), &actual.Filter.SortBy) + } else { assert.FailNow(t, err.Error()) } }) + }) + t.Run("Test_filter.limit", func(t *testing.T) { t.Run("Override", func(t *testing.T) { testValue := "1" - cmdFlags.Set("latest", testValue) - if vBool, err := cmdFlags.GetBool("latest"); err == nil { - testDecodeJson_TaskConfig(t, fmt.Sprintf("%v", vBool), &actual.Latest) + cmdFlags.Set("filter.limit", testValue) + if vInt32, err := cmdFlags.GetInt32("filter.limit"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vInt32), &actual.Filter.Limit) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_filter.asc", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("filter.asc", testValue) + if vBool, err := cmdFlags.GetBool("filter.asc"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vBool), &actual.Filter.Asc) } else { assert.FailNow(t, err.Error()) diff --git a/flytectl/cmd/config/subcommand/launchplan/launchplan_config.go b/flytectl/cmd/config/subcommand/launchplan/launchplan_config.go new file mode 100644 index 00000000000..5e245deb48b --- /dev/null +++ b/flytectl/cmd/config/subcommand/launchplan/launchplan_config.go @@ -0,0 +1,20 @@ +package launchplan + +import ( + "github.com/flyteorg/flytectl/pkg/filters" +) + +//go:generate pflags Config --default-var DefaultConfig +var ( + DefaultConfig = &Config{ + Filter: filters.DefaultFilter, + } +) + +// Config +type Config struct { + ExecFile string `json:"execFile" pflag:",execution file name to be used for generating execution spec of a single launchplan."` + Version string `json:"version" pflag:",version of the launchplan to be fetched."` + Latest bool `json:"latest" pflag:", flag to indicate to fetch the latest version, version flag will be ignored in this case"` + Filter filters.Filters `json:"filter" pflag:","` +} diff --git a/flytectl/cmd/config/subcommand/project/config_flags.go b/flytectl/cmd/config/subcommand/project/config_flags.go new file mode 100755 index 00000000000..3a3e9bb5df1 --- /dev/null +++ b/flytectl/cmd/config/subcommand/project/config_flags.go @@ -0,0 +1,58 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots. + +package project + +import ( + "encoding/json" + "reflect" + + "fmt" + + "github.com/spf13/pflag" +) + +// If v is a pointer, it will get its element value or the zero value of the element type. +// If v is not a pointer, it will return it as is. +func (Config) elemValueOrNil(v interface{}) interface{} { + if t := reflect.TypeOf(v); t.Kind() == reflect.Ptr { + if reflect.ValueOf(v).IsNil() { + return reflect.Zero(t.Elem()).Interface() + } else { + return reflect.ValueOf(v).Interface() + } + } else if v == nil { + return reflect.Zero(t).Interface() + } + + return v +} + +func (Config) mustJsonMarshal(v interface{}) string { + raw, err := json.Marshal(v) + if err != nil { + panic(err) + } + + return string(raw) +} + +func (Config) mustMarshalJSON(v json.Marshaler) string { + raw, err := v.MarshalJSON() + if err != nil { + panic(err) + } + + return string(raw) +} + +// GetPFlagSet will return strongly types pflags for all fields in Config and its nested types. The format of the +// flags is json-name.json-sub-name... etc. +func (cfg Config) GetPFlagSet(prefix string) *pflag.FlagSet { + cmdFlags := pflag.NewFlagSet("Config", pflag.ExitOnError) + cmdFlags.StringVar(&(DefaultConfig.Filter.FieldSelector), fmt.Sprintf("%v%v", prefix, "filter.field-selector"), *new(string), "Specifies the Field selector") + cmdFlags.StringVar((&DefaultConfig.Filter.SortBy), fmt.Sprintf("%v%v", prefix, "filter.sort-by"), *new(string), "Specifies which field to sort result by ") + cmdFlags.Int32Var((&DefaultConfig.Filter.Limit), fmt.Sprintf("%v%v", prefix, "filter.limit"), 100, "Specifies the limit") + cmdFlags.BoolVar((&DefaultConfig.Filter.Asc), fmt.Sprintf("%v%v", prefix, "filter.asc"), false, "Specifies the sorting order. By default flytectl sort result in descending order") + return cmdFlags +} diff --git a/flytectl/cmd/config/subcommand/project/config_flags_test.go b/flytectl/cmd/config/subcommand/project/config_flags_test.go new file mode 100755 index 00000000000..50fcfad9d25 --- /dev/null +++ b/flytectl/cmd/config/subcommand/project/config_flags_test.go @@ -0,0 +1,158 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots. + +package project + +import ( + "encoding/json" + "fmt" + "reflect" + "strings" + "testing" + + "github.com/mitchellh/mapstructure" + "github.com/stretchr/testify/assert" +) + +var dereferencableKindsConfig = map[reflect.Kind]struct{}{ + reflect.Array: {}, reflect.Chan: {}, reflect.Map: {}, reflect.Ptr: {}, reflect.Slice: {}, +} + +// Checks if t is a kind that can be dereferenced to get its underlying type. +func canGetElementConfig(t reflect.Kind) bool { + _, exists := dereferencableKindsConfig[t] + return exists +} + +// This decoder hook tests types for json unmarshaling capability. If implemented, it uses json unmarshal to build the +// object. Otherwise, it'll just pass on the original data. +func jsonUnmarshalerHookConfig(_, to reflect.Type, data interface{}) (interface{}, error) { + unmarshalerType := reflect.TypeOf((*json.Unmarshaler)(nil)).Elem() + if to.Implements(unmarshalerType) || reflect.PtrTo(to).Implements(unmarshalerType) || + (canGetElementConfig(to.Kind()) && to.Elem().Implements(unmarshalerType)) { + + raw, err := json.Marshal(data) + if err != nil { + fmt.Printf("Failed to marshal Data: %v. Error: %v. Skipping jsonUnmarshalHook", data, err) + return data, nil + } + + res := reflect.New(to).Interface() + err = json.Unmarshal(raw, &res) + if err != nil { + fmt.Printf("Failed to umarshal Data: %v. Error: %v. Skipping jsonUnmarshalHook", data, err) + return data, nil + } + + return res, nil + } + + return data, nil +} + +func decode_Config(input, result interface{}) error { + config := &mapstructure.DecoderConfig{ + TagName: "json", + WeaklyTypedInput: true, + Result: result, + DecodeHook: mapstructure.ComposeDecodeHookFunc( + mapstructure.StringToTimeDurationHookFunc(), + mapstructure.StringToSliceHookFunc(","), + jsonUnmarshalerHookConfig, + ), + } + + decoder, err := mapstructure.NewDecoder(config) + if err != nil { + return err + } + + return decoder.Decode(input) +} + +func join_Config(arr interface{}, sep string) string { + listValue := reflect.ValueOf(arr) + strs := make([]string, 0, listValue.Len()) + for i := 0; i < listValue.Len(); i++ { + strs = append(strs, fmt.Sprintf("%v", listValue.Index(i))) + } + + return strings.Join(strs, sep) +} + +func testDecodeJson_Config(t *testing.T, val, result interface{}) { + assert.NoError(t, decode_Config(val, result)) +} + +func testDecodeRaw_Config(t *testing.T, vStringSlice, result interface{}) { + assert.NoError(t, decode_Config(vStringSlice, result)) +} + +func TestConfig_GetPFlagSet(t *testing.T) { + val := Config{} + cmdFlags := val.GetPFlagSet("") + assert.True(t, cmdFlags.HasFlags()) +} + +func TestConfig_SetFlags(t *testing.T) { + actual := Config{} + cmdFlags := actual.GetPFlagSet("") + assert.True(t, cmdFlags.HasFlags()) + + t.Run("Test_filter.field-selector", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("filter.field-selector", testValue) + if vString, err := cmdFlags.GetString("filter.field-selector"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vString), &actual.Filter.FieldSelector) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_filter.sort-by", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("filter.sort-by", testValue) + if vString, err := cmdFlags.GetString("filter.sort-by"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vString), &actual.Filter.SortBy) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_filter.limit", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("filter.limit", testValue) + if vInt32, err := cmdFlags.GetInt32("filter.limit"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vInt32), &actual.Filter.Limit) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_filter.asc", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("filter.asc", testValue) + if vBool, err := cmdFlags.GetBool("filter.asc"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vBool), &actual.Filter.Asc) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) +} diff --git a/flytectl/cmd/config/subcommand/project/project_config.go b/flytectl/cmd/config/subcommand/project/project_config.go new file mode 100644 index 00000000000..e5a78505952 --- /dev/null +++ b/flytectl/cmd/config/subcommand/project/project_config.go @@ -0,0 +1,17 @@ +package project + +import ( + "github.com/flyteorg/flytectl/pkg/filters" +) + +//go:generate pflags Config --default-var DefaultConfig +var ( + DefaultConfig = &Config{ + Filter: filters.DefaultFilter, + } +) + +// Config +type Config struct { + Filter filters.Filters `json:"filter" pflag:","` +} diff --git a/flytectl/cmd/config/subcommand/task/config_flags.go b/flytectl/cmd/config/subcommand/task/config_flags.go new file mode 100755 index 00000000000..4c48a38e6c3 --- /dev/null +++ b/flytectl/cmd/config/subcommand/task/config_flags.go @@ -0,0 +1,62 @@ +// Code generated by go generate; DO NOT EDIT. +// This file was generated by robots. + +package task + +import ( + "encoding/json" + "reflect" + + "fmt" + + "github.com/spf13/pflag" +) + +// If v is a pointer, it will get its element value or the zero value of the element type. +// If v is not a pointer, it will return it as is. +func (Config) elemValueOrNil(v interface{}) interface{} { + if t := reflect.TypeOf(v); t.Kind() == reflect.Ptr { + if reflect.ValueOf(v).IsNil() { + return reflect.Zero(t.Elem()).Interface() + } else { + return reflect.ValueOf(v).Interface() + } + } else if v == nil { + return reflect.Zero(t).Interface() + } + + return v +} + +func (Config) mustJsonMarshal(v interface{}) string { + raw, err := json.Marshal(v) + if err != nil { + panic(err) + } + + return string(raw) +} + +func (Config) mustMarshalJSON(v json.Marshaler) string { + raw, err := v.MarshalJSON() + if err != nil { + panic(err) + } + + return string(raw) +} + +// GetPFlagSet will return strongly types pflags for all fields in Config and its nested types. The format of the +// flags is json-name.json-sub-name... etc. +func (cfg Config) GetPFlagSet(prefix string) *pflag.FlagSet { + cmdFlags := pflag.NewFlagSet("Config", pflag.ExitOnError) + cmdFlags.StringVar(&(DefaultConfig.ExecFile), fmt.Sprintf("%v%v", prefix, "execFile"), DefaultConfig.ExecFile, "execution file name to be used for generating execution spec of a single task.") + cmdFlags.StringVar(&(DefaultConfig.Version), fmt.Sprintf("%v%v", prefix, "version"), DefaultConfig.Version, "version of the task to be fetched.") + cmdFlags.BoolVar(&(DefaultConfig.Latest), fmt.Sprintf("%v%v", prefix, "latest"), DefaultConfig.Latest, "flag to indicate to fetch the latest version, version flag will be ignored in this case") + + cmdFlags.StringVar(&(DefaultConfig.Filter.FieldSelector), fmt.Sprintf("%v%v", prefix, "filter.field-selector"), *new(string), "Specifies the Field selector") + cmdFlags.StringVar((&DefaultConfig.Filter.SortBy), fmt.Sprintf("%v%v", prefix, "filter.sort-by"), *new(string), "Specifies which field to sort result by ") + cmdFlags.Int32Var((&DefaultConfig.Filter.Limit), fmt.Sprintf("%v%v", prefix, "filter.limit"), 100, "Specifies the limit") + cmdFlags.BoolVar((&DefaultConfig.Filter.Asc), fmt.Sprintf("%v%v", prefix, "filter.asc"), false, "Specifies the sorting order. By default flytectl sort result in descending order") + return cmdFlags +} diff --git a/flytectl/cmd/get/launchplanconfig_flags_test.go b/flytectl/cmd/config/subcommand/task/config_flags_test.go similarity index 55% rename from flytectl/cmd/get/launchplanconfig_flags_test.go rename to flytectl/cmd/config/subcommand/task/config_flags_test.go index 2b9271b278f..bea2ff142e0 100755 --- a/flytectl/cmd/get/launchplanconfig_flags_test.go +++ b/flytectl/cmd/config/subcommand/task/config_flags_test.go @@ -1,7 +1,7 @@ // Code generated by go generate; DO NOT EDIT. // This file was generated by robots. -package get +package task import ( "encoding/json" @@ -14,22 +14,22 @@ import ( "github.com/stretchr/testify/assert" ) -var dereferencableKindsLaunchPlanConfig = map[reflect.Kind]struct{}{ +var dereferencableKindsConfig = map[reflect.Kind]struct{}{ reflect.Array: {}, reflect.Chan: {}, reflect.Map: {}, reflect.Ptr: {}, reflect.Slice: {}, } // Checks if t is a kind that can be dereferenced to get its underlying type. -func canGetElementLaunchPlanConfig(t reflect.Kind) bool { - _, exists := dereferencableKindsLaunchPlanConfig[t] +func canGetElementConfig(t reflect.Kind) bool { + _, exists := dereferencableKindsConfig[t] return exists } // This decoder hook tests types for json unmarshaling capability. If implemented, it uses json unmarshal to build the // object. Otherwise, it'll just pass on the original data. -func jsonUnmarshalerHookLaunchPlanConfig(_, to reflect.Type, data interface{}) (interface{}, error) { +func jsonUnmarshalerHookConfig(_, to reflect.Type, data interface{}) (interface{}, error) { unmarshalerType := reflect.TypeOf((*json.Unmarshaler)(nil)).Elem() if to.Implements(unmarshalerType) || reflect.PtrTo(to).Implements(unmarshalerType) || - (canGetElementLaunchPlanConfig(to.Kind()) && to.Elem().Implements(unmarshalerType)) { + (canGetElementConfig(to.Kind()) && to.Elem().Implements(unmarshalerType)) { raw, err := json.Marshal(data) if err != nil { @@ -50,7 +50,7 @@ func jsonUnmarshalerHookLaunchPlanConfig(_, to reflect.Type, data interface{}) ( return data, nil } -func decode_LaunchPlanConfig(input, result interface{}) error { +func decode_Config(input, result interface{}) error { config := &mapstructure.DecoderConfig{ TagName: "json", WeaklyTypedInput: true, @@ -58,7 +58,7 @@ func decode_LaunchPlanConfig(input, result interface{}) error { DecodeHook: mapstructure.ComposeDecodeHookFunc( mapstructure.StringToTimeDurationHookFunc(), mapstructure.StringToSliceHookFunc(","), - jsonUnmarshalerHookLaunchPlanConfig, + jsonUnmarshalerHookConfig, ), } @@ -70,7 +70,7 @@ func decode_LaunchPlanConfig(input, result interface{}) error { return decoder.Decode(input) } -func join_LaunchPlanConfig(arr interface{}, sep string) string { +func join_Config(arr interface{}, sep string) string { listValue := reflect.ValueOf(arr) strs := make([]string, 0, listValue.Len()) for i := 0; i < listValue.Len(); i++ { @@ -80,85 +80,117 @@ func join_LaunchPlanConfig(arr interface{}, sep string) string { return strings.Join(strs, sep) } -func testDecodeJson_LaunchPlanConfig(t *testing.T, val, result interface{}) { - assert.NoError(t, decode_LaunchPlanConfig(val, result)) +func testDecodeJson_Config(t *testing.T, val, result interface{}) { + assert.NoError(t, decode_Config(val, result)) } -func testDecodeSlice_LaunchPlanConfig(t *testing.T, vStringSlice, result interface{}) { - assert.NoError(t, decode_LaunchPlanConfig(vStringSlice, result)) +func testDecodeRaw_Config(t *testing.T, vStringSlice, result interface{}) { + assert.NoError(t, decode_Config(vStringSlice, result)) } -func TestLaunchPlanConfig_GetPFlagSet(t *testing.T) { - val := LaunchPlanConfig{} +func TestConfig_GetPFlagSet(t *testing.T) { + val := Config{} cmdFlags := val.GetPFlagSet("") assert.True(t, cmdFlags.HasFlags()) } -func TestLaunchPlanConfig_SetFlags(t *testing.T) { - actual := LaunchPlanConfig{} +func TestConfig_SetFlags(t *testing.T) { + actual := Config{} cmdFlags := actual.GetPFlagSet("") assert.True(t, cmdFlags.HasFlags()) t.Run("Test_execFile", func(t *testing.T) { - t.Run("DefaultValue", func(t *testing.T) { - // Test that default value is set properly + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("execFile", testValue) if vString, err := cmdFlags.GetString("execFile"); err == nil { - assert.Equal(t, string(launchPlanConfig.ExecFile), vString) + testDecodeJson_Config(t, fmt.Sprintf("%v", vString), &actual.ExecFile) + } else { assert.FailNow(t, err.Error()) } }) + }) + t.Run("Test_version", func(t *testing.T) { t.Run("Override", func(t *testing.T) { testValue := "1" - cmdFlags.Set("execFile", testValue) - if vString, err := cmdFlags.GetString("execFile"); err == nil { - testDecodeJson_LaunchPlanConfig(t, fmt.Sprintf("%v", vString), &actual.ExecFile) + cmdFlags.Set("version", testValue) + if vString, err := cmdFlags.GetString("version"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vString), &actual.Version) } else { assert.FailNow(t, err.Error()) } }) }) - t.Run("Test_version", func(t *testing.T) { - t.Run("DefaultValue", func(t *testing.T) { - // Test that default value is set properly - if vString, err := cmdFlags.GetString("version"); err == nil { - assert.Equal(t, string(launchPlanConfig.Version), vString) + t.Run("Test_latest", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("latest", testValue) + if vBool, err := cmdFlags.GetBool("latest"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vBool), &actual.Latest) + } else { assert.FailNow(t, err.Error()) } }) + }) + t.Run("Test_filter.field-selector", func(t *testing.T) { t.Run("Override", func(t *testing.T) { testValue := "1" - cmdFlags.Set("version", testValue) - if vString, err := cmdFlags.GetString("version"); err == nil { - testDecodeJson_LaunchPlanConfig(t, fmt.Sprintf("%v", vString), &actual.Version) + cmdFlags.Set("filter.field-selector", testValue) + if vString, err := cmdFlags.GetString("filter.field-selector"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vString), &actual.Filter.FieldSelector) } else { assert.FailNow(t, err.Error()) } }) }) - t.Run("Test_latest", func(t *testing.T) { - t.Run("DefaultValue", func(t *testing.T) { - // Test that default value is set properly - if vBool, err := cmdFlags.GetBool("latest"); err == nil { - assert.Equal(t, bool(launchPlanConfig.Latest), vBool) + t.Run("Test_filter.sort-by", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("filter.sort-by", testValue) + if vString, err := cmdFlags.GetString("filter.sort-by"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vString), &actual.Filter.SortBy) + } else { assert.FailNow(t, err.Error()) } }) + }) + t.Run("Test_filter.limit", func(t *testing.T) { t.Run("Override", func(t *testing.T) { testValue := "1" - cmdFlags.Set("latest", testValue) - if vBool, err := cmdFlags.GetBool("latest"); err == nil { - testDecodeJson_LaunchPlanConfig(t, fmt.Sprintf("%v", vBool), &actual.Latest) + cmdFlags.Set("filter.limit", testValue) + if vInt32, err := cmdFlags.GetInt32("filter.limit"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vInt32), &actual.Filter.Limit) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_filter.asc", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("filter.asc", testValue) + if vBool, err := cmdFlags.GetBool("filter.asc"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vBool), &actual.Filter.Asc) } else { assert.FailNow(t, err.Error()) diff --git a/flytectl/cmd/config/subcommand/task/task_config.go b/flytectl/cmd/config/subcommand/task/task_config.go new file mode 100644 index 00000000000..241a1c1faba --- /dev/null +++ b/flytectl/cmd/config/subcommand/task/task_config.go @@ -0,0 +1,18 @@ +package task + +import "github.com/flyteorg/flytectl/pkg/filters" + +//go:generate pflags Config --default-var DefaultConfig +var ( + DefaultConfig = &Config{ + Filter: filters.DefaultFilter, + } +) + +// Config +type Config struct { + ExecFile string `json:"execFile" pflag:",execution file name to be used for generating execution spec of a single task."` + Version string `json:"version" pflag:",version of the task to be fetched."` + Latest bool `json:"latest" pflag:", flag to indicate to fetch the latest version, version flag will be ignored in this case"` + Filter filters.Filters `json:"filter" pflag:","` +} diff --git a/flytectl/cmd/config/subcommand/workflow/config_flags.go b/flytectl/cmd/config/subcommand/workflow/config_flags.go index 3db237e852c..61f6245c05f 100755 --- a/flytectl/cmd/config/subcommand/workflow/config_flags.go +++ b/flytectl/cmd/config/subcommand/workflow/config_flags.go @@ -28,6 +28,15 @@ func (Config) elemValueOrNil(v interface{}) interface{} { return v } +func (Config) mustJsonMarshal(v interface{}) string { + raw, err := json.Marshal(v) + if err != nil { + panic(err) + } + + return string(raw) +} + func (Config) mustMarshalJSON(v json.Marshaler) string { raw, err := v.MarshalJSON() if err != nil { @@ -41,7 +50,12 @@ func (Config) mustMarshalJSON(v json.Marshaler) string { // flags is json-name.json-sub-name... etc. func (cfg Config) GetPFlagSet(prefix string) *pflag.FlagSet { cmdFlags := pflag.NewFlagSet("Config", pflag.ExitOnError) - cmdFlags.StringVar(&(DefaultConfig.Version), fmt.Sprintf("%v%v", prefix, "version"), DefaultConfig.Version, "version of the workflow to be fetched.") - cmdFlags.BoolVar(&(DefaultConfig.Latest),fmt.Sprintf("%v%v", prefix, "latest"), DefaultConfig.Latest, " flag to indicate to fetch the latest version, version flag will be ignored in this case") + cmdFlags.StringVar(&(DefaultConfig.Version), fmt.Sprintf("%v%v", prefix, "version"), *new(string), "version of the workflow to be fetched.") + cmdFlags.BoolVar(&(DefaultConfig.Latest), fmt.Sprintf("%v%v", prefix, "latest"), *new(bool), " flag to indicate to fetch the latest version, version flag will be ignored in this case") + cmdFlags.StringVar(&(DefaultConfig.Filter.FieldSelector), fmt.Sprintf("%v%v", prefix, "filter.field-selector"), *new(string), "Specifies the Field selector") + cmdFlags.StringVar((&DefaultConfig.Filter.SortBy), fmt.Sprintf("%v%v", prefix, "filter.sort-by"), *new(string), "Specifies which field to sort result by ") + cmdFlags.Int32Var((&DefaultConfig.Filter.Limit), fmt.Sprintf("%v%v", prefix, "filter.limit"), 100, "Specifies the limit") + cmdFlags.BoolVar((&DefaultConfig.Filter.Asc), fmt.Sprintf("%v%v", prefix, "filter.asc"), false, "Specifies the sorting order. By default flytectl sort result in descending order") + return cmdFlags } diff --git a/flytectl/cmd/config/subcommand/workflow/config_flags_test.go b/flytectl/cmd/config/subcommand/workflow/config_flags_test.go index e3d3eae4120..86998d77885 100755 --- a/flytectl/cmd/config/subcommand/workflow/config_flags_test.go +++ b/flytectl/cmd/config/subcommand/workflow/config_flags_test.go @@ -84,7 +84,7 @@ func testDecodeJson_Config(t *testing.T, val, result interface{}) { assert.NoError(t, decode_Config(val, result)) } -func testDecodeSlice_Config(t *testing.T, vStringSlice, result interface{}) { +func testDecodeRaw_Config(t *testing.T, vStringSlice, result interface{}) { assert.NoError(t, decode_Config(vStringSlice, result)) } @@ -100,14 +100,6 @@ func TestConfig_SetFlags(t *testing.T) { assert.True(t, cmdFlags.HasFlags()) t.Run("Test_version", func(t *testing.T) { - t.Run("DefaultValue", func(t *testing.T) { - // Test that default value is set properly - if vString, err := cmdFlags.GetString("version"); err == nil { - assert.Equal(t, string(DefaultConfig.Version), vString) - } else { - assert.FailNow(t, err.Error()) - } - }) t.Run("Override", func(t *testing.T) { testValue := "1" @@ -122,21 +114,69 @@ func TestConfig_SetFlags(t *testing.T) { }) }) t.Run("Test_latest", func(t *testing.T) { - t.Run("DefaultValue", func(t *testing.T) { - // Test that default value is set properly + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("latest", testValue) if vBool, err := cmdFlags.GetBool("latest"); err == nil { - assert.Equal(t, bool(DefaultConfig.Latest), vBool) + testDecodeJson_Config(t, fmt.Sprintf("%v", vBool), &actual.Latest) + } else { assert.FailNow(t, err.Error()) } }) + }) + t.Run("Test_filter.field-selector", func(t *testing.T) { t.Run("Override", func(t *testing.T) { testValue := "1" - cmdFlags.Set("latest", testValue) - if vBool, err := cmdFlags.GetBool("latest"); err == nil { - testDecodeJson_Config(t, fmt.Sprintf("%v", vBool), &actual.Latest) + cmdFlags.Set("filter.field-selector", testValue) + if vString, err := cmdFlags.GetString("filter.field-selector"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vString), &actual.Filter.FieldSelector) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_filter.sort-by", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("filter.sort-by", testValue) + if vString, err := cmdFlags.GetString("filter.sort-by"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vString), &actual.Filter.SortBy) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_filter.limit", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("filter.limit", testValue) + if vInt32, err := cmdFlags.GetInt32("filter.limit"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vInt32), &actual.Filter.Limit) + + } else { + assert.FailNow(t, err.Error()) + } + }) + }) + t.Run("Test_filter.asc", func(t *testing.T) { + + t.Run("Override", func(t *testing.T) { + testValue := "1" + + cmdFlags.Set("filter.asc", testValue) + if vBool, err := cmdFlags.GetBool("filter.asc"); err == nil { + testDecodeJson_Config(t, fmt.Sprintf("%v", vBool), &actual.Filter.Asc) } else { assert.FailNow(t, err.Error()) diff --git a/flytectl/cmd/config/subcommand/workflow/workflow_config.go b/flytectl/cmd/config/subcommand/workflow/workflow_config.go index d4890f84c22..8051d4547f9 100644 --- a/flytectl/cmd/config/subcommand/workflow/workflow_config.go +++ b/flytectl/cmd/config/subcommand/workflow/workflow_config.go @@ -1,13 +1,18 @@ package workflow +import "github.com/flyteorg/flytectl/pkg/filters" + //go:generate pflags Config --default-var DefaultConfig var ( - DefaultConfig = &Config{} + DefaultConfig = &Config{ + Filter: filters.DefaultFilter, + } ) // Config commandline configuration type Config struct { - Version string `json:"version" pflag:",version of the workflow to be fetched."` - Latest bool `json:"latest" pflag:", flag to indicate to fetch the latest version, version flag will be ignored in this case"` + Version string `json:"version" pflag:",version of the workflow to be fetched."` + Latest bool `json:"latest" pflag:", flag to indicate to fetch the latest version, version flag will be ignored in this case"` + Filter filters.Filters `json:"filter" pflag:","` } diff --git a/flytectl/cmd/get/execution.go b/flytectl/cmd/get/execution.go index e77bea6f614..73c2e36b78e 100644 --- a/flytectl/cmd/get/execution.go +++ b/flytectl/cmd/get/execution.go @@ -3,7 +3,10 @@ package get import ( "context" + "github.com/flyteorg/flytectl/pkg/filters" + "github.com/flyteorg/flytectl/cmd/config" + "github.com/flyteorg/flytectl/cmd/config/subcommand/execution" cmdCore "github.com/flyteorg/flytectl/cmd/core" "github.com/flyteorg/flytectl/pkg/printer" "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/admin" @@ -25,10 +28,17 @@ Retrieves execution by name within project and domain. bin/flytectl get execution -p flytesnacks -d development oeh94k9r2r -Retrieves execution by filters +Retrieves all the executions with filters. :: + + bin/flytectl get execution -p flytesnacks -d development --filter.field-selector="execution.phase in (FAILED;SUCCEEDED),execution.duration<200" - Not yet implemented + +Retrieves all the execution with limit and sorting. +:: + + bin/flytectl get execution -p flytesnacks -d development --filter.sort-by=created_at --filter.limit=1 --filter.asc + Retrieves all the execution within project and domain in yaml format @@ -76,23 +86,17 @@ func getExecutionFunc(ctx context.Context, args []string, cmdCtx cmdCore.Command } executions = append(executions, execution) } else { - executionList, err := cmdCtx.AdminClient().ListExecutions(ctx, &admin.ResourceListRequest{ - Limit: 100, - Id: &admin.NamedEntityIdentifier{ - Project: config.GetConfig().Project, - Domain: config.GetConfig().Domain, - }, - }) + transformFilters, err := filters.BuildResourceListRequestWithName(execution.DefaultConfig.Filter, config.GetConfig().Project, config.GetConfig().Domain, "") + if err != nil { + return err + } + executionList, err := cmdCtx.AdminClient().ListExecutions(ctx, transformFilters) if err != nil { return err } executions = executionList.Executions } logger.Infof(ctx, "Retrieved %v executions", len(executions)) - err := adminPrinter.Print(config.GetConfig().MustOutputFormat(), executionColumns, + return adminPrinter.Print(config.GetConfig().MustOutputFormat(), executionColumns, ExecutionToProtoMessages(executions)...) - if err != nil { - return err - } - return nil } diff --git a/flytectl/cmd/get/get.go b/flytectl/cmd/get/get.go index b78bc4f67dc..6b3b0777944 100644 --- a/flytectl/cmd/get/get.go +++ b/flytectl/cmd/get/get.go @@ -2,9 +2,13 @@ package get import ( "github.com/flyteorg/flytectl/cmd/config/subcommand/clusterresourceattribute" + "github.com/flyteorg/flytectl/cmd/config/subcommand/execution" "github.com/flyteorg/flytectl/cmd/config/subcommand/executionclusterlabel" "github.com/flyteorg/flytectl/cmd/config/subcommand/executionqueueattribute" + "github.com/flyteorg/flytectl/cmd/config/subcommand/launchplan" pluginoverride "github.com/flyteorg/flytectl/cmd/config/subcommand/plugin_override" + "github.com/flyteorg/flytectl/cmd/config/subcommand/project" + "github.com/flyteorg/flytectl/cmd/config/subcommand/task" "github.com/flyteorg/flytectl/cmd/config/subcommand/taskresourceattribute" "github.com/flyteorg/flytectl/cmd/config/subcommand/workflow" cmdcore "github.com/flyteorg/flytectl/cmd/core" @@ -34,15 +38,15 @@ func CreateGetCommand() *cobra.Command { getResourcesFuncs := map[string]cmdcore.CommandEntry{ "project": {CmdFunc: getProjectsFunc, Aliases: []string{"projects"}, ProjectDomainNotRequired: true, Short: projectShort, - Long: projectLong}, + Long: projectLong, PFlagProvider: project.DefaultConfig}, "task": {CmdFunc: getTaskFunc, Aliases: []string{"tasks"}, Short: taskShort, - Long: taskLong, PFlagProvider: taskConfig}, + Long: taskLong, PFlagProvider: task.DefaultConfig}, "workflow": {CmdFunc: getWorkflowFunc, Aliases: []string{"workflows"}, Short: workflowShort, Long: workflowLong, PFlagProvider: workflow.DefaultConfig}, "launchplan": {CmdFunc: getLaunchPlanFunc, Aliases: []string{"launchplans"}, Short: launchPlanShort, - Long: launchPlanLong, PFlagProvider: launchPlanConfig}, + Long: launchPlanLong, PFlagProvider: launchplan.DefaultConfig}, "execution": {CmdFunc: getExecutionFunc, Aliases: []string{"executions"}, Short: executionShort, - Long: executionLong}, + Long: executionLong, PFlagProvider: execution.DefaultConfig}, "task-resource-attribute": {CmdFunc: getTaskResourceAttributes, Aliases: []string{"task-resource-attributes"}, Short: taskResourceAttributesShort, Long: taskResourceAttributesLong, PFlagProvider: taskresourceattribute.DefaultFetchConfig}, diff --git a/flytectl/cmd/get/launch_plan.go b/flytectl/cmd/get/launch_plan.go index 22ff6660fe3..994f0d84f25 100644 --- a/flytectl/cmd/get/launch_plan.go +++ b/flytectl/cmd/get/launch_plan.go @@ -3,14 +3,15 @@ package get import ( "context" + "github.com/flyteorg/flytectl/pkg/filters" + "github.com/flyteorg/flytectl/cmd/config" + "github.com/flyteorg/flytectl/cmd/config/subcommand/launchplan" cmdCore "github.com/flyteorg/flytectl/cmd/core" - "github.com/flyteorg/flytectl/pkg/adminutils" "github.com/flyteorg/flytectl/pkg/ext" "github.com/flyteorg/flytectl/pkg/printer" "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/admin" "github.com/flyteorg/flytestdlib/logger" - "github.com/golang/protobuf/proto" ) @@ -41,10 +42,22 @@ Retrieves particular version of launchplan by name within project and domain. flytectl get launchplan -p flytesnacks -d development core.basic.lp.go_greet --version v2 -Retrieves launchplan by filters. +Retrieves all the launch plans with filters. :: - - Not yet implemented + + bin/flytectl get launchplan -p flytesnacks -d development --filter.field-selector="name=core.basic.lp.go_greet" + +Retrieves launch plans entity search across all versions with filters. +:: + + bin/flytectl get launchplan -p flytesnacks -d development k8s_spark.dataframe_passing.my_smart_schema --filter.field-selector="version=v1" + + +Retrieves all the launch plans with limit and sorting. +:: + + bin/flytectl get launchplan -p flytesnacks -d development --filter.sort-by=created_at --filter.limit=1 --filter.asc + Retrieves all the launchplan within project and domain in yaml format. @@ -86,18 +99,7 @@ Usage ` ) -//go:generate pflags LaunchPlanConfig --default-var launchPlanConfig -var ( - launchPlanConfig = &LaunchPlanConfig{} -) - -// LaunchPlanConfig -type LaunchPlanConfig struct { - ExecFile string `json:"execFile" pflag:",execution file name to be used for generating execution spec of a single launchplan."` - Version string `json:"version" pflag:",version of the launchplan to be fetched."` - Latest bool `json:"latest" pflag:", flag to indicate to fetch the latest version, version flag will be ignored in this case"` -} - +// Column structure for get specific launchplan var launchplanColumns = []printer.Column{ {Header: "Version", JSONPath: "$.id.version"}, {Header: "Name", JSONPath: "$.id.name"}, @@ -106,6 +108,14 @@ var launchplanColumns = []printer.Column{ {Header: "Schedule", JSONPath: "$.spec.entityMetadata.schedule"}, } +// Column structure for get all launchplans +var launchplansColumns = []printer.Column{ + {Header: "Version", JSONPath: "$.id.version"}, + {Header: "Name", JSONPath: "$.id.name"}, + {Header: "Type", JSONPath: "$.id.resourceType"}, + {Header: "CreatedAt", JSONPath: "$.closure.createdAt"}, +} + func LaunchplanToProtoMessages(l []*admin.LaunchPlan) []proto.Message { messages := make([]proto.Message, 0, len(l)) for _, m := range l { @@ -133,15 +143,21 @@ func getLaunchPlanFunc(ctx context.Context, args []string, cmdCtx cmdCore.Comman } return nil } - - launchPlans, err := adminutils.GetAllNamedEntities(ctx, cmdCtx.AdminClient().ListLaunchPlanIds, - adminutils.ListRequest{Project: project, Domain: domain}) + transformFilters, err := filters.BuildResourceListRequestWithName(launchplan.DefaultConfig.Filter, config.GetConfig().Project, config.GetConfig().Domain, "") + if err != nil { + return err + } + launchPlanList, err := cmdCtx.AdminClient().ListLaunchPlans(ctx, transformFilters) + if err != nil { + return err + } + launchPlans := launchPlanList.LaunchPlans if err != nil { return err } logger.Debugf(ctx, "Retrieved %v launch plans", len(launchPlans)) - return launchPlanPrinter.Print(config.GetConfig().MustOutputFormat(), entityColumns, - adminutils.NamedEntityToProtoMessage(launchPlans)...) + return launchPlanPrinter.Print(config.GetConfig().MustOutputFormat(), launchplansColumns, + LaunchplanToProtoMessages(launchPlans)...) } // FetchLPForName fetches the launchplan give it name. @@ -150,28 +166,28 @@ func FetchLPForName(ctx context.Context, fetcher ext.AdminFetcherExtInterface, n var launchPlans []*admin.LaunchPlan var lp *admin.LaunchPlan var err error - if launchPlanConfig.Latest { - if lp, err = fetcher.FetchLPLatestVersion(ctx, name, project, domain); err != nil { + if launchplan.DefaultConfig.Latest { + if lp, err = fetcher.FetchLPLatestVersion(ctx, name, project, domain, launchplan.DefaultConfig.Filter); err != nil { return nil, err } launchPlans = append(launchPlans, lp) - } else if launchPlanConfig.Version != "" { - if lp, err = fetcher.FetchLPVersion(ctx, name, launchPlanConfig.Version, project, domain); err != nil { + } else if launchplan.DefaultConfig.Version != "" { + if lp, err = fetcher.FetchLPVersion(ctx, name, launchplan.DefaultConfig.Version, project, domain); err != nil { return nil, err } launchPlans = append(launchPlans, lp) } else { - launchPlans, err = fetcher.FetchAllVerOfLP(ctx, name, project, domain) + launchPlans, err = fetcher.FetchAllVerOfLP(ctx, name, project, domain, launchplan.DefaultConfig.Filter) if err != nil { return nil, err } } - if launchPlanConfig.ExecFile != "" { + if launchplan.DefaultConfig.ExecFile != "" { // There would be atleast one launchplan object when code reaches here and hence the length // assertion is not required. lp = launchPlans[0] // Only write the first task from the tasks object. - if err = CreateAndWriteExecConfigForWorkflow(lp, launchPlanConfig.ExecFile); err != nil { + if err = CreateAndWriteExecConfigForWorkflow(lp, launchplan.DefaultConfig.ExecFile); err != nil { return nil, err } } diff --git a/flytectl/cmd/get/launch_plan_test.go b/flytectl/cmd/get/launch_plan_test.go index 5933746acb4..9757a35c1d5 100644 --- a/flytectl/cmd/get/launch_plan_test.go +++ b/flytectl/cmd/get/launch_plan_test.go @@ -5,6 +5,9 @@ import ( "os" "testing" + "github.com/flyteorg/flytectl/pkg/filters" + + "github.com/flyteorg/flytectl/cmd/config/subcommand/launchplan" cmdCore "github.com/flyteorg/flytectl/cmd/core" u "github.com/flyteorg/flytectl/cmd/testutils" "github.com/flyteorg/flytectl/pkg/ext/mocks" @@ -18,6 +21,7 @@ import ( var ( resourceListRequest *admin.ResourceListRequest + resourceGetRequest *admin.ResourceListRequest objectGetRequest *admin.ObjectGetRequest namedIDRequest *admin.NamedEntityIdentifierListRequest launchPlanListResponse *admin.LaunchPlanList @@ -121,13 +125,15 @@ func getLaunchPlanSetup() { Id: &admin.NamedEntityIdentifier{ Project: projectValue, Domain: domainValue, - Name: argsLp[0], }, - SortBy: &admin.Sort{ - Key: "created_at", - Direction: admin.Sort_DESCENDING, + } + + resourceGetRequest = &admin.ResourceListRequest{ + Id: &admin.NamedEntityIdentifier{ + Project: projectValue, + Domain: domainValue, + Name: argsLp[0], }, - Limit: 100, } launchPlanListResponse = &admin.LaunchPlanList{ @@ -147,11 +153,6 @@ func getLaunchPlanSetup() { namedIDRequest = &admin.NamedEntityIdentifierListRequest{ Project: projectValue, Domain: domainValue, - SortBy: &admin.Sort{ - Key: "name", - Direction: admin.Sort_ASCENDING, - }, - Limit: 100, } var entities []*admin.NamedEntityIdentifier @@ -170,9 +171,10 @@ func getLaunchPlanSetup() { Entities: entities, } - launchPlanConfig.Latest = false - launchPlanConfig.Version = "" - launchPlanConfig.ExecFile = "" + launchplan.DefaultConfig.Latest = false + launchplan.DefaultConfig.Version = "" + launchplan.DefaultConfig.ExecFile = "" + launchplan.DefaultConfig.Filter = filters.Filters{} } func TestGetLaunchPlanFuncWithError(t *testing.T) { @@ -180,9 +182,10 @@ func TestGetLaunchPlanFuncWithError(t *testing.T) { setup() getLaunchPlanSetup() mockFetcher := new(mocks.AdminFetcherExtInterface) - launchPlanConfig.Latest = true + launchplan.DefaultConfig.Latest = true + launchplan.DefaultConfig.Filter = filters.Filters{} mockFetcher.OnFetchLPLatestVersionMatch(mock.Anything, mock.Anything, mock.Anything, - mock.Anything).Return(nil, fmt.Errorf("error fetching latest version")) + mock.Anything, mock.Anything).Return(nil, fmt.Errorf("error fetching latest version")) _, err = FetchLPForName(ctx, mockFetcher, "lpName", projectValue, domainValue) assert.NotNil(t, err) }) @@ -191,7 +194,8 @@ func TestGetLaunchPlanFuncWithError(t *testing.T) { setup() getLaunchPlanSetup() mockFetcher := new(mocks.AdminFetcherExtInterface) - launchPlanConfig.Version = "v1" + launchplan.DefaultConfig.Version = "v1" + launchplan.DefaultConfig.Filter = filters.Filters{} mockFetcher.OnFetchLPVersionMatch(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("error fetching version")) _, err = FetchLPForName(ctx, mockFetcher, "lpName", projectValue, domainValue) @@ -201,9 +205,11 @@ func TestGetLaunchPlanFuncWithError(t *testing.T) { t.Run("failure fetching all version ", func(t *testing.T) { setup() getLaunchPlanSetup() + launchplan.DefaultConfig.Filter = filters.Filters{} + launchplan.DefaultConfig.Filter = filters.Filters{} mockFetcher := new(mocks.AdminFetcherExtInterface) mockFetcher.OnFetchAllVerOfLPMatch(mock.Anything, mock.Anything, mock.Anything, - mock.Anything).Return(nil, fmt.Errorf("error fetching all version")) + mock.Anything, mock.Anything).Return(nil, fmt.Errorf("error fetching all version")) _, err = FetchLPForName(ctx, mockFetcher, "lpName", projectValue, domainValue) assert.NotNil(t, err) }) @@ -211,23 +217,32 @@ func TestGetLaunchPlanFuncWithError(t *testing.T) { t.Run("failure fetching ", func(t *testing.T) { setup() getLaunchPlanSetup() - mockClient.OnListLaunchPlansMatch(ctx, resourceListRequest).Return(nil, fmt.Errorf("error fetching all version")) + mockClient.OnListLaunchPlansMatch(ctx, resourceGetRequest).Return(nil, fmt.Errorf("error fetching all version")) mockClient.OnGetLaunchPlanMatch(ctx, objectGetRequest).Return(nil, fmt.Errorf("error fetching lanuch plan")) mockClient.OnListLaunchPlanIdsMatch(ctx, namedIDRequest).Return(nil, fmt.Errorf("error listing lanuch plan ids")) err = getLaunchPlanFunc(ctx, argsLp, cmdCtx) assert.NotNil(t, err) }) + + t.Run("failure fetching list", func(t *testing.T) { + setup() + getLaunchPlanSetup() + argsLp = []string{} + mockClient.OnListLaunchPlansMatch(ctx, resourceListRequest).Return(nil, fmt.Errorf("error fetching all version")) + err = getLaunchPlanFunc(ctx, argsLp, cmdCtx) + assert.NotNil(t, err) + }) } func TestGetLaunchPlanFunc(t *testing.T) { setup() getLaunchPlanSetup() - mockClient.OnListLaunchPlansMatch(ctx, resourceListRequest).Return(launchPlanListResponse, nil) + mockClient.OnListLaunchPlansMatch(ctx, resourceGetRequest).Return(launchPlanListResponse, nil) mockClient.OnGetLaunchPlanMatch(ctx, objectGetRequest).Return(launchPlan2, nil) mockClient.OnListLaunchPlanIdsMatch(ctx, namedIDRequest).Return(namedIdentifierList, nil) err = getLaunchPlanFunc(ctx, argsLp, cmdCtx) assert.Nil(t, err) - mockClient.AssertCalled(t, "ListLaunchPlans", ctx, resourceListRequest) + mockClient.AssertCalled(t, "ListLaunchPlans", ctx, resourceGetRequest) tearDownAndVerify(t, `[ { "id": { @@ -393,13 +408,13 @@ func TestGetLaunchPlanFunc(t *testing.T) { func TestGetLaunchPlanFuncLatest(t *testing.T) { setup() getLaunchPlanSetup() - launchPlanConfig.Latest = true - mockClient.OnListLaunchPlansMatch(ctx, resourceListRequest).Return(launchPlanListResponse, nil) + launchplan.DefaultConfig.Latest = true + launchplan.DefaultConfig.Filter = filters.Filters{} + mockClient.OnListLaunchPlansMatch(ctx, resourceGetRequest).Return(launchPlanListResponse, nil) mockClient.OnGetLaunchPlanMatch(ctx, objectGetRequest).Return(launchPlan2, nil) - mockClient.OnListLaunchPlanIdsMatch(ctx, namedIDRequest).Return(namedIdentifierList, nil) err = getLaunchPlanFunc(ctx, argsLp, cmdCtx) assert.Nil(t, err) - mockClient.AssertCalled(t, "ListLaunchPlans", ctx, resourceListRequest) + mockClient.AssertCalled(t, "ListLaunchPlans", ctx, resourceGetRequest) tearDownAndVerify(t, `{ "id": { "name": "launchplan1", @@ -484,7 +499,7 @@ func TestGetLaunchPlanFuncLatest(t *testing.T) { func TestGetLaunchPlanWithVersion(t *testing.T) { setup() getLaunchPlanSetup() - launchPlanConfig.Version = "v2" + launchplan.DefaultConfig.Version = "v2" mockClient.OnListLaunchPlansMatch(ctx, resourceListRequest).Return(launchPlanListResponse, nil) mockClient.OnGetLaunchPlanMatch(ctx, objectGetRequest).Return(launchPlan2, nil) mockClient.OnListLaunchPlanIdsMatch(ctx, namedIDRequest).Return(namedIdentifierList, nil) @@ -577,23 +592,10 @@ func TestGetLaunchPlans(t *testing.T) { getLaunchPlanSetup() mockClient.OnListLaunchPlansMatch(ctx, resourceListRequest).Return(launchPlanListResponse, nil) mockClient.OnGetLaunchPlanMatch(ctx, objectGetRequest).Return(launchPlan2, nil) - mockClient.OnListLaunchPlanIdsMatch(ctx, namedIDRequest).Return(namedIdentifierList, nil) argsLp = []string{} err = getLaunchPlanFunc(ctx, argsLp, cmdCtx) assert.Nil(t, err) - mockClient.AssertCalled(t, "ListLaunchPlanIds", ctx, namedIDRequest) - tearDownAndVerify(t, `[ - { - "project": "dummyProject", - "domain": "dummyDomain", - "name": "launchplan1" - }, - { - "project": "dummyProject", - "domain": "dummyDomain", - "name": "launchplan2" - } -]`) + tearDownAndVerify(t, `[{"id": {"name": "launchplan1","version": "v2"},"spec": {"defaultInputs": {"parameters": {"numbers": {"var": {"type": {"collectionType": {"simple": "INTEGER"}}}},"numbers_count": {"var": {"type": {"simple": "INTEGER"}}},"run_local_at_count": {"var": {"type": {"simple": "INTEGER"}},"default": {"scalar": {"primitive": {"integer": "10"}}}}}}},"closure": {"expectedInputs": {"parameters": {"numbers": {"var": {"type": {"collectionType": {"simple": "INTEGER"}}}},"numbers_count": {"var": {"type": {"simple": "INTEGER"}}},"run_local_at_count": {"var": {"type": {"simple": "INTEGER"}},"default": {"scalar": {"primitive": {"integer": "10"}}}}}},"createdAt": "1970-01-01T00:00:01Z"}},{"id": {"name": "launchplan1","version": "v1"},"spec": {"defaultInputs": {"parameters": {"numbers": {"var": {"type": {"collectionType": {"simple": "INTEGER"}}}},"numbers_count": {"var": {"type": {"simple": "INTEGER"}}},"run_local_at_count": {"var": {"type": {"simple": "INTEGER"}},"default": {"scalar": {"primitive": {"integer": "10"}}}}}}},"closure": {"expectedInputs": {"parameters": {"numbers": {"var": {"type": {"collectionType": {"simple": "INTEGER"}}}},"numbers_count": {"var": {"type": {"simple": "INTEGER"}}},"run_local_at_count": {"var": {"type": {"simple": "INTEGER"}},"default": {"scalar": {"primitive": {"integer": "10"}}}}}},"createdAt": "1970-01-01T00:00:00Z"}}]`) } func TestGetLaunchPlansWithExecFile(t *testing.T) { @@ -602,10 +604,10 @@ func TestGetLaunchPlansWithExecFile(t *testing.T) { mockClient.OnListLaunchPlansMatch(ctx, resourceListRequest).Return(launchPlanListResponse, nil) mockClient.OnGetLaunchPlanMatch(ctx, objectGetRequest).Return(launchPlan2, nil) mockClient.OnListLaunchPlanIdsMatch(ctx, namedIDRequest).Return(namedIdentifierList, nil) - launchPlanConfig.Version = "v2" - launchPlanConfig.ExecFile = testDataFolder + "exec_file" + launchplan.DefaultConfig.Version = "v2" + launchplan.DefaultConfig.ExecFile = testDataFolder + "exec_file" err = getLaunchPlanFunc(ctx, argsLp, cmdCtx) - os.Remove(launchPlanConfig.ExecFile) + os.Remove(launchplan.DefaultConfig.ExecFile) assert.Nil(t, err) mockClient.AssertCalled(t, "GetLaunchPlan", ctx, objectGetRequest) tearDownAndVerify(t, `{ diff --git a/flytectl/cmd/get/launchplanconfig_flags.go b/flytectl/cmd/get/launchplanconfig_flags.go deleted file mode 100755 index f4e37ea0c4c..00000000000 --- a/flytectl/cmd/get/launchplanconfig_flags.go +++ /dev/null @@ -1,48 +0,0 @@ -// Code generated by go generate; DO NOT EDIT. -// This file was generated by robots. - -package get - -import ( - "encoding/json" - "reflect" - - "fmt" - - "github.com/spf13/pflag" -) - -// If v is a pointer, it will get its element value or the zero value of the element type. -// If v is not a pointer, it will return it as is. -func (LaunchPlanConfig) elemValueOrNil(v interface{}) interface{} { - if t := reflect.TypeOf(v); t.Kind() == reflect.Ptr { - if reflect.ValueOf(v).IsNil() { - return reflect.Zero(t.Elem()).Interface() - } else { - return reflect.ValueOf(v).Interface() - } - } else if v == nil { - return reflect.Zero(t).Interface() - } - - return v -} - -func (LaunchPlanConfig) mustMarshalJSON(v json.Marshaler) string { - raw, err := v.MarshalJSON() - if err != nil { - panic(err) - } - - return string(raw) -} - -// GetPFlagSet will return strongly types pflags for all fields in LaunchPlanConfig and its nested types. The format of the -// flags is json-name.json-sub-name... etc. -func (cfg LaunchPlanConfig) GetPFlagSet(prefix string) *pflag.FlagSet { - cmdFlags := pflag.NewFlagSet("LaunchPlanConfig", pflag.ExitOnError) - cmdFlags.StringVar(&(launchPlanConfig.ExecFile), fmt.Sprintf("%v%v", prefix, "execFile"), launchPlanConfig.ExecFile, "execution file name to be used for generating execution spec of a single launchplan.") - cmdFlags.StringVar(&(launchPlanConfig.Version), fmt.Sprintf("%v%v", prefix, "version"), launchPlanConfig.Version, "version of the launchplan to be fetched.") - cmdFlags.BoolVar(&(launchPlanConfig.Latest), fmt.Sprintf("%v%v", prefix, "latest"), launchPlanConfig.Latest, "flag to indicate to fetch the latest version, version flag will be ignored in this case") - return cmdFlags -} diff --git a/flytectl/cmd/get/named_entity.go b/flytectl/cmd/get/named_entity.go deleted file mode 100644 index 617542f5ec0..00000000000 --- a/flytectl/cmd/get/named_entity.go +++ /dev/null @@ -1,11 +0,0 @@ -package get - -import ( - "github.com/flyteorg/flytectl/pkg/printer" -) - -var entityColumns = []printer.Column{ - {Header: "Domain", JSONPath: "$.domain"}, - {Header: "Name", JSONPath: "$.name"}, - {Header: "Project", JSONPath: "$.project"}, -} diff --git a/flytectl/cmd/get/project.go b/flytectl/cmd/get/project.go index 0fa2f704504..535cb16af48 100644 --- a/flytectl/cmd/get/project.go +++ b/flytectl/cmd/get/project.go @@ -3,6 +3,10 @@ package get import ( "context" + "github.com/flyteorg/flytectl/cmd/config/subcommand/project" + + "github.com/flyteorg/flytectl/pkg/filters" + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/admin" "github.com/flyteorg/flytestdlib/logger" "github.com/golang/protobuf/proto" @@ -26,10 +30,15 @@ Retrieves project by name bin/flytectl get project flytesnacks -Retrieves project by filters +Retrieves all the projects with filters. :: - - Not yet implemented + + bin/flytectl get project --filter.field-selector="project.name=flytesnacks" + +Retrieves all the projects with limit and sorting. +:: + + bin/flytectl get project --filter.sort-by=created_at --filter.limit=1 --filter.asc Retrieves all the projects in yaml format @@ -63,7 +72,11 @@ func ProjectToProtoMessages(l []*admin.Project) []proto.Message { func getProjectsFunc(ctx context.Context, args []string, cmdCtx cmdCore.CommandContext) error { adminPrinter := printer.Printer{} - projects, err := cmdCtx.AdminClient().ListProjects(ctx, &admin.ProjectListRequest{}) + transformFilters, err := filters.BuildProjectListRequest(project.DefaultConfig.Filter) + if err != nil { + return err + } + projects, err := cmdCtx.AdminClient().ListProjects(ctx, transformFilters) if err != nil { return err } diff --git a/flytectl/cmd/get/project_test.go b/flytectl/cmd/get/project_test.go new file mode 100644 index 00000000000..2419ceda6c6 --- /dev/null +++ b/flytectl/cmd/get/project_test.go @@ -0,0 +1,83 @@ +package get + +import ( + "fmt" + "testing" + + "github.com/flyteorg/flytectl/cmd/config/subcommand/project" + + "github.com/flyteorg/flytectl/pkg/filters" + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/admin" + "github.com/stretchr/testify/assert" +) + +var ( + resourceListRequestProject *admin.ProjectListRequest + projectListResponse *admin.Projects + argsProject []string + project1 *admin.Project +) + +func getProjectSetup() { + argsProject = []string{"flyteexample"} + resourceListRequestProject = &admin.ProjectListRequest{} + + project1 = &admin.Project{ + Id: "flyteexample", + Name: "flyteexample", + Domains: []*admin.Domain{ + { + Id: "development", + Name: "development", + }, + }, + } + + project2 := &admin.Project{ + Id: "flytesnacks", + Name: "flytesnacks", + Domains: []*admin.Domain{ + { + Id: "development", + Name: "development", + }, + }, + } + + projects := []*admin.Project{project1, project2} + + projectListResponse = &admin.Projects{ + Projects: projects, + } +} + +func TestProjectFunc(t *testing.T) { + setup() + getProjectSetup() + project.DefaultConfig.Filter = filters.Filters{} + mockClient.OnListProjectsMatch(ctx, resourceListRequestProject).Return(projectListResponse, nil) + err = getProjectsFunc(ctx, argsProject, cmdCtx) + assert.Nil(t, err) + mockClient.AssertCalled(t, "ListProjects", ctx, resourceListRequestProject) +} + +func TestGetProjectFunc(t *testing.T) { + setup() + getProjectSetup() + project.DefaultConfig.Filter = filters.Filters{} + mockClient.OnListProjectsMatch(ctx, resourceListRequestProject).Return(projectListResponse, nil) + err = getProjectsFunc(ctx, argsProject, cmdCtx) + assert.Nil(t, err) + mockClient.AssertCalled(t, "ListProjects", ctx, resourceListRequestProject) +} + +func TestGetProjectFuncError(t *testing.T) { + setup() + getProjectSetup() + project.DefaultConfig.Filter = filters.Filters{ + FieldSelector: "hello=", + } + mockClient.OnListProjectsMatch(ctx, resourceListRequestProject).Return(nil, fmt.Errorf("Please add a valid field selector")) + err = getProjectsFunc(ctx, argsProject, cmdCtx) + assert.NotNil(t, err) +} diff --git a/flytectl/cmd/get/task.go b/flytectl/cmd/get/task.go index eb40e9cb23c..fd02d17b405 100644 --- a/flytectl/cmd/get/task.go +++ b/flytectl/cmd/get/task.go @@ -4,9 +4,10 @@ import ( "context" "github.com/flyteorg/flytectl/cmd/config" + taskConfig "github.com/flyteorg/flytectl/cmd/config/subcommand/task" cmdCore "github.com/flyteorg/flytectl/cmd/core" - "github.com/flyteorg/flytectl/pkg/adminutils" "github.com/flyteorg/flytectl/pkg/ext" + "github.com/flyteorg/flytectl/pkg/filters" "github.com/flyteorg/flytectl/pkg/printer" "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/admin" "github.com/flyteorg/flytestdlib/logger" @@ -38,15 +39,24 @@ Retrieves particular version of task by name within project and domain. :: - flytectl get workflow -p flytesnacks -d development core.basic.lp.greet --version v2 + flytectl get task -p flytesnacks -d development core.basic.lp.greet --version v2 -Retrieves project by filters. +Retrieves all the tasks with filters. :: - - Not yet implemented + + bin/flytectl get task -p flytesnacks -d development --filter.field-selector="task.name=k8s_spark.pyspark_pi.print_every_time,task.version=v1" + +Retrieve a specific task with filters. +:: + + bin/flytectl get task -p flytesnacks -d development k8s_spark.pyspark_pi.print_every_time --filter.field-selector="task.version=v1,created_at>=2021-05-24T21:43:12.325335Z" + +Retrieves all the task with limit and sorting. +:: + + bin/flytectl get -p flytesnacks -d development task --filter.sort-by=created_at --filter.limit=1 --filter.asc Retrieves all the tasks within project and domain in yaml format. - :: bin/flytectl get task -p flytesnacks -d development -o yaml @@ -85,18 +95,6 @@ Usage ` ) -//go:generate pflags TaskConfig --default-var taskConfig -var ( - taskConfig = &TaskConfig{} -) - -// FilesConfig -type TaskConfig struct { - ExecFile string `json:"execFile" pflag:",execution file name to be used for generating execution spec of a single task."` - Version string `json:"version" pflag:",version of the task to be fetched."` - Latest bool `json:"latest" pflag:", flag to indicate to fetch the latest version, version flag will be ignored in this case"` -} - var taskColumns = []printer.Column{ {Header: "Version", JSONPath: "$.id.version"}, {Header: "Name", JSONPath: "$.id.name"}, @@ -128,12 +126,18 @@ func getTaskFunc(ctx context.Context, args []string, cmdCtx cmdCore.CommandConte logger.Debugf(ctx, "Retrieved Task", tasks) return taskPrinter.Print(config.GetConfig().MustOutputFormat(), taskColumns, TaskToProtoMessages(tasks)...) } - tasks, err := adminutils.GetAllNamedEntities(ctx, cmdCtx.AdminClient().ListTaskIds, adminutils.ListRequest{Project: project, Domain: domain}) + transformFilters, err := filters.BuildResourceListRequestWithName(taskConfig.DefaultConfig.Filter, config.GetConfig().Project, config.GetConfig().Domain, "") + if err != nil { + return err + } + taskList, err := cmdCtx.AdminClient().ListTasks(ctx, transformFilters) if err != nil { return err } + tasks := taskList.Tasks + logger.Debugf(ctx, "Retrieved %v Task", len(tasks)) - return taskPrinter.Print(config.GetConfig().MustOutputFormat(), entityColumns, adminutils.NamedEntityToProtoMessage(tasks)...) + return taskPrinter.Print(config.GetConfig().MustOutputFormat(), taskColumns, TaskToProtoMessages(tasks)...) } // FetchTaskForName Reads the task config to drive fetching the correct tasks. @@ -141,27 +145,27 @@ func FetchTaskForName(ctx context.Context, fetcher ext.AdminFetcherExtInterface, var tasks []*admin.Task var err error var task *admin.Task - if taskConfig.Latest { - if task, err = fetcher.FetchTaskLatestVersion(ctx, name, project, domain); err != nil { + if taskConfig.DefaultConfig.Latest { + if task, err = fetcher.FetchTaskLatestVersion(ctx, name, project, domain, taskConfig.DefaultConfig.Filter); err != nil { return nil, err } tasks = append(tasks, task) - } else if taskConfig.Version != "" { - if task, err = fetcher.FetchTaskVersion(ctx, name, taskConfig.Version, project, domain); err != nil { + } else if taskConfig.DefaultConfig.Version != "" { + if task, err = fetcher.FetchTaskVersion(ctx, name, taskConfig.DefaultConfig.Version, project, domain); err != nil { return nil, err } tasks = append(tasks, task) } else { - tasks, err = fetcher.FetchAllVerOfTask(ctx, name, project, domain) + tasks, err = fetcher.FetchAllVerOfTask(ctx, name, project, domain, taskConfig.DefaultConfig.Filter) if err != nil { return nil, err } } - if taskConfig.ExecFile != "" { + if taskConfig.DefaultConfig.ExecFile != "" { // There would be atleast one task object when code reaches here and hence the length assertion is not required. task = tasks[0] // Only write the first task from the tasks object. - if err = CreateAndWriteExecConfigForTask(task, taskConfig.ExecFile); err != nil { + if err = CreateAndWriteExecConfigForTask(task, taskConfig.DefaultConfig.ExecFile); err != nil { return nil, err } } diff --git a/flytectl/cmd/get/task_test.go b/flytectl/cmd/get/task_test.go index 71648405182..b72545487d4 100644 --- a/flytectl/cmd/get/task_test.go +++ b/flytectl/cmd/get/task_test.go @@ -5,6 +5,10 @@ import ( "os" "testing" + taskConfig "github.com/flyteorg/flytectl/cmd/config/subcommand/task" + + "github.com/flyteorg/flytectl/pkg/filters" + cmdCore "github.com/flyteorg/flytectl/cmd/core" u "github.com/flyteorg/flytectl/cmd/testutils" "github.com/flyteorg/flytectl/pkg/ext/mocks" @@ -17,13 +21,17 @@ import ( ) var ( - resourceListRequestTask *admin.ResourceListRequest - objectGetRequestTask *admin.ObjectGetRequest - namedIDRequestTask *admin.NamedEntityIdentifierListRequest - taskListResponse *admin.TaskList - argsTask []string - namedIdentifierListTask *admin.NamedEntityIdentifierList - task2 *admin.Task + resourceListRequestTask *admin.ResourceListRequest + resourceListFilterRequestTask *admin.ResourceListRequest + resourceListTaskRequest *admin.ResourceListRequest + resourceListLimitRequestTask *admin.ResourceListRequest + objectGetRequestTask *admin.ObjectGetRequest + namedIDRequestTask *admin.NamedEntityIdentifierListRequest + taskListResponse *admin.TaskList + taskListFilterResponse *admin.TaskList + argsTask []string + namedIdentifierListTask *admin.NamedEntityIdentifierList + task2 *admin.Task ) func getTaskSetup() { @@ -87,23 +95,44 @@ func getTaskSetup() { } tasks := []*admin.Task{task2, task1} + resourceListLimitRequestTask = &admin.ResourceListRequest{ + Id: &admin.NamedEntityIdentifier{ + Project: projectValue, + Domain: domainValue, + Name: argsTask[0], + }, + Limit: 100, + } resourceListRequestTask = &admin.ResourceListRequest{ Id: &admin.NamedEntityIdentifier{ Project: projectValue, Domain: domainValue, Name: argsTask[0], }, - SortBy: &admin.Sort{ - Key: "created_at", - Direction: admin.Sort_DESCENDING, + } + + resourceListTaskRequest = &admin.ResourceListRequest{ + Id: &admin.NamedEntityIdentifier{ + Project: projectValue, + Domain: domainValue, }, - Limit: 100, + } + + resourceListFilterRequestTask = &admin.ResourceListRequest{ + Id: &admin.NamedEntityIdentifier{ + Project: projectValue, + Domain: domainValue, + Name: argsTask[0], + }, + Filters: "eq(task.name,task1)+eq(task.version,v1)", } taskListResponse = &admin.TaskList{ Tasks: tasks, } - + taskListFilterResponse = &admin.TaskList{ + Tasks: []*admin.Task{task1}, + } objectGetRequestTask = &admin.ObjectGetRequest{ Id: &core.Identifier{ ResourceType: core.ResourceType_TASK, @@ -139,9 +168,9 @@ func getTaskSetup() { Entities: taskEntities, } - taskConfig.Latest = false - taskConfig.ExecFile = "" - taskConfig.Version = "" + taskConfig.DefaultConfig.Latest = false + taskConfig.DefaultConfig.ExecFile = "" + taskConfig.DefaultConfig.Version = "" } func TestGetTaskFuncWithError(t *testing.T) { @@ -149,9 +178,10 @@ func TestGetTaskFuncWithError(t *testing.T) { setup() getTaskSetup() mockFetcher := new(mocks.AdminFetcherExtInterface) - taskConfig.Latest = true + taskConfig.DefaultConfig.Latest = true + taskConfig.DefaultConfig.Filter = filters.Filters{} mockFetcher.OnFetchTaskLatestVersionMatch(mock.Anything, mock.Anything, mock.Anything, - mock.Anything).Return(nil, fmt.Errorf("error fetching latest version")) + mock.Anything, mock.Anything).Return(nil, fmt.Errorf("error fetching latest version")) _, err = FetchTaskForName(ctx, mockFetcher, "lpName", projectValue, domainValue) assert.NotNil(t, err) }) @@ -160,9 +190,10 @@ func TestGetTaskFuncWithError(t *testing.T) { setup() getTaskSetup() mockFetcher := new(mocks.AdminFetcherExtInterface) - taskConfig.Version = "v1" + taskConfig.DefaultConfig.Version = "v1" + taskConfig.DefaultConfig.Filter = filters.Filters{} mockFetcher.OnFetchTaskVersionMatch(mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything).Return(nil, fmt.Errorf("error fetching version")) + mock.Anything, mock.Anything).Return(nil, fmt.Errorf("error fetching version")) _, err = FetchTaskForName(ctx, mockFetcher, "lpName", projectValue, domainValue) assert.NotNil(t, err) }) @@ -171,8 +202,9 @@ func TestGetTaskFuncWithError(t *testing.T) { setup() getTaskSetup() mockFetcher := new(mocks.AdminFetcherExtInterface) + taskConfig.DefaultConfig.Filter = filters.Filters{} mockFetcher.OnFetchAllVerOfTaskMatch(mock.Anything, mock.Anything, mock.Anything, - mock.Anything).Return(nil, fmt.Errorf("error fetching all version")) + mock.Anything, mock.Anything).Return(nil, fmt.Errorf("error fetching all version")) _, err = FetchTaskForName(ctx, mockFetcher, "lpName", projectValue, domainValue) assert.NotNil(t, err) }) @@ -186,6 +218,18 @@ func TestGetTaskFuncWithError(t *testing.T) { err = getTaskFunc(ctx, argsTask, cmdCtx) assert.NotNil(t, err) }) + + t.Run("failure fetching list task", func(t *testing.T) { + setup() + getLaunchPlanSetup() + taskConfig.DefaultConfig.Filter = filters.Filters{} + argsTask = []string{} + mockClient.OnListTasksMatch(ctx, resourceListTaskRequest).Return(nil, fmt.Errorf("error fetching all version")) + mockClient.OnGetTaskMatch(ctx, objectGetRequestTask).Return(nil, fmt.Errorf("error fetching task")) + mockClient.OnListTaskIdsMatch(ctx, namedIDRequestTask).Return(nil, fmt.Errorf("error listing task ids")) + err = getTaskFunc(ctx, argsTask, cmdCtx) + assert.NotNil(t, err) + }) } func TestGetTaskFunc(t *testing.T) { @@ -193,7 +237,6 @@ func TestGetTaskFunc(t *testing.T) { getTaskSetup() mockClient.OnListTasksMatch(ctx, resourceListRequestTask).Return(taskListResponse, nil) mockClient.OnGetTaskMatch(ctx, objectGetRequestTask).Return(task2, nil) - mockClient.OnListTaskIdsMatch(ctx, namedIDRequestTask).Return(namedIdentifierListTask, nil) err = getTaskFunc(ctx, argsTask, cmdCtx) assert.Nil(t, err) mockClient.AssertCalled(t, "ListTasks", ctx, resourceListRequestTask) @@ -273,7 +316,7 @@ func TestGetTaskFuncLatest(t *testing.T) { mockClient.OnListTasksMatch(ctx, resourceListRequestTask).Return(taskListResponse, nil) mockClient.OnGetTaskMatch(ctx, objectGetRequestTask).Return(task2, nil) mockClient.OnListTaskIdsMatch(ctx, namedIDRequestTask).Return(namedIdentifierListTask, nil) - taskConfig.Latest = true + taskConfig.DefaultConfig.Latest = true err = getTaskFunc(ctx, argsTask, cmdCtx) assert.Nil(t, err) mockClient.AssertCalled(t, "ListTasks", ctx, resourceListRequestTask) @@ -318,7 +361,7 @@ func TestGetTaskWithVersion(t *testing.T) { mockClient.OnListTasksMatch(ctx, resourceListRequestTask).Return(taskListResponse, nil) mockClient.OnGetTaskMatch(ctx, objectGetRequestTask).Return(task2, nil) mockClient.OnListTaskIdsMatch(ctx, namedIDRequestTask).Return(namedIdentifierListTask, nil) - taskConfig.Version = "v2" + taskConfig.DefaultConfig.Version = "v2" objectGetRequestTask.Id.ResourceType = core.ResourceType_TASK err = getTaskFunc(ctx, argsTask, cmdCtx) assert.Nil(t, err) @@ -363,23 +406,21 @@ func TestGetTasks(t *testing.T) { getTaskSetup() mockClient.OnListTasksMatch(ctx, resourceListRequestTask).Return(taskListResponse, nil) mockClient.OnGetTaskMatch(ctx, objectGetRequestTask).Return(task2, nil) - mockClient.OnListTaskIdsMatch(ctx, namedIDRequestTask).Return(namedIdentifierListTask, nil) - argsTask = []string{} err = getTaskFunc(ctx, argsTask, cmdCtx) assert.Nil(t, err) - mockClient.AssertCalled(t, "ListTaskIds", ctx, namedIDRequest) - tearDownAndVerify(t, `[ - { - "project": "dummyProject", - "domain": "dummyDomain", - "name": "task1" - }, - { - "project": "dummyProject", - "domain": "dummyDomain", - "name": "task2" + tearDownAndVerify(t, `[{"id": {"name": "task1","version": "v2"},"closure": {"compiledTask": {"template": {"interface": {"inputs": {"variables": {"sorted_list1": {"type": {"collectionType": {"simple": "INTEGER"}}},"sorted_list2": {"type": {"collectionType": {"simple": "INTEGER"}}}}}}}},"createdAt": "1970-01-01T00:00:01Z"}},{"id": {"name": "task1","version": "v1"},"closure": {"compiledTask": {"template": {"interface": {"inputs": {"variables": {"sorted_list1": {"type": {"collectionType": {"simple": "INTEGER"}}},"sorted_list2": {"type": {"collectionType": {"simple": "INTEGER"}}}}}}}},"createdAt": "1970-01-01T00:00:00Z"}}]`) +} + +func TestGetTasksFilters(t *testing.T) { + setup() + getTaskSetup() + taskConfig.DefaultConfig.Filter = filters.Filters{ + FieldSelector: "task.name=task1,task.version=v1", } -]`) + mockClient.OnListTasksMatch(ctx, resourceListFilterRequestTask).Return(taskListFilterResponse, nil) + err = getTaskFunc(ctx, argsTask, cmdCtx) + assert.Nil(t, err) + tearDownAndVerify(t, `{"id": {"name": "task1","version": "v1"},"closure": {"compiledTask": {"template": {"interface": {"inputs": {"variables": {"sorted_list1": {"type": {"collectionType": {"simple": "INTEGER"}}},"sorted_list2": {"type": {"collectionType": {"simple": "INTEGER"}}}}}}}},"createdAt": "1970-01-01T00:00:00Z"}}`) } func TestGetTaskWithExecFile(t *testing.T) { @@ -388,10 +429,10 @@ func TestGetTaskWithExecFile(t *testing.T) { mockClient.OnListTasksMatch(ctx, resourceListRequestTask).Return(taskListResponse, nil) mockClient.OnGetTaskMatch(ctx, objectGetRequestTask).Return(task2, nil) mockClient.OnListTaskIdsMatch(ctx, namedIDRequestTask).Return(namedIdentifierListTask, nil) - taskConfig.Version = "v2" - taskConfig.ExecFile = testDataFolder + "task_exec_file" + taskConfig.DefaultConfig.Version = "v2" + taskConfig.DefaultConfig.ExecFile = testDataFolder + "task_exec_file" err = getTaskFunc(ctx, argsTask, cmdCtx) - os.Remove(taskConfig.ExecFile) + os.Remove(taskConfig.DefaultConfig.ExecFile) assert.Nil(t, err) mockClient.AssertCalled(t, "GetTask", ctx, objectGetRequestTask) tearDownAndVerify(t, `{ diff --git a/flytectl/cmd/get/taskconfig_flags.go b/flytectl/cmd/get/taskconfig_flags.go deleted file mode 100755 index 525884466bb..00000000000 --- a/flytectl/cmd/get/taskconfig_flags.go +++ /dev/null @@ -1,48 +0,0 @@ -// Code generated by go generate; DO NOT EDIT. -// This file was generated by robots. - -package get - -import ( - "encoding/json" - "reflect" - - "fmt" - - "github.com/spf13/pflag" -) - -// If v is a pointer, it will get its element value or the zero value of the element type. -// If v is not a pointer, it will return it as is. -func (TaskConfig) elemValueOrNil(v interface{}) interface{} { - if t := reflect.TypeOf(v); t.Kind() == reflect.Ptr { - if reflect.ValueOf(v).IsNil() { - return reflect.Zero(t.Elem()).Interface() - } else { - return reflect.ValueOf(v).Interface() - } - } else if v == nil { - return reflect.Zero(t).Interface() - } - - return v -} - -func (TaskConfig) mustMarshalJSON(v json.Marshaler) string { - raw, err := v.MarshalJSON() - if err != nil { - panic(err) - } - - return string(raw) -} - -// GetPFlagSet will return strongly types pflags for all fields in TaskConfig and its nested types. The format of the -// flags is json-name.json-sub-name... etc. -func (cfg TaskConfig) GetPFlagSet(prefix string) *pflag.FlagSet { - cmdFlags := pflag.NewFlagSet("TaskResourceAttrConfig", pflag.ExitOnError) - cmdFlags.StringVar(&(taskConfig.ExecFile), fmt.Sprintf("%v%v", prefix, "execFile"), taskConfig.ExecFile, "execution file name to be used for generating execution spec of a single task.") - cmdFlags.StringVar(&(taskConfig.Version), fmt.Sprintf("%v%v", prefix, "version"), taskConfig.Version, "version of the task to be fetched.") - cmdFlags.BoolVar(&(taskConfig.Latest), fmt.Sprintf("%v%v", prefix, "latest"), taskConfig.Latest, "flag to indicate to fetch the latest version, version flag will be ignored in this case") - return cmdFlags -} diff --git a/flytectl/cmd/get/workflow.go b/flytectl/cmd/get/workflow.go index 4de25ace611..c87cc3406ba 100644 --- a/flytectl/cmd/get/workflow.go +++ b/flytectl/cmd/get/workflow.go @@ -3,6 +3,8 @@ package get import ( "context" + "github.com/flyteorg/flytectl/pkg/filters" + workflowconfig "github.com/flyteorg/flytectl/cmd/config/subcommand/workflow" "github.com/flyteorg/flytectl/pkg/ext" "github.com/flyteorg/flytestdlib/logger" @@ -10,7 +12,6 @@ import ( "github.com/flyteorg/flytectl/cmd/config" cmdCore "github.com/flyteorg/flytectl/cmd/core" - "github.com/flyteorg/flytectl/pkg/adminutils" "github.com/flyteorg/flytectl/pkg/printer" "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/admin" @@ -42,10 +43,20 @@ Retrieves particular version of workflow by name within project and domain. flytectl get workflow -p flytesnacks -d development core.basic.lp.go_greet --version v2 -Retrieves workflow by filters. +Retrieves all the workflows with filters. :: - - Not yet implemented + + bin/flytectl get workflow -p flytesnacks -d development --filter.field-selector="workflow.name=k8s_spark.dataframe_passing.my_smart_schema" + +Retrieve specific workflow with filters. +:: + + bin/flytectl get workflow -p flytesnacks -d development k8s_spark.dataframe_passing.my_smart_schema --filter.field-selector="workflow.version=v1" + +Retrieves all the workflows with limit and sorting. +:: + + bin/flytectl get -p flytesnacks -d development workflow --filter.sort-by=created_at --filter.limit=1 --filter.asc Retrieves all the workflow within project and domain in yaml format. @@ -63,6 +74,18 @@ Usage ` ) +//go:generate pflags WorkflowConfig --default-var workflowConfig +var ( + workflowConfig = &WorkflowConfig{ + Filter: filters.DefaultFilter, + } +) + +// WorkflowConfig +type WorkflowConfig struct { + Filter filters.Filters `json:"filter" pflag:","` +} + var workflowColumns = []printer.Column{ {Header: "Version", JSONPath: "$.id.version"}, {Header: "Name", JSONPath: "$.id.name"}, @@ -94,12 +117,18 @@ func getWorkflowFunc(ctx context.Context, args []string, cmdCtx cmdCore.CommandC return nil } - workflows, err := adminutils.GetAllNamedEntities(ctx, cmdCtx.AdminClient().ListWorkflowIds, adminutils.ListRequest{Project: config.GetConfig().Project, Domain: config.GetConfig().Domain}) + transformFilters, err := filters.BuildResourceListRequestWithName(workflowConfig.Filter, config.GetConfig().Project, config.GetConfig().Domain, "") + if err != nil { + return err + } + workflowList, err := cmdCtx.AdminClient().ListWorkflows(ctx, transformFilters) if err != nil { return err } + workflows := workflowList.Workflows + logger.Debugf(ctx, "Retrieved %v workflows", len(workflows)) - return adminPrinter.Print(config.GetConfig().MustOutputFormat(), entityColumns, adminutils.NamedEntityToProtoMessage(workflows)...) + return adminPrinter.Print(config.GetConfig().MustOutputFormat(), workflowColumns, WorkflowToProtoMessages(workflows)...) } // FetchWorkflowForName fetches the workflow give it name. @@ -109,7 +138,7 @@ func FetchWorkflowForName(ctx context.Context, fetcher ext.AdminFetcherExtInterf var workflow *admin.Workflow var err error if workflowconfig.DefaultConfig.Latest { - if workflow, err = fetcher.FetchWorkflowLatestVersion(ctx, name, project, domain); err != nil { + if workflow, err = fetcher.FetchWorkflowLatestVersion(ctx, name, project, domain, workflowConfig.Filter); err != nil { return nil, err } workflows = append(workflows, workflow) @@ -119,7 +148,7 @@ func FetchWorkflowForName(ctx context.Context, fetcher ext.AdminFetcherExtInterf } workflows = append(workflows, workflow) } else { - workflows, err = fetcher.FetchAllVerOfWorkflow(ctx, name, project, domain) + workflows, err = fetcher.FetchAllVerOfWorkflow(ctx, name, project, domain, workflowConfig.Filter) if err != nil { return nil, err } diff --git a/flytectl/cmd/get/workflow_test.go b/flytectl/cmd/get/workflow_test.go index bb9f88d3568..29f3274afc3 100644 --- a/flytectl/cmd/get/workflow_test.go +++ b/flytectl/cmd/get/workflow_test.go @@ -4,17 +4,51 @@ import ( "fmt" "testing" - "github.com/flyteorg/flytectl/cmd/config/subcommand/workflow" - u "github.com/flyteorg/flytectl/cmd/testutils" "github.com/flyteorg/flytectl/pkg/ext/mocks" + "github.com/flyteorg/flytectl/pkg/filters" + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/admin" + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/core" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + + "github.com/flyteorg/flytectl/cmd/config/subcommand/workflow" + u "github.com/flyteorg/flytectl/cmd/testutils" +) + +var ( + resourceListRequestWorkflow *admin.ResourceListRequest + workflowListResponse *admin.WorkflowList ) func getWorkflowSetup() { ctx = u.Ctx mockClient = u.MockClient cmdCtx = u.CmdCtx + resourceListRequestWorkflow = &admin.ResourceListRequest{ + Id: &admin.NamedEntityIdentifier{ + Project: projectValue, + Domain: domainValue, + }, + } + + workflow1 := &admin.Workflow{ + Id: &core.Identifier{ + Project: projectValue, + Domain: domainValue, + Name: "workflow1", + }, + } + workflow2 := &admin.Workflow{ + Id: &core.Identifier{ + Project: projectValue, + Domain: domainValue, + Name: "workflow2", + }, + } + workflows := []*admin.Workflow{workflow1, workflow2} + workflowListResponse = &admin.WorkflowList{ + Workflows: workflows, + } workflow.DefaultConfig.Latest = false workflow.DefaultConfig.Version = "" } @@ -25,8 +59,7 @@ func TestGetWorkflowFuncWithError(t *testing.T) { getWorkflowSetup() mockFetcher := new(mocks.AdminFetcherExtInterface) workflow.DefaultConfig.Latest = true - mockFetcher.OnFetchWorkflowLatestVersionMatch(mock.Anything, mock.Anything, mock.Anything, - mock.Anything).Return(nil, fmt.Errorf("error fetching latest version")) + mockFetcher.OnFetchWorkflowLatestVersionMatch(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("error fetching latest version")) _, err = FetchWorkflowForName(ctx, mockFetcher, "workflowName", projectValue, domainValue) assert.NotNil(t, err) }) @@ -37,7 +70,7 @@ func TestGetWorkflowFuncWithError(t *testing.T) { mockFetcher := new(mocks.AdminFetcherExtInterface) workflow.DefaultConfig.Version = "v1" mockFetcher.OnFetchWorkflowVersionMatch(mock.Anything, mock.Anything, mock.Anything, mock.Anything, - mock.Anything).Return(nil, fmt.Errorf("error fetching version")) + mock.Anything, mock.Anything).Return(nil, fmt.Errorf("error fetching version")) _, err = FetchWorkflowForName(ctx, mockFetcher, "workflowName", projectValue, domainValue) assert.NotNil(t, err) }) @@ -47,7 +80,7 @@ func TestGetWorkflowFuncWithError(t *testing.T) { getWorkflowSetup() mockFetcher := new(mocks.AdminFetcherExtInterface) mockFetcher.OnFetchAllVerOfWorkflowMatch(mock.Anything, mock.Anything, mock.Anything, - mock.Anything).Return(nil, fmt.Errorf("error fetching all version")) + mock.Anything, mock.Anything).Return(nil, fmt.Errorf("error fetching all version")) _, err = FetchWorkflowForName(ctx, mockFetcher, "workflowName", projectValue, domainValue) assert.NotNil(t, err) }) @@ -58,8 +91,20 @@ func TestGetWorkflowFuncWithError(t *testing.T) { workflow.DefaultConfig.Latest = true args := []string{"workflowName"} u.FetcherExt.OnFetchWorkflowLatestVersionMatch(mock.Anything, mock.Anything, mock.Anything, - mock.Anything).Return(nil, fmt.Errorf("error fetching latest version")) + mock.Anything, mock.Anything).Return(nil, fmt.Errorf("error fetching latest version")) err = getWorkflowFunc(ctx, args, cmdCtx) assert.NotNil(t, err) }) + +} + +func TestGetWorkflowFunc(t *testing.T) { + setup() + getWorkflowSetup() + workflowConfig.Filter = filters.Filters{} + argsWorkflow := []string{} + mockClient.OnListWorkflowsMatch(ctx, resourceListRequestWorkflow).Return(workflowListResponse, nil) + err = getWorkflowFunc(ctx, argsWorkflow, cmdCtx) + assert.Nil(t, err) + mockClient.AssertCalled(t, "ListWorkflows", ctx, resourceListRequestWorkflow) } diff --git a/flytectl/docs/source/gen/flytectl.rst b/flytectl/docs/source/gen/flytectl.rst index 22fabc9f41f..35598ae7a23 100644 --- a/flytectl/docs/source/gen/flytectl.rst +++ b/flytectl/docs/source/gen/flytectl.rst @@ -30,8 +30,6 @@ Options --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. -h, --help help for flytectl diff --git a/flytectl/docs/source/gen/flytectl_config.rst b/flytectl/docs/source/gen/flytectl_config.rst index aea876904b2..5039c54e4fb 100644 --- a/flytectl/docs/source/gen/flytectl_config.rst +++ b/flytectl/docs/source/gen/flytectl_config.rst @@ -39,8 +39,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_config_discover.rst b/flytectl/docs/source/gen/flytectl_config_discover.rst index c1c625d72a4..932addfa427 100644 --- a/flytectl/docs/source/gen/flytectl_config_discover.rst +++ b/flytectl/docs/source/gen/flytectl_config_discover.rst @@ -41,8 +41,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --file stringArray Passes the config file to load. diff --git a/flytectl/docs/source/gen/flytectl_config_validate.rst b/flytectl/docs/source/gen/flytectl_config_validate.rst index a55952f1dec..984231c587d 100644 --- a/flytectl/docs/source/gen/flytectl_config_validate.rst +++ b/flytectl/docs/source/gen/flytectl_config_validate.rst @@ -43,8 +43,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --file stringArray Passes the config file to load. diff --git a/flytectl/docs/source/gen/flytectl_create.rst b/flytectl/docs/source/gen/flytectl_create.rst index 67aff792713..b2463ade5fc 100644 --- a/flytectl/docs/source/gen/flytectl_create.rst +++ b/flytectl/docs/source/gen/flytectl_create.rst @@ -42,8 +42,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_create_execution.rst b/flytectl/docs/source/gen/flytectl_create_execution.rst index 2d99025dfa5..aac5479c3b6 100644 --- a/flytectl/docs/source/gen/flytectl_create_execution.rst +++ b/flytectl/docs/source/gen/flytectl_create_execution.rst @@ -115,8 +115,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_create_project.rst b/flytectl/docs/source/gen/flytectl_create_project.rst index 994e53e8258..a0670e5f92b 100644 --- a/flytectl/docs/source/gen/flytectl_create_project.rst +++ b/flytectl/docs/source/gen/flytectl_create_project.rst @@ -66,8 +66,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_delete.rst b/flytectl/docs/source/gen/flytectl_delete.rst index 6795a572e41..9cfd95edad2 100644 --- a/flytectl/docs/source/gen/flytectl_delete.rst +++ b/flytectl/docs/source/gen/flytectl_delete.rst @@ -42,8 +42,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_delete_cluster-resource-attribute.rst b/flytectl/docs/source/gen/flytectl_delete_cluster-resource-attribute.rst index e29fb6b821d..17eae9ec87e 100644 --- a/flytectl/docs/source/gen/flytectl_delete_cluster-resource-attribute.rst +++ b/flytectl/docs/source/gen/flytectl_delete_cluster-resource-attribute.rst @@ -78,8 +78,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_delete_execution-cluster-label.rst b/flytectl/docs/source/gen/flytectl_delete_execution-cluster-label.rst index 801b28f333f..2524bc63e81 100644 --- a/flytectl/docs/source/gen/flytectl_delete_execution-cluster-label.rst +++ b/flytectl/docs/source/gen/flytectl_delete_execution-cluster-label.rst @@ -76,8 +76,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_delete_execution-queue-attribute.rst b/flytectl/docs/source/gen/flytectl_delete_execution-queue-attribute.rst index 43b59d38787..c9935a0f7f1 100644 --- a/flytectl/docs/source/gen/flytectl_delete_execution-queue-attribute.rst +++ b/flytectl/docs/source/gen/flytectl_delete_execution-queue-attribute.rst @@ -80,8 +80,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_delete_execution.rst b/flytectl/docs/source/gen/flytectl_delete_execution.rst index 14a769ccb05..f87a174752d 100644 --- a/flytectl/docs/source/gen/flytectl_delete_execution.rst +++ b/flytectl/docs/source/gen/flytectl_delete_execution.rst @@ -85,8 +85,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_delete_plugin-override.rst b/flytectl/docs/source/gen/flytectl_delete_plugin-override.rst index 5431cb54f9a..03b9f01b0e0 100644 --- a/flytectl/docs/source/gen/flytectl_delete_plugin-override.rst +++ b/flytectl/docs/source/gen/flytectl_delete_plugin-override.rst @@ -81,8 +81,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_delete_task-resource-attribute.rst b/flytectl/docs/source/gen/flytectl_delete_task-resource-attribute.rst index 19ee6daf95e..2d782bb68b7 100644 --- a/flytectl/docs/source/gen/flytectl_delete_task-resource-attribute.rst +++ b/flytectl/docs/source/gen/flytectl_delete_task-resource-attribute.rst @@ -81,8 +81,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_get.rst b/flytectl/docs/source/gen/flytectl_get.rst index 2faf6997b84..82dcafb42f4 100644 --- a/flytectl/docs/source/gen/flytectl_get.rst +++ b/flytectl/docs/source/gen/flytectl_get.rst @@ -42,8 +42,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_get_cluster-resource-attribute.rst b/flytectl/docs/source/gen/flytectl_get_cluster-resource-attribute.rst index d650498f752..a713afac14a 100644 --- a/flytectl/docs/source/gen/flytectl_get_cluster-resource-attribute.rst +++ b/flytectl/docs/source/gen/flytectl_get_cluster-resource-attribute.rst @@ -87,8 +87,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_get_execution-cluster-label.rst b/flytectl/docs/source/gen/flytectl_get_execution-cluster-label.rst index e2da0f360de..0f043d8cd4a 100644 --- a/flytectl/docs/source/gen/flytectl_get_execution-cluster-label.rst +++ b/flytectl/docs/source/gen/flytectl_get_execution-cluster-label.rst @@ -85,8 +85,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_get_execution-queue-attribute.rst b/flytectl/docs/source/gen/flytectl_get_execution-queue-attribute.rst index 667fe0fd96f..1f0593a1254 100644 --- a/flytectl/docs/source/gen/flytectl_get_execution-queue-attribute.rst +++ b/flytectl/docs/source/gen/flytectl_get_execution-queue-attribute.rst @@ -89,8 +89,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_get_execution.rst b/flytectl/docs/source/gen/flytectl_get_execution.rst index 43e7134dbaf..1726008f381 100644 --- a/flytectl/docs/source/gen/flytectl_get_execution.rst +++ b/flytectl/docs/source/gen/flytectl_get_execution.rst @@ -21,10 +21,21 @@ Retrieves execution by name within project and domain. bin/flytectl get execution -p flytesnacks -d development oeh94k9r2r -Retrieves execution by filters +Retrieves all the execution with filters. :: - - Not yet implemented + + bin/flytectl get execution -p flytesnacks -d development --filter.field-selector="execution.phase in (FAILED;SUCCEEDED),execution.duration<200" + +Retrieve specific execution with filters. +:: + + bin/flytectl get execution -p flytesnacks -d development y8n2wtuspj --filter.field-selector="execution.phase in (FAILED),execution.duration<200" + +Retrieves all the execution with limit and sorting. +:: + + bin/flytectl get execution -p flytesnacks -d development --filter.sort-by=created_at --filter.limit=1 --filter.asc + Retrieves all the execution within project and domain in yaml format @@ -50,7 +61,11 @@ Options :: - -h, --help help for execution + --filter.asc Specifies the sorting order. By default flytectl sort result in descending order + --filter.field-selector string Specifies the Field selector + --filter.limit int32 Specifies the limit (default 100) + --filter.sort-by string Specifies which field to sort results (default "created_at") + -h, --help help for execution Options inherited from parent commands ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -71,8 +86,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_get_launchplan.rst b/flytectl/docs/source/gen/flytectl_get_launchplan.rst index fbbef2cacee..23b06925cda 100644 --- a/flytectl/docs/source/gen/flytectl_get_launchplan.rst +++ b/flytectl/docs/source/gen/flytectl_get_launchplan.rst @@ -34,10 +34,22 @@ Retrieves particular version of launchplan by name within project and domain. flytectl get launchplan -p flytesnacks -d development core.basic.lp.go_greet --version v2 -Retrieves launchplan by filters. +Retrieves all the launch plans with filters. :: - - Not yet implemented + + bin/flytectl get launchplan -p flytesnacks -d development --filter.field-selector="name=core.basic.lp.go_greet" + +Retrieves specific launch plans with filters. +:: + + bin/flytectl get launchplan -p flytesnacks -d development k8s_spark.dataframe_passing.my_smart_schema --filter.field-selector="version=v1" + + +Retrieves all the launch plans with limit and sorting. +:: + + bin/flytectl get launchplan -p flytesnacks -d development --filter.sort-by=created_at --filter.limit=1 --filter.asc + Retrieves all the launchplan within project and domain in yaml format. @@ -87,10 +99,14 @@ Options :: - --execFile string execution file name to be used for generating execution spec of a single launchplan. - -h, --help help for launchplan - --latest flag to indicate to fetch the latest version, version flag will be ignored in this case - --version string version of the launchplan to be fetched. + --execFile string execution file name to be used for generating execution spec of a single launchplan. + --filter.asc Specifies the sorting order. By default flytectl sort result in descending order + --filter.field-selector string Specifies the Field selector + --filter.limit int32 Specifies the limit (default 100) + --filter.sort-by string Specifies which field to sort results (default "created_at") + -h, --help help for launchplan + --latest flag to indicate to fetch the latest version, version flag will be ignored in this case + --version string version of the launchplan to be fetched. Options inherited from parent commands ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -111,8 +127,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_get_plugin-override.rst b/flytectl/docs/source/gen/flytectl_get_plugin-override.rst index 25fbfbf288a..fcc8e5c9be9 100644 --- a/flytectl/docs/source/gen/flytectl_get_plugin-override.rst +++ b/flytectl/docs/source/gen/flytectl_get_plugin-override.rst @@ -109,8 +109,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_get_project.rst b/flytectl/docs/source/gen/flytectl_get_project.rst index 9d9eec43cf5..ba86d53cd07 100644 --- a/flytectl/docs/source/gen/flytectl_get_project.rst +++ b/flytectl/docs/source/gen/flytectl_get_project.rst @@ -21,10 +21,15 @@ Retrieves project by name bin/flytectl get project flytesnacks -Retrieves project by filters +Retrieves all the projects with filters. :: - - Not yet implemented + + bin/flytectl get project --filter.field-selector="project.name=flytesnacks" + +Retrieves all the projects with limit and sorting. +:: + + bin/flytectl get project --filter.sort-by=created_at --filter.limit=1 --filter.asc Retrieves all the projects in yaml format @@ -50,7 +55,11 @@ Options :: - -h, --help help for project + --filter.asc Specifies the sorting order. By default flytectl sort result in descending order + --filter.field-selector string Specifies the Field selector + --filter.limit int32 Specifies the limit (default 100) + --filter.sort-by string Specifies which field to sort results (default "created_at") + -h, --help help for project Options inherited from parent commands ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -71,8 +80,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_get_task-resource-attribute.rst b/flytectl/docs/source/gen/flytectl_get_task-resource-attribute.rst index 613da8d7b39..dfd44d3c323 100644 --- a/flytectl/docs/source/gen/flytectl_get_task-resource-attribute.rst +++ b/flytectl/docs/source/gen/flytectl_get_task-resource-attribute.rst @@ -91,8 +91,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_get_task.rst b/flytectl/docs/source/gen/flytectl_get_task.rst index e7c2c759687..f49501561d5 100644 --- a/flytectl/docs/source/gen/flytectl_get_task.rst +++ b/flytectl/docs/source/gen/flytectl_get_task.rst @@ -31,15 +31,24 @@ Retrieves particular version of task by name within project and domain. :: - flytectl get workflow -p flytesnacks -d development core.basic.lp.greet --version v2 + flytectl get task -p flytesnacks -d development core.basic.lp.greet --version v2 -Retrieves project by filters. +Retrieves all the tasks with filters. :: - - Not yet implemented + + bin/flytectl get task -p flytesnacks -d development --filter.field-selector="task.name=k8s_spark.pyspark_pi.print_every_time,task.version=v1" + +Retrieve a specific task with filters. +:: + + bin/flytectl get task -p flytesnacks -d development k8s_spark.pyspark_pi.print_every_time --filter.field-selector="task.version=v1,created_at>=2021-05-24T21:43:12.325335Z" + +Retrieves all the task with limit and sorting. +:: + + bin/flytectl get -p flytesnacks -d development task --filter.sort-by=created_at --filter.limit=1 --filter.asc Retrieves all the tasks within project and domain in yaml format. - :: bin/flytectl get task -p flytesnacks -d development -o yaml @@ -86,10 +95,14 @@ Options :: - --execFile string execution file name to be used for generating execution spec of a single task. - -h, --help help for task - --latest flag to indicate to fetch the latest version, version flag will be ignored in this case - --version string version of the task to be fetched. + --execFile string execution file name to be used for generating execution spec of a single task. + --filter.asc Specifies the sorting order. By default flytectl sort result in descending order + --filter.field-selector string Specifies the Field selector + --filter.limit int32 Specifies the limit (default 100) + --filter.sort-by string Specifies which field to sort results (default "created_at") + -h, --help help for task + --latest flag to indicate to fetch the latest version, version flag will be ignored in this case + --version string version of the task to be fetched. Options inherited from parent commands ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -110,8 +123,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_get_workflow.rst b/flytectl/docs/source/gen/flytectl_get_workflow.rst index e951129aa5f..846afb9682b 100644 --- a/flytectl/docs/source/gen/flytectl_get_workflow.rst +++ b/flytectl/docs/source/gen/flytectl_get_workflow.rst @@ -33,10 +33,20 @@ Retrieves particular version of workflow by name within project and domain. flytectl get workflow -p flytesnacks -d development core.basic.lp.go_greet --version v2 -Retrieves workflow by filters. +Retrieves all the workflows with filters. :: - - Not yet implemented + + bin/flytectl get workflow -p flytesnacks -d development --filter.field-selector="workflow.name=k8s_spark.dataframe_passing.my_smart_schema" + +Retrieve specific workflow with filters. +:: + + bin/flytectl get workflow -p flytesnacks -d development k8s_spark.dataframe_passing.my_smart_schema --filter.field-selector="workflow.version=v1" + +Retrieves all the workflows with limit and sorting. +:: + + bin/flytectl get -p flytesnacks -d development workflow --filter.sort-by=created_at --filter.limit=1 --filter.asc Retrieves all the workflow within project and domain in yaml format. @@ -62,9 +72,11 @@ Options :: - -h, --help help for workflow - --latest flag to indicate to fetch the latest version, version flag will be ignored in this case - --version string version of the workflow to be fetched. + --filter.asc Specifies the sorting order. By default flytectl sort result in descending order + --filter.field-selector string Specifies the Field selector + --filter.limit int32 Specifies the limit (default 100) + --filter.sort-by string Specifies which field to sort results (default "created_at") + -h, --help help for workflow Options inherited from parent commands ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -85,8 +97,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_register.rst b/flytectl/docs/source/gen/flytectl_register.rst index 76ba2622471..98d8c02b4a1 100644 --- a/flytectl/docs/source/gen/flytectl_register.rst +++ b/flytectl/docs/source/gen/flytectl_register.rst @@ -42,8 +42,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_register_files.rst b/flytectl/docs/source/gen/flytectl_register_files.rst index 39f7601c8df..8d79a9df137 100644 --- a/flytectl/docs/source/gen/flytectl_register_files.rst +++ b/flytectl/docs/source/gen/flytectl_register_files.rst @@ -109,8 +109,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_update.rst b/flytectl/docs/source/gen/flytectl_update.rst index 43dfbae8df9..17ba39721e4 100644 --- a/flytectl/docs/source/gen/flytectl_update.rst +++ b/flytectl/docs/source/gen/flytectl_update.rst @@ -44,8 +44,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_update_cluster-resource-attribute.rst b/flytectl/docs/source/gen/flytectl_update_cluster-resource-attribute.rst index 3bc41ae6463..b8000b4d3c3 100644 --- a/flytectl/docs/source/gen/flytectl_update_cluster-resource-attribute.rst +++ b/flytectl/docs/source/gen/flytectl_update_cluster-resource-attribute.rst @@ -83,8 +83,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_update_execution-cluster-label.rst b/flytectl/docs/source/gen/flytectl_update_execution-cluster-label.rst index 8f22a1f3270..2431eedd01e 100644 --- a/flytectl/docs/source/gen/flytectl_update_execution-cluster-label.rst +++ b/flytectl/docs/source/gen/flytectl_update_execution-cluster-label.rst @@ -76,8 +76,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_update_execution-queue-attribute.rst b/flytectl/docs/source/gen/flytectl_update_execution-queue-attribute.rst index 19d10aa0506..a32e711f121 100644 --- a/flytectl/docs/source/gen/flytectl_update_execution-queue-attribute.rst +++ b/flytectl/docs/source/gen/flytectl_update_execution-queue-attribute.rst @@ -87,8 +87,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_update_launchplan.rst b/flytectl/docs/source/gen/flytectl_update_launchplan.rst index f0e7838f61d..aeb20a9f162 100644 --- a/flytectl/docs/source/gen/flytectl_update_launchplan.rst +++ b/flytectl/docs/source/gen/flytectl_update_launchplan.rst @@ -61,8 +61,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_update_plugin-override.rst b/flytectl/docs/source/gen/flytectl_update_plugin-override.rst index b4cf04600f5..657efbfb94d 100644 --- a/flytectl/docs/source/gen/flytectl_update_plugin-override.rst +++ b/flytectl/docs/source/gen/flytectl_update_plugin-override.rst @@ -89,8 +89,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_update_project.rst b/flytectl/docs/source/gen/flytectl_update_project.rst index e7954f31dda..742db693b92 100644 --- a/flytectl/docs/source/gen/flytectl_update_project.rst +++ b/flytectl/docs/source/gen/flytectl_update_project.rst @@ -86,8 +86,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_update_task-resource-attribute.rst b/flytectl/docs/source/gen/flytectl_update_task-resource-attribute.rst index 496a79779e7..d4ae5db9c97 100644 --- a/flytectl/docs/source/gen/flytectl_update_task-resource-attribute.rst +++ b/flytectl/docs/source/gen/flytectl_update_task-resource-attribute.rst @@ -89,8 +89,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_update_task.rst b/flytectl/docs/source/gen/flytectl_update_task.rst index 9d4c95142b8..26d9237800d 100644 --- a/flytectl/docs/source/gen/flytectl_update_task.rst +++ b/flytectl/docs/source/gen/flytectl_update_task.rst @@ -61,8 +61,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_update_workflow.rst b/flytectl/docs/source/gen/flytectl_update_workflow.rst index 5899dfa2208..b79c81977d5 100644 --- a/flytectl/docs/source/gen/flytectl_update_workflow.rst +++ b/flytectl/docs/source/gen/flytectl_update_workflow.rst @@ -61,8 +61,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/docs/source/gen/flytectl_version.rst b/flytectl/docs/source/gen/flytectl_version.rst index 4ba5a821ef8..7d125dcfb94 100644 --- a/flytectl/docs/source/gen/flytectl_version.rst +++ b/flytectl/docs/source/gen/flytectl_version.rst @@ -46,8 +46,6 @@ Options inherited from parent commands --admin.scopes strings List of scopes to request --admin.tokenUrl string OPTIONAL: Your IdP's token endpoint. It'll be discovered from flyte admin's OAuth Metadata endpoint if not provided. --admin.useAuth Deprecated: Auth will be enabled/disabled based on admin's dynamically discovered information. - --adminutils.batchSize int Maximum number of records to retrieve per call. (default 100) - --adminutils.maxRecords int Maximum number of records to retrieve. (default 500) --config string config file (default is $HOME/.flyte/config.yaml) -d, --domain string Specifies the Flyte project's domain. --logger.formatter.type string Sets logging format type. (default "json") diff --git a/flytectl/pkg/ext/deleter_test.go b/flytectl/pkg/ext/deleter_test.go new file mode 100644 index 00000000000..17666b021dc --- /dev/null +++ b/flytectl/pkg/ext/deleter_test.go @@ -0,0 +1,17 @@ +package ext + +import ( + "testing" + + "github.com/flyteorg/flyteidl/clients/go/admin/mocks" + "github.com/stretchr/testify/assert" +) + +var deleterFetcherClient *AdminDeleterExtClient + +func TestAdminDeleterExtClient_AdminServiceClient(t *testing.T) { + adminClient = new(mocks.AdminServiceClient) + deleterFetcherClient = nil + client := deleterFetcherClient.AdminServiceClient() + assert.Nil(t, client) +} diff --git a/flytectl/pkg/ext/fetcher.go b/flytectl/pkg/ext/fetcher.go index 8601ec7e718..ecc3b6371ce 100644 --- a/flytectl/pkg/ext/fetcher.go +++ b/flytectl/pkg/ext/fetcher.go @@ -3,6 +3,8 @@ package ext import ( "context" + "github.com/flyteorg/flytectl/pkg/filters" + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/admin" "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/service" ) @@ -18,28 +20,28 @@ type AdminFetcherExtInterface interface { FetchExecution(ctx context.Context, name, project, domain string) (*admin.Execution, error) // FetchAllVerOfLP fetches all versions of launch plan in a project, domain - FetchAllVerOfLP(ctx context.Context, lpName, project, domain string) ([]*admin.LaunchPlan, error) + FetchAllVerOfLP(ctx context.Context, lpName, project, domain string, filter filters.Filters) ([]*admin.LaunchPlan, error) // FetchLPLatestVersion fetches latest version of launch plan in a project, domain - FetchLPLatestVersion(ctx context.Context, name, project, domain string) (*admin.LaunchPlan, error) + FetchLPLatestVersion(ctx context.Context, name, project, domain string, filter filters.Filters) (*admin.LaunchPlan, error) // FetchLPVersion fetches particular version of launch plan in a project, domain FetchLPVersion(ctx context.Context, name, version, project, domain string) (*admin.LaunchPlan, error) // FetchAllVerOfTask fetches all versions of task in a project, domain - FetchAllVerOfTask(ctx context.Context, name, project, domain string) ([]*admin.Task, error) + FetchAllVerOfTask(ctx context.Context, name, project, domain string, filter filters.Filters) ([]*admin.Task, error) // FetchTaskLatestVersion fetches latest version of task in a project, domain - FetchTaskLatestVersion(ctx context.Context, name, project, domain string) (*admin.Task, error) + FetchTaskLatestVersion(ctx context.Context, name, project, domain string, filter filters.Filters) (*admin.Task, error) // FetchTaskVersion fetches particular version of task in a project, domain FetchTaskVersion(ctx context.Context, name, version, project, domain string) (*admin.Task, error) // FetchAllVerOfWorkflow fetches all versions of task in a project, domain - FetchAllVerOfWorkflow(ctx context.Context, name, project, domain string) ([]*admin.Workflow, error) + FetchAllVerOfWorkflow(ctx context.Context, name, project, domain string, filter filters.Filters) ([]*admin.Workflow, error) // FetchWorkflowLatestVersion fetches latest version of workflow in a project, domain - FetchWorkflowLatestVersion(ctx context.Context, name, project, domain string) (*admin.Workflow, error) + FetchWorkflowLatestVersion(ctx context.Context, name, project, domain string, filter filters.Filters) (*admin.Workflow, error) // FetchWorkflowVersion fetches particular version of workflow in a project, domain FetchWorkflowVersion(ctx context.Context, name, version, project, domain string) (*admin.Workflow, error) diff --git a/flytectl/pkg/ext/fetcher_test.go b/flytectl/pkg/ext/fetcher_test.go new file mode 100644 index 00000000000..f0ddffebd46 --- /dev/null +++ b/flytectl/pkg/ext/fetcher_test.go @@ -0,0 +1,17 @@ +package ext + +import ( + "testing" + + "github.com/flyteorg/flyteidl/clients/go/admin/mocks" + "github.com/stretchr/testify/assert" +) + +var fetcherClient *AdminFetcherExtClient + +func TestAdminFetcherExtClient_AdminServiceClient(t *testing.T) { + adminClient = new(mocks.AdminServiceClient) + fetcherClient = nil + client := fetcherClient.AdminServiceClient() + assert.Nil(t, client) +} diff --git a/flytectl/pkg/ext/launch_plan_fetcher.go b/flytectl/pkg/ext/launch_plan_fetcher.go index e7aa21b124b..ad24b3abb57 100644 --- a/flytectl/pkg/ext/launch_plan_fetcher.go +++ b/flytectl/pkg/ext/launch_plan_fetcher.go @@ -4,24 +4,19 @@ import ( "context" "fmt" + "github.com/flyteorg/flytectl/pkg/filters" + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/admin" "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/core" ) // FetchAllVerOfLP fetches all the versions for give launch plan name -func (a *AdminFetcherExtClient) FetchAllVerOfLP(ctx context.Context, lpName, project, domain string) ([]*admin.LaunchPlan, error) { - tList, err := a.AdminServiceClient().ListLaunchPlans(ctx, &admin.ResourceListRequest{ - Id: &admin.NamedEntityIdentifier{ - Project: project, - Domain: domain, - Name: lpName, - }, - SortBy: &admin.Sort{ - Key: "created_at", - Direction: admin.Sort_DESCENDING, - }, - Limit: 100, - }) +func (a *AdminFetcherExtClient) FetchAllVerOfLP(ctx context.Context, lpName, project, domain string, filter filters.Filters) ([]*admin.LaunchPlan, error) { + transformFilters, err := filters.BuildResourceListRequestWithName(filter, project, domain, lpName) + if err != nil { + return nil, err + } + tList, err := a.AdminServiceClient().ListLaunchPlans(ctx, transformFilters) if err != nil { return nil, err } @@ -32,9 +27,9 @@ func (a *AdminFetcherExtClient) FetchAllVerOfLP(ctx context.Context, lpName, pro } // FetchLPLatestVersion fetches latest version for give launch plan name -func (a *AdminFetcherExtClient) FetchLPLatestVersion(ctx context.Context, name, project, domain string) (*admin.LaunchPlan, error) { +func (a *AdminFetcherExtClient) FetchLPLatestVersion(ctx context.Context, name, project, domain string, filter filters.Filters) (*admin.LaunchPlan, error) { // Fetch the latest version of the task. - lpVersions, err := a.FetchAllVerOfLP(ctx, name, project, domain) + lpVersions, err := a.FetchAllVerOfLP(ctx, name, project, domain, filter) if err != nil { return nil, err } diff --git a/flytectl/pkg/ext/launch_plan_fetcher_test.go b/flytectl/pkg/ext/launch_plan_fetcher_test.go index 7b40fbde89f..39d0121c93e 100644 --- a/flytectl/pkg/ext/launch_plan_fetcher_test.go +++ b/flytectl/pkg/ext/launch_plan_fetcher_test.go @@ -5,6 +5,8 @@ import ( "fmt" "testing" + "github.com/flyteorg/flytectl/pkg/filters" + "github.com/flyteorg/flyteidl/clients/go/admin/mocks" "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/admin" "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/core" @@ -16,6 +18,8 @@ import ( var ( launchPlanListResponse *admin.LaunchPlanList + lpFilters = filters.Filters{} + launchPlan1 *admin.LaunchPlan ) func getLaunchPlanFetcherSetup() { @@ -71,7 +75,7 @@ func getLaunchPlanFetcherSetup() { }, }, } - launchPlan1 := &admin.LaunchPlan{ + launchPlan1 = &admin.LaunchPlan{ Id: &core.Identifier{ Name: "launchplan1", Version: "v1", @@ -116,29 +120,45 @@ func getLaunchPlanFetcherSetup() { func TestFetchAllVerOfLP(t *testing.T) { getLaunchPlanFetcherSetup() adminClient.OnListLaunchPlansMatch(mock.Anything, mock.Anything).Return(launchPlanListResponse, nil) - _, err := adminFetcherExt.FetchAllVerOfLP(ctx, "lpName", "project", "domain") + _, err := adminFetcherExt.FetchAllVerOfLP(ctx, "lpName", "project", "domain", lpFilters) + assert.Nil(t, err) +} + +func TestFetchLPVersion(t *testing.T) { + getLaunchPlanFetcherSetup() + adminClient.OnGetLaunchPlanMatch(mock.Anything, mock.Anything).Return(launchPlan1, nil) + _, err := adminFetcherExt.FetchLPVersion(ctx, "launchplan1", "v1", "project", "domain") assert.Nil(t, err) } func TestFetchAllVerOfLPError(t *testing.T) { getLaunchPlanFetcherSetup() adminClient.OnListLaunchPlansMatch(mock.Anything, mock.Anything).Return(nil, fmt.Errorf("failed")) - _, err := adminFetcherExt.FetchAllVerOfLP(ctx, "lpName", "project", "domain") + _, err := adminFetcherExt.FetchAllVerOfLP(ctx, "lpName", "project", "domain", lpFilters) assert.Equal(t, fmt.Errorf("failed"), err) } +func TestFetchAllVerOfLPFilterError(t *testing.T) { + getLaunchPlanFetcherSetup() + lpFilters.FieldSelector = "hello=" + adminClient.OnListLaunchPlansMatch(mock.Anything, mock.Anything).Return(nil, fmt.Errorf("Please add a valid field selector")) + _, err := adminFetcherExt.FetchAllVerOfLP(ctx, "lpName", "project", "domain", lpFilters) + assert.Equal(t, fmt.Errorf("Please add a valid field selector"), err) +} + func TestFetchAllVerOfLPEmptyResponse(t *testing.T) { launchPlanListResponse := &admin.LaunchPlanList{} getLaunchPlanFetcherSetup() + lpFilters.FieldSelector = "" adminClient.OnListLaunchPlansMatch(mock.Anything, mock.Anything).Return(launchPlanListResponse, nil) - _, err := adminFetcherExt.FetchAllVerOfLP(ctx, "lpName", "project", "domain") + _, err := adminFetcherExt.FetchAllVerOfLP(ctx, "lpName", "project", "domain", lpFilters) assert.Equal(t, fmt.Errorf("no launchplans retrieved for lpName"), err) } func TestFetchLPLatestVersion(t *testing.T) { getLaunchPlanFetcherSetup() adminClient.OnListLaunchPlansMatch(mock.Anything, mock.Anything).Return(launchPlanListResponse, nil) - _, err := adminFetcherExt.FetchLPLatestVersion(ctx, "lpName", "project", "domain") + _, err := adminFetcherExt.FetchLPLatestVersion(ctx, "lpName", "project", "domain", lpFilters) assert.Nil(t, err) } @@ -146,6 +166,6 @@ func TestFetchLPLatestVersionError(t *testing.T) { launchPlanListResponse := &admin.LaunchPlanList{} getLaunchPlanFetcherSetup() adminClient.OnListLaunchPlansMatch(mock.Anything, mock.Anything).Return(launchPlanListResponse, nil) - _, err := adminFetcherExt.FetchLPLatestVersion(ctx, "lpName", "project", "domain") + _, err := adminFetcherExt.FetchLPLatestVersion(ctx, "lpName", "project", "domain", lpFilters) assert.Equal(t, fmt.Errorf("no launchplans retrieved for lpName"), err) } diff --git a/flytectl/pkg/ext/mocks/admin_fetcher_ext_interface.go b/flytectl/pkg/ext/mocks/admin_fetcher_ext_interface.go index 902121ef881..8ae7cde8f8d 100644 --- a/flytectl/pkg/ext/mocks/admin_fetcher_ext_interface.go +++ b/flytectl/pkg/ext/mocks/admin_fetcher_ext_interface.go @@ -7,6 +7,8 @@ import ( admin "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/admin" + filters "github.com/flyteorg/flytectl/pkg/filters" + mock "github.com/stretchr/testify/mock" service "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/service" @@ -59,8 +61,8 @@ func (_m AdminFetcherExtInterface_FetchAllVerOfLP) Return(_a0 []*admin.LaunchPla return &AdminFetcherExtInterface_FetchAllVerOfLP{Call: _m.Call.Return(_a0, _a1)} } -func (_m *AdminFetcherExtInterface) OnFetchAllVerOfLP(ctx context.Context, lpName string, project string, domain string) *AdminFetcherExtInterface_FetchAllVerOfLP { - c := _m.On("FetchAllVerOfLP", ctx, lpName, project, domain) +func (_m *AdminFetcherExtInterface) OnFetchAllVerOfLP(ctx context.Context, lpName string, project string, domain string, filter filters.Filters) *AdminFetcherExtInterface_FetchAllVerOfLP { + c := _m.On("FetchAllVerOfLP", ctx, lpName, project, domain, filter) return &AdminFetcherExtInterface_FetchAllVerOfLP{Call: c} } @@ -69,13 +71,13 @@ func (_m *AdminFetcherExtInterface) OnFetchAllVerOfLPMatch(matchers ...interface return &AdminFetcherExtInterface_FetchAllVerOfLP{Call: c} } -// FetchAllVerOfLP provides a mock function with given fields: ctx, lpName, project, domain -func (_m *AdminFetcherExtInterface) FetchAllVerOfLP(ctx context.Context, lpName string, project string, domain string) ([]*admin.LaunchPlan, error) { - ret := _m.Called(ctx, lpName, project, domain) +// FetchAllVerOfLP provides a mock function with given fields: ctx, lpName, project, domain, filter +func (_m *AdminFetcherExtInterface) FetchAllVerOfLP(ctx context.Context, lpName string, project string, domain string, filter filters.Filters) ([]*admin.LaunchPlan, error) { + ret := _m.Called(ctx, lpName, project, domain, filter) var r0 []*admin.LaunchPlan - if rf, ok := ret.Get(0).(func(context.Context, string, string, string) []*admin.LaunchPlan); ok { - r0 = rf(ctx, lpName, project, domain) + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, filters.Filters) []*admin.LaunchPlan); ok { + r0 = rf(ctx, lpName, project, domain, filter) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]*admin.LaunchPlan) @@ -83,8 +85,8 @@ func (_m *AdminFetcherExtInterface) FetchAllVerOfLP(ctx context.Context, lpName } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok { - r1 = rf(ctx, lpName, project, domain) + if rf, ok := ret.Get(1).(func(context.Context, string, string, string, filters.Filters) error); ok { + r1 = rf(ctx, lpName, project, domain, filter) } else { r1 = ret.Error(1) } @@ -100,8 +102,8 @@ func (_m AdminFetcherExtInterface_FetchAllVerOfTask) Return(_a0 []*admin.Task, _ return &AdminFetcherExtInterface_FetchAllVerOfTask{Call: _m.Call.Return(_a0, _a1)} } -func (_m *AdminFetcherExtInterface) OnFetchAllVerOfTask(ctx context.Context, name string, project string, domain string) *AdminFetcherExtInterface_FetchAllVerOfTask { - c := _m.On("FetchAllVerOfTask", ctx, name, project, domain) +func (_m *AdminFetcherExtInterface) OnFetchAllVerOfTask(ctx context.Context, name string, project string, domain string, filter filters.Filters) *AdminFetcherExtInterface_FetchAllVerOfTask { + c := _m.On("FetchAllVerOfTask", ctx, name, project, domain, filter) return &AdminFetcherExtInterface_FetchAllVerOfTask{Call: c} } @@ -110,13 +112,13 @@ func (_m *AdminFetcherExtInterface) OnFetchAllVerOfTaskMatch(matchers ...interfa return &AdminFetcherExtInterface_FetchAllVerOfTask{Call: c} } -// FetchAllVerOfTask provides a mock function with given fields: ctx, name, project, domain -func (_m *AdminFetcherExtInterface) FetchAllVerOfTask(ctx context.Context, name string, project string, domain string) ([]*admin.Task, error) { - ret := _m.Called(ctx, name, project, domain) +// FetchAllVerOfTask provides a mock function with given fields: ctx, name, project, domain, filter +func (_m *AdminFetcherExtInterface) FetchAllVerOfTask(ctx context.Context, name string, project string, domain string, filter filters.Filters) ([]*admin.Task, error) { + ret := _m.Called(ctx, name, project, domain, filter) var r0 []*admin.Task - if rf, ok := ret.Get(0).(func(context.Context, string, string, string) []*admin.Task); ok { - r0 = rf(ctx, name, project, domain) + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, filters.Filters) []*admin.Task); ok { + r0 = rf(ctx, name, project, domain, filter) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]*admin.Task) @@ -124,8 +126,8 @@ func (_m *AdminFetcherExtInterface) FetchAllVerOfTask(ctx context.Context, name } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok { - r1 = rf(ctx, name, project, domain) + if rf, ok := ret.Get(1).(func(context.Context, string, string, string, filters.Filters) error); ok { + r1 = rf(ctx, name, project, domain, filter) } else { r1 = ret.Error(1) } @@ -141,8 +143,8 @@ func (_m AdminFetcherExtInterface_FetchAllVerOfWorkflow) Return(_a0 []*admin.Wor return &AdminFetcherExtInterface_FetchAllVerOfWorkflow{Call: _m.Call.Return(_a0, _a1)} } -func (_m *AdminFetcherExtInterface) OnFetchAllVerOfWorkflow(ctx context.Context, name string, project string, domain string) *AdminFetcherExtInterface_FetchAllVerOfWorkflow { - c := _m.On("FetchAllVerOfWorkflow", ctx, name, project, domain) +func (_m *AdminFetcherExtInterface) OnFetchAllVerOfWorkflow(ctx context.Context, name string, project string, domain string, filter filters.Filters) *AdminFetcherExtInterface_FetchAllVerOfWorkflow { + c := _m.On("FetchAllVerOfWorkflow", ctx, name, project, domain, filter) return &AdminFetcherExtInterface_FetchAllVerOfWorkflow{Call: c} } @@ -151,13 +153,13 @@ func (_m *AdminFetcherExtInterface) OnFetchAllVerOfWorkflowMatch(matchers ...int return &AdminFetcherExtInterface_FetchAllVerOfWorkflow{Call: c} } -// FetchAllVerOfWorkflow provides a mock function with given fields: ctx, name, project, domain -func (_m *AdminFetcherExtInterface) FetchAllVerOfWorkflow(ctx context.Context, name string, project string, domain string) ([]*admin.Workflow, error) { - ret := _m.Called(ctx, name, project, domain) +// FetchAllVerOfWorkflow provides a mock function with given fields: ctx, name, project, domain, filter +func (_m *AdminFetcherExtInterface) FetchAllVerOfWorkflow(ctx context.Context, name string, project string, domain string, filter filters.Filters) ([]*admin.Workflow, error) { + ret := _m.Called(ctx, name, project, domain, filter) var r0 []*admin.Workflow - if rf, ok := ret.Get(0).(func(context.Context, string, string, string) []*admin.Workflow); ok { - r0 = rf(ctx, name, project, domain) + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, filters.Filters) []*admin.Workflow); ok { + r0 = rf(ctx, name, project, domain, filter) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]*admin.Workflow) @@ -165,8 +167,8 @@ func (_m *AdminFetcherExtInterface) FetchAllVerOfWorkflow(ctx context.Context, n } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok { - r1 = rf(ctx, name, project, domain) + if rf, ok := ret.Get(1).(func(context.Context, string, string, string, filters.Filters) error); ok { + r1 = rf(ctx, name, project, domain, filter) } else { r1 = ret.Error(1) } @@ -223,8 +225,8 @@ func (_m AdminFetcherExtInterface_FetchLPLatestVersion) Return(_a0 *admin.Launch return &AdminFetcherExtInterface_FetchLPLatestVersion{Call: _m.Call.Return(_a0, _a1)} } -func (_m *AdminFetcherExtInterface) OnFetchLPLatestVersion(ctx context.Context, name string, project string, domain string) *AdminFetcherExtInterface_FetchLPLatestVersion { - c := _m.On("FetchLPLatestVersion", ctx, name, project, domain) +func (_m *AdminFetcherExtInterface) OnFetchLPLatestVersion(ctx context.Context, name string, project string, domain string, filter filters.Filters) *AdminFetcherExtInterface_FetchLPLatestVersion { + c := _m.On("FetchLPLatestVersion", ctx, name, project, domain, filter) return &AdminFetcherExtInterface_FetchLPLatestVersion{Call: c} } @@ -233,13 +235,13 @@ func (_m *AdminFetcherExtInterface) OnFetchLPLatestVersionMatch(matchers ...inte return &AdminFetcherExtInterface_FetchLPLatestVersion{Call: c} } -// FetchLPLatestVersion provides a mock function with given fields: ctx, name, project, domain -func (_m *AdminFetcherExtInterface) FetchLPLatestVersion(ctx context.Context, name string, project string, domain string) (*admin.LaunchPlan, error) { - ret := _m.Called(ctx, name, project, domain) +// FetchLPLatestVersion provides a mock function with given fields: ctx, name, project, domain, filter +func (_m *AdminFetcherExtInterface) FetchLPLatestVersion(ctx context.Context, name string, project string, domain string, filter filters.Filters) (*admin.LaunchPlan, error) { + ret := _m.Called(ctx, name, project, domain, filter) var r0 *admin.LaunchPlan - if rf, ok := ret.Get(0).(func(context.Context, string, string, string) *admin.LaunchPlan); ok { - r0 = rf(ctx, name, project, domain) + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, filters.Filters) *admin.LaunchPlan); ok { + r0 = rf(ctx, name, project, domain, filter) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*admin.LaunchPlan) @@ -247,8 +249,8 @@ func (_m *AdminFetcherExtInterface) FetchLPLatestVersion(ctx context.Context, na } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok { - r1 = rf(ctx, name, project, domain) + if rf, ok := ret.Get(1).(func(context.Context, string, string, string, filters.Filters) error); ok { + r1 = rf(ctx, name, project, domain, filter) } else { r1 = ret.Error(1) } @@ -346,8 +348,8 @@ func (_m AdminFetcherExtInterface_FetchTaskLatestVersion) Return(_a0 *admin.Task return &AdminFetcherExtInterface_FetchTaskLatestVersion{Call: _m.Call.Return(_a0, _a1)} } -func (_m *AdminFetcherExtInterface) OnFetchTaskLatestVersion(ctx context.Context, name string, project string, domain string) *AdminFetcherExtInterface_FetchTaskLatestVersion { - c := _m.On("FetchTaskLatestVersion", ctx, name, project, domain) +func (_m *AdminFetcherExtInterface) OnFetchTaskLatestVersion(ctx context.Context, name string, project string, domain string, filter filters.Filters) *AdminFetcherExtInterface_FetchTaskLatestVersion { + c := _m.On("FetchTaskLatestVersion", ctx, name, project, domain, filter) return &AdminFetcherExtInterface_FetchTaskLatestVersion{Call: c} } @@ -356,13 +358,13 @@ func (_m *AdminFetcherExtInterface) OnFetchTaskLatestVersionMatch(matchers ...in return &AdminFetcherExtInterface_FetchTaskLatestVersion{Call: c} } -// FetchTaskLatestVersion provides a mock function with given fields: ctx, name, project, domain -func (_m *AdminFetcherExtInterface) FetchTaskLatestVersion(ctx context.Context, name string, project string, domain string) (*admin.Task, error) { - ret := _m.Called(ctx, name, project, domain) +// FetchTaskLatestVersion provides a mock function with given fields: ctx, name, project, domain, filter +func (_m *AdminFetcherExtInterface) FetchTaskLatestVersion(ctx context.Context, name string, project string, domain string, filter filters.Filters) (*admin.Task, error) { + ret := _m.Called(ctx, name, project, domain, filter) var r0 *admin.Task - if rf, ok := ret.Get(0).(func(context.Context, string, string, string) *admin.Task); ok { - r0 = rf(ctx, name, project, domain) + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, filters.Filters) *admin.Task); ok { + r0 = rf(ctx, name, project, domain, filter) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*admin.Task) @@ -370,8 +372,8 @@ func (_m *AdminFetcherExtInterface) FetchTaskLatestVersion(ctx context.Context, } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok { - r1 = rf(ctx, name, project, domain) + if rf, ok := ret.Get(1).(func(context.Context, string, string, string, filters.Filters) error); ok { + r1 = rf(ctx, name, project, domain, filter) } else { r1 = ret.Error(1) } @@ -469,8 +471,8 @@ func (_m AdminFetcherExtInterface_FetchWorkflowLatestVersion) Return(_a0 *admin. return &AdminFetcherExtInterface_FetchWorkflowLatestVersion{Call: _m.Call.Return(_a0, _a1)} } -func (_m *AdminFetcherExtInterface) OnFetchWorkflowLatestVersion(ctx context.Context, name string, project string, domain string) *AdminFetcherExtInterface_FetchWorkflowLatestVersion { - c := _m.On("FetchWorkflowLatestVersion", ctx, name, project, domain) +func (_m *AdminFetcherExtInterface) OnFetchWorkflowLatestVersion(ctx context.Context, name string, project string, domain string, filter filters.Filters) *AdminFetcherExtInterface_FetchWorkflowLatestVersion { + c := _m.On("FetchWorkflowLatestVersion", ctx, name, project, domain, filter) return &AdminFetcherExtInterface_FetchWorkflowLatestVersion{Call: c} } @@ -479,13 +481,13 @@ func (_m *AdminFetcherExtInterface) OnFetchWorkflowLatestVersionMatch(matchers . return &AdminFetcherExtInterface_FetchWorkflowLatestVersion{Call: c} } -// FetchWorkflowLatestVersion provides a mock function with given fields: ctx, name, project, domain -func (_m *AdminFetcherExtInterface) FetchWorkflowLatestVersion(ctx context.Context, name string, project string, domain string) (*admin.Workflow, error) { - ret := _m.Called(ctx, name, project, domain) +// FetchWorkflowLatestVersion provides a mock function with given fields: ctx, name, project, domain, filter +func (_m *AdminFetcherExtInterface) FetchWorkflowLatestVersion(ctx context.Context, name string, project string, domain string, filter filters.Filters) (*admin.Workflow, error) { + ret := _m.Called(ctx, name, project, domain, filter) var r0 *admin.Workflow - if rf, ok := ret.Get(0).(func(context.Context, string, string, string) *admin.Workflow); ok { - r0 = rf(ctx, name, project, domain) + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, filters.Filters) *admin.Workflow); ok { + r0 = rf(ctx, name, project, domain, filter) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*admin.Workflow) @@ -493,8 +495,8 @@ func (_m *AdminFetcherExtInterface) FetchWorkflowLatestVersion(ctx context.Conte } var r1 error - if rf, ok := ret.Get(1).(func(context.Context, string, string, string) error); ok { - r1 = rf(ctx, name, project, domain) + if rf, ok := ret.Get(1).(func(context.Context, string, string, string, filters.Filters) error); ok { + r1 = rf(ctx, name, project, domain, filter) } else { r1 = ret.Error(1) } diff --git a/flytectl/pkg/ext/task_fetcher.go b/flytectl/pkg/ext/task_fetcher.go index 96984549a26..2c3366a5c0b 100644 --- a/flytectl/pkg/ext/task_fetcher.go +++ b/flytectl/pkg/ext/task_fetcher.go @@ -4,23 +4,18 @@ import ( "context" "fmt" + "github.com/flyteorg/flytectl/pkg/filters" + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/admin" "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/core" ) -func (a *AdminFetcherExtClient) FetchAllVerOfTask(ctx context.Context, name, project, domain string) ([]*admin.Task, error) { - tList, err := a.AdminServiceClient().ListTasks(ctx, &admin.ResourceListRequest{ - Id: &admin.NamedEntityIdentifier{ - Project: project, - Domain: domain, - Name: name, - }, - SortBy: &admin.Sort{ - Key: "created_at", - Direction: admin.Sort_DESCENDING, - }, - Limit: 100, - }) +func (a *AdminFetcherExtClient) FetchAllVerOfTask(ctx context.Context, name, project, domain string, filter filters.Filters) ([]*admin.Task, error) { + transformFilters, err := filters.BuildResourceListRequestWithName(filter, project, domain, name) + if err != nil { + return nil, err + } + tList, err := a.AdminServiceClient().ListTasks(ctx, transformFilters) if err != nil { return nil, err } @@ -30,12 +25,12 @@ func (a *AdminFetcherExtClient) FetchAllVerOfTask(ctx context.Context, name, pro return tList.Tasks, nil } -func (a *AdminFetcherExtClient) FetchTaskLatestVersion(ctx context.Context, name, project, domain string) (*admin.Task, error) { +func (a *AdminFetcherExtClient) FetchTaskLatestVersion(ctx context.Context, name, project, domain string, filter filters.Filters) (*admin.Task, error) { var t *admin.Task var err error // Fetch the latest version of the task. var taskVersions []*admin.Task - taskVersions, err = a.FetchAllVerOfTask(ctx, name, project, domain) + taskVersions, err = a.FetchAllVerOfTask(ctx, name, project, domain, filter) if err != nil { return nil, err } diff --git a/flytectl/pkg/ext/task_fetcher_test.go b/flytectl/pkg/ext/task_fetcher_test.go index 7f7476b2c0e..0bfc9ef8dd1 100644 --- a/flytectl/pkg/ext/task_fetcher_test.go +++ b/flytectl/pkg/ext/task_fetcher_test.go @@ -5,6 +5,8 @@ import ( "fmt" "testing" + "github.com/flyteorg/flytectl/pkg/filters" + "github.com/flyteorg/flyteidl/clients/go/admin/mocks" "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/admin" "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/core" @@ -19,6 +21,8 @@ var ( adminClient *mocks.AdminServiceClient ctx context.Context taskListResponse *admin.TaskList + taskFilter = filters.Filters{} + task1 *admin.Task ) func getTaskFetcherSetup() { @@ -90,29 +94,49 @@ func getTaskFetcherSetup() { func TestFetchAllVerOfTask(t *testing.T) { getTaskFetcherSetup() adminClient.OnListTasksMatch(mock.Anything, mock.Anything).Return(taskListResponse, nil) - _, err := adminFetcherExt.FetchAllVerOfTask(ctx, "taskName", "project", "domain") + _, err := adminFetcherExt.FetchAllVerOfTask(ctx, "taskName", "project", "domain", taskFilter) + assert.Nil(t, err) +} + +func TestFetchTaskVersion(t *testing.T) { + getTaskFetcherSetup() + adminClient.OnGetTaskMatch(mock.Anything, mock.Anything).Return(task1, nil) + _, err := adminFetcherExt.FetchTaskVersion(ctx, "task1", "v1", "project", "domain") assert.Nil(t, err) } func TestFetchAllVerOfTaskError(t *testing.T) { getTaskFetcherSetup() adminClient.OnListTasksMatch(mock.Anything, mock.Anything).Return(nil, fmt.Errorf("failed")) - _, err := adminFetcherExt.FetchAllVerOfTask(ctx, "taskName", "project", "domain") + _, err := adminFetcherExt.FetchAllVerOfTask(ctx, "taskName", "project", "domain", taskFilter) assert.Equal(t, fmt.Errorf("failed"), err) } +func TestFetchAllVerOfTaskFilterError(t *testing.T) { + getTaskFetcherSetup() + taskFilter = filters.Filters{ + FieldSelector: "hello=", + } + adminClient.OnListTasksMatch(mock.Anything, mock.Anything).Return(nil, fmt.Errorf("failed")) + _, err := adminFetcherExt.FetchAllVerOfTask(ctx, "taskName", "project", "domain", taskFilter) + assert.NotNil(t, err) +} + func TestFetchAllVerOfTaskEmptyResponse(t *testing.T) { taskListResponse := &admin.TaskList{} getTaskFetcherSetup() + taskFilter = filters.Filters{ + FieldSelector: "", + } adminClient.OnListTasksMatch(mock.Anything, mock.Anything).Return(taskListResponse, nil) - _, err := adminFetcherExt.FetchAllVerOfTask(ctx, "taskName", "project", "domain") + _, err := adminFetcherExt.FetchAllVerOfTask(ctx, "taskName", "project", "domain", taskFilter) assert.Equal(t, fmt.Errorf("no tasks retrieved for taskName"), err) } func TestFetchTaskLatestVersion(t *testing.T) { getTaskFetcherSetup() adminClient.OnListTasksMatch(mock.Anything, mock.Anything).Return(taskListResponse, nil) - _, err := adminFetcherExt.FetchTaskLatestVersion(ctx, "taskName", "project", "domain") + _, err := adminFetcherExt.FetchTaskLatestVersion(ctx, "taskName", "project", "domain", taskFilter) assert.Nil(t, err) } @@ -120,6 +144,6 @@ func TestFetchTaskLatestVersionError(t *testing.T) { taskListResponse := &admin.TaskList{} getTaskFetcherSetup() adminClient.OnListTasksMatch(mock.Anything, mock.Anything).Return(taskListResponse, nil) - _, err := adminFetcherExt.FetchTaskLatestVersion(ctx, "taskName", "project", "domain") + _, err := adminFetcherExt.FetchTaskLatestVersion(ctx, "taskName", "project", "domain", taskFilter) assert.Equal(t, fmt.Errorf("no tasks retrieved for taskName"), err) } diff --git a/flytectl/pkg/ext/updater_test.go b/flytectl/pkg/ext/updater_test.go new file mode 100644 index 00000000000..6e692c44cf7 --- /dev/null +++ b/flytectl/pkg/ext/updater_test.go @@ -0,0 +1,17 @@ +package ext + +import ( + "testing" + + "github.com/flyteorg/flyteidl/clients/go/admin/mocks" + "github.com/stretchr/testify/assert" +) + +var updaterFetcherClient *AdminUpdaterExtClient + +func TestAdminUpdaterExtClient_AdminServiceClient(t *testing.T) { + adminClient = new(mocks.AdminServiceClient) + updaterFetcherClient = nil + client := updaterFetcherClient.AdminServiceClient() + assert.Nil(t, client) +} diff --git a/flytectl/pkg/ext/workflow_fetcher.go b/flytectl/pkg/ext/workflow_fetcher.go index 86fe88abda6..734298a5d4c 100644 --- a/flytectl/pkg/ext/workflow_fetcher.go +++ b/flytectl/pkg/ext/workflow_fetcher.go @@ -4,24 +4,19 @@ import ( "context" "fmt" + "github.com/flyteorg/flytectl/pkg/filters" + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/admin" "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/core" ) // FetchAllVerOfWorkflow fetches all the versions for give workflow name -func (a *AdminFetcherExtClient) FetchAllVerOfWorkflow(ctx context.Context, workflowName, project, domain string) ([]*admin.Workflow, error) { - wList, err := a.AdminServiceClient().ListWorkflows(ctx, &admin.ResourceListRequest{ - Id: &admin.NamedEntityIdentifier{ - Project: project, - Domain: domain, - Name: workflowName, - }, - SortBy: &admin.Sort{ - Key: "created_at", - Direction: admin.Sort_DESCENDING, - }, - Limit: 100, - }) +func (a *AdminFetcherExtClient) FetchAllVerOfWorkflow(ctx context.Context, workflowName, project, domain string, filter filters.Filters) ([]*admin.Workflow, error) { + tranformFilters, err := filters.BuildResourceListRequestWithName(filter, project, domain, workflowName) + if err != nil { + return nil, err + } + wList, err := a.AdminServiceClient().ListWorkflows(ctx, tranformFilters) if err != nil { return nil, err } @@ -32,9 +27,9 @@ func (a *AdminFetcherExtClient) FetchAllVerOfWorkflow(ctx context.Context, workf } // FetchWorkflowLatestVersion fetches latest version for given workflow name -func (a *AdminFetcherExtClient) FetchWorkflowLatestVersion(ctx context.Context, name, project, domain string) (*admin.Workflow, error) { +func (a *AdminFetcherExtClient) FetchWorkflowLatestVersion(ctx context.Context, name, project, domain string, filter filters.Filters) (*admin.Workflow, error) { // Fetch the latest version of the workflow. - wVersions, err := a.FetchAllVerOfWorkflow(ctx, name, project, domain) + wVersions, err := a.FetchAllVerOfWorkflow(ctx, name, project, domain, filter) if err != nil { return nil, err } diff --git a/flytectl/pkg/ext/workflow_fetcher_test.go b/flytectl/pkg/ext/workflow_fetcher_test.go index c18d04842aa..9ae96612a61 100644 --- a/flytectl/pkg/ext/workflow_fetcher_test.go +++ b/flytectl/pkg/ext/workflow_fetcher_test.go @@ -5,6 +5,8 @@ import ( "fmt" "testing" + "github.com/flyteorg/flytectl/pkg/filters" + "github.com/flyteorg/flyteidl/clients/go/admin/mocks" "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/admin" "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/core" @@ -16,6 +18,7 @@ import ( var ( workflowListResponse *admin.WorkflowList + workflowFilter = filters.Filters{} workflowResponse *admin.Workflow ) @@ -87,14 +90,14 @@ func getWorkflowFetcherSetup() { func TestFetchAllVerOfWorkflow(t *testing.T) { getWorkflowFetcherSetup() adminClient.OnListWorkflowsMatch(mock.Anything, mock.Anything).Return(workflowListResponse, nil) - _, err := adminFetcherExt.FetchAllVerOfWorkflow(ctx, "workflowName", "project", "domain") + _, err := adminFetcherExt.FetchAllVerOfWorkflow(ctx, "workflowName", "project", "domain", workflowFilter) assert.Nil(t, err) } func TestFetchAllVerOfWorkflowError(t *testing.T) { getWorkflowFetcherSetup() adminClient.OnListWorkflowsMatch(mock.Anything, mock.Anything).Return(nil, fmt.Errorf("failed")) - _, err := adminFetcherExt.FetchAllVerOfWorkflow(ctx, "workflowName", "project", "domain") + _, err := adminFetcherExt.FetchAllVerOfWorkflow(ctx, "workflowName", "project", "domain", workflowFilter) assert.Equal(t, fmt.Errorf("failed"), err) } @@ -102,7 +105,7 @@ func TestFetchAllVerOfWorkflowEmptyResponse(t *testing.T) { workflowListResponse := &admin.WorkflowList{} getWorkflowFetcherSetup() adminClient.OnListWorkflowsMatch(mock.Anything, mock.Anything).Return(workflowListResponse, nil) - _, err := adminFetcherExt.FetchAllVerOfWorkflow(ctx, "workflowName", "project", "domain") + _, err := adminFetcherExt.FetchAllVerOfWorkflow(ctx, "workflowName", "project", "domain", workflowFilter) assert.Equal(t, fmt.Errorf("no workflow retrieved for workflowName"), err) } @@ -110,7 +113,7 @@ func TestFetchWorkflowLatestVersion(t *testing.T) { getWorkflowFetcherSetup() adminClient.OnGetWorkflowMatch(mock.Anything, mock.Anything).Return(workflowResponse, nil) adminClient.OnListWorkflowsMatch(mock.Anything, mock.Anything).Return(workflowListResponse, nil) - _, err := adminFetcherExt.FetchWorkflowLatestVersion(ctx, "workflowName", "project", "domain") + _, err := adminFetcherExt.FetchWorkflowLatestVersion(ctx, "workflowName", "project", "domain", workflowFilter) assert.Nil(t, err) } @@ -118,7 +121,6 @@ func TestFetchWorkflowLatestVersionError(t *testing.T) { workflowListResponse := &admin.WorkflowList{} getWorkflowFetcherSetup() adminClient.OnListWorkflowsMatch(mock.Anything, mock.Anything).Return(workflowListResponse, nil) - adminClient.OnGetWorkflowMatch(mock.Anything, mock.Anything).Return(workflowResponse, nil) - _, err := adminFetcherExt.FetchWorkflowLatestVersion(ctx, "workflowName", "project", "domain") + _, err := adminFetcherExt.FetchWorkflowLatestVersion(ctx, "workflowName", "project", "domain", workflowFilter) assert.Equal(t, fmt.Errorf("no workflow retrieved for workflowName"), err) } diff --git a/flytectl/pkg/filters/coverage.out b/flytectl/pkg/filters/coverage.out new file mode 100644 index 00000000000..937e698b182 --- /dev/null +++ b/flytectl/pkg/filters/coverage.out @@ -0,0 +1,68 @@ +mode: set +github.com/flyteorg/flytectl/pkg/filters/filters.go:18.41,19.18 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:22.2,22.19 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:19.18,21.3 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:26.50,28.28 2 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:47.2,47.25 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:28.28,29.39 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:29.39,31.18 2 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:34.4,34.36 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:31.18,33.5 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:34.36,36.29 2 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:36.29,38.6 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:38.11,40.6 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:41.10,44.5 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:51.37,53.34 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:56.2,56.14 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:53.34,55.3 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:64.47,66.2 1 0 +github.com/flyteorg/flytectl/pkg/filters/filters.go:70.46,72.36 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:76.2,78.22 3 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:104.2,104.13 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:108.2,108.24 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:72.36,74.3 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:78.22,79.14 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:92.3,92.12 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:79.14,80.13 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:88.4,89.12 2 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:81.24,83.19 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:84.12,86.72 1 0 +github.com/flyteorg/flytectl/pkg/filters/filters.go:93.13,94.18 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:95.17,97.34 1 0 +github.com/flyteorg/flytectl/pkg/filters/filters.go:98.11,99.18 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:104.13,106.3 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:116.39,118.2 1 0 +github.com/flyteorg/flytectl/pkg/filters/filters.go:121.58,122.24 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:144.2,144.26 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:122.24,125.36 3 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:125.36,126.22 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:126.22,127.40 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:127.40,130.6 2 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:131.10,131.23 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:131.23,132.34 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:132.34,136.6 3 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:137.10,138.41 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:138.41,140.6 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:148.44,149.12 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:167.2,167.11 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:150.25,151.45 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:152.22,153.45 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:154.19,155.44 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:156.16,157.44 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:158.16,159.50 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:160.17,161.44 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:162.14,163.44 1 1 +github.com/flyteorg/flytectl/pkg/filters/filters.go:164.10,165.50 1 1 +github.com/flyteorg/flytectl/pkg/filters/util.go:7.116,9.16 2 1 +github.com/flyteorg/flytectl/pkg/filters/util.go:12.2,20.19 2 1 +github.com/flyteorg/flytectl/pkg/filters/util.go:23.2,23.49 1 1 +github.com/flyteorg/flytectl/pkg/filters/util.go:26.2,26.21 1 1 +github.com/flyteorg/flytectl/pkg/filters/util.go:9.16,11.3 1 1 +github.com/flyteorg/flytectl/pkg/filters/util.go:20.19,22.3 1 1 +github.com/flyteorg/flytectl/pkg/filters/util.go:23.49,25.3 1 1 +github.com/flyteorg/flytectl/pkg/filters/util.go:29.76,31.16 2 1 +github.com/flyteorg/flytectl/pkg/filters/util.go:34.2,39.21 2 1 +github.com/flyteorg/flytectl/pkg/filters/util.go:31.16,33.3 1 1 +github.com/flyteorg/flytectl/pkg/filters/util.go:42.49,44.11 2 1 +github.com/flyteorg/flytectl/pkg/filters/util.go:47.2,50.3 1 1 +github.com/flyteorg/flytectl/pkg/filters/util.go:44.11,46.3 1 1 diff --git a/flytectl/pkg/filters/filters.go b/flytectl/pkg/filters/filters.go new file mode 100644 index 00000000000..629b6a25c8a --- /dev/null +++ b/flytectl/pkg/filters/filters.go @@ -0,0 +1,168 @@ +package filters + +import ( + "bytes" + "fmt" + "regexp" + "strings" +) + +var ( + InReg = regexp.MustCompile(` in `) + ContainsReg = regexp.MustCompile(` contains `) + InRegValue = regexp.MustCompile(`(?s)\((.*)\)`) + termOperators = []string{NotEquals, Equals, GreaterThanEquals, GreaterThan, LessThanEquals, LessThan, Contains, In} +) + +// SplitTerms split the filter string and returns the map of strings +func SplitTerms(filter string) []string { + if filter != "" { + return strings.Split(filter, ",") + } + return []string{} +} + +// Transform transform the field selector term from string to flyteadmin field selector syntax +func Transform(filters []string) (string, error) { + adminFilter := "" + for _, f := range filters { + if lhs, op, rhs, ok := parse(f); ok { + unescapedRHS, err := UnescapeValue(rhs) + if err != nil { + return "", err + } + if ok := validate(lhs, rhs); ok { + transformFilter := transform(lhs, op, unescapedRHS) + if len(adminFilter) > 0 { + adminFilter = fmt.Sprintf("%v+%v", adminFilter, transformFilter) + } else { + adminFilter = fmt.Sprintf("%v", transformFilter) + } + } else { + // TODO(Yuvraj): Add filters docs in error + return "", fmt.Errorf("Please add a valid field selector") + } + } + } + return adminFilter, nil +} + +// validate validate the field selector operation +func validate(lhs, rhs string) bool { + // TODO Add Validation check with regular expression + if len(lhs) > 0 && len(rhs) > 0 { + return true + } + return false +} + +// InvalidEscapeSequence indicates an error occurred unescaping a field selector +type InvalidEscapeSequence struct { + sequence string +} + +func (i InvalidEscapeSequence) Error() string { + return fmt.Sprintf("invalid field selector: invalid escape sequence: %s", i.sequence) +} + +// UnescapeValue unescapes a fieldSelector value and returns the original literal value. +// May return the original string if it contains no escaped or special characters. +func UnescapeValue(s string) (string, error) { + // if there's no escaping or special characters, just return to avoid allocation + if !strings.ContainsAny(s, `\,=`) { + return s, nil + } + + v := bytes.NewBuffer(make([]byte, 0, len(s))) + inSlash := false + for _, c := range s { + if inSlash { + switch c { + case '\\', ',', '=': + // omit the \ for recognized escape sequences + v.WriteRune(c) + default: + // error on unrecognized escape sequences + return "", InvalidEscapeSequence{sequence: string([]rune{'\\', c})} + } + inSlash = false + continue + } + + switch c { + case '\\': + inSlash = true + case ',', '=': + // unescaped , and = characters are not allowed in field selector values + return "", UnescapedRune{r: c} + default: + v.WriteRune(c) + } + } + + // Ending with a single backslash is an invalid sequence + if inSlash { + return "", InvalidEscapeSequence{sequence: "\\"} + } + + return v.String(), nil +} + +// UnescapedRune indicates an error occurred unescaping a field selector +type UnescapedRune struct { + r rune +} + +func (i UnescapedRune) Error() string { + return fmt.Sprintf("invalid field selector: unescaped character in value: %v", i.r) +} + +// parse parse the filter string into an operation string and return the lhs,rhs value and operation type +func parse(filter string) (lhs, op, rhs string, ok bool) { + for i := range filter { + remaining := filter[i:] + var results []string + for _, op := range termOperators { + if op == Contains { + if ContainsReg.MatchString(filter) { + results = ContainsReg.Split(filter, 2) + return results[0], op, results[1], true + } + } else if op == In { + if InReg.MatchString(filter) { + results = InReg.Split(filter, 2) + values := InRegValue.FindAllStringSubmatch(strings.TrimSpace(results[1]), -1) + return results[0], op, values[0][1], true + } + } else { + if strings.HasPrefix(remaining, op) { + return filter[0:i], op, filter[i+len(op):], true + } + } + } + } + return "", "", "", false +} + +// transform it transform the field selector operation and return flyteadmin filter syntax +func transform(lhs, op, rhs string) string { + switch op { + case GreaterThanEquals: + return fmt.Sprintf("gte(%v,%v)", lhs, rhs) + case LessThanEquals: + return fmt.Sprintf("lte(%v,%v)", lhs, rhs) + case GreaterThan: + return fmt.Sprintf("gt(%v,%v)", lhs, rhs) + case LessThan: + return fmt.Sprintf("lt(%v,%v)", lhs, rhs) + case Contains: + return fmt.Sprintf("contains(%v,%v)", lhs, rhs) + case NotEquals: + return fmt.Sprintf("ne(%v,%v)", lhs, rhs) + case Equals: + return fmt.Sprintf("eq(%v,%v)", lhs, rhs) + case In: + return fmt.Sprintf("value_in(%v,%v)", lhs, rhs) + } + return "" +} diff --git a/flytectl/pkg/filters/filters_test.go b/flytectl/pkg/filters/filters_test.go new file mode 100644 index 00000000000..cd988f0c58f --- /dev/null +++ b/flytectl/pkg/filters/filters_test.go @@ -0,0 +1,73 @@ +package filters + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +type TestCase struct { + Input string `json:"input"` + Output string `json:"output"` +} + +func TestTransformFilter(t *testing.T) { + tests := []TestCase{ + { + Input: "project.name=flytesnacks,execution.duration<200,execution.duration<=200,execution.duration>=200,name contains flyte,name!=flyte", + Output: "eq(project.name,flytesnacks)+lt(execution.duration,200)+lte(execution.duration,200)+gte(execution.duration,200)+contains(name,flyte)+ne(name,flyte)", + }, + { + Input: "execution.phase in (FAILED;SUCCEEDED),execution.name=y8n2wtuspj,execution.duration>200", + Output: "value_in(execution.phase,FAILED;SUCCEEDED)+eq(execution.name,y8n2wtuspj)+gt(execution.duration,200)", + }, + { + Input: `k=\\,,k2=v2`, + Output: "eq(k,\\)+eq(k2,v2)", + }, + } + for _, test := range tests { + filters := SplitTerms(test.Input) + + result, err := Transform(filters) + assert.Nil(t, err) + assert.Equal(t, test.Output, result) + } +} + +func TestTransformFilterError(t *testing.T) { + tests := []TestCase{ + { + Input: `\=\,\`, + Output: "", + }, + { + Input: `foo=bar,baz=blah,complex=\=value\\\,\\`, + Output: "", + }, + } + for _, test := range tests { + filters := SplitTerms(test.Input) + result, err := Transform(filters) + assert.NotNil(t, err) + assert.Equal(t, "", result) + } +} + +func TestParseFailed(t *testing.T) { + tests := []TestCase{ + { + Input: ``, + Output: "", + }, + } + for _, test := range tests { + lhs, op, rhs, ok := parse(test.Input) + result := transform(lhs, op, rhs) + assert.Equal(t, "", result) + assert.Equal(t, false, ok) + assert.Equal(t, "", lhs) + assert.Equal(t, "", rhs) + assert.Equal(t, "", op) + } +} diff --git a/flytectl/pkg/filters/operator.go b/flytectl/pkg/filters/operator.go new file mode 100644 index 00000000000..37d8c94d2ee --- /dev/null +++ b/flytectl/pkg/filters/operator.go @@ -0,0 +1,12 @@ +package filters + +const ( + Equals string = "=" + In string = "in" + Contains string = "contains" + NotEquals string = "!=" + GreaterThan string = ">" + GreaterThanEquals string = ">=" + LessThan string = "<" + LessThanEquals string = "<=" +) diff --git a/flytectl/pkg/filters/type.go b/flytectl/pkg/filters/type.go new file mode 100644 index 00000000000..83b7d18a746 --- /dev/null +++ b/flytectl/pkg/filters/type.go @@ -0,0 +1,17 @@ +package filters + +var ( + DefaultLimit int32 = 100 + DefaultFilter = Filters{ + Limit: DefaultLimit, + Asc: false, + } +) + +type Filters struct { + FieldSelector string `json:"field-selector" pflag:",Specifies the Field selector"` + SortBy string `json:"sort-by" pflag:",Specifies which field to sort results "` + // TODO: Support paginated queries + Limit int32 `json:"limit" pflag:",Specifies the limit"` + Asc bool `json:"asc" pflag:",Specifies the sorting order. By default flytectl sort result in descending order"` +} diff --git a/flytectl/pkg/filters/util.go b/flytectl/pkg/filters/util.go new file mode 100644 index 00000000000..2c2515326a8 --- /dev/null +++ b/flytectl/pkg/filters/util.go @@ -0,0 +1,54 @@ +package filters + +import ( + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/admin" +) + +func BuildResourceListRequestWithName(c Filters, project, domain, name string) (*admin.ResourceListRequest, error) { + fieldSelector, err := Transform(SplitTerms(c.FieldSelector)) + if err != nil { + return nil, err + } + request := &admin.ResourceListRequest{ + Limit: uint32(c.Limit), + Filters: fieldSelector, + Id: &admin.NamedEntityIdentifier{ + Project: project, + Domain: domain, + }, + } + if len(name) > 0 { + request.Id.Name = name + } + if sort := buildSortingRequest(c); sort != nil { + request.SortBy = sort + } + return request, nil +} + +func BuildProjectListRequest(c Filters) (*admin.ProjectListRequest, error) { + fieldSelector, err := Transform(SplitTerms(c.FieldSelector)) + if err != nil { + return nil, err + } + request := &admin.ProjectListRequest{ + Limit: uint32(c.Limit), + Filters: fieldSelector, + SortBy: buildSortingRequest(c), + } + return request, nil +} + +func buildSortingRequest(c Filters) *admin.Sort { + sortingOrder := admin.Sort_DESCENDING + if c.Asc { + sortingOrder = admin.Sort_ASCENDING + } + if len(c.SortBy) > 0 { + return &admin.Sort{ + Key: c.SortBy, + Direction: sortingOrder, + } + } + return nil +} diff --git a/flytectl/pkg/filters/util_test.go b/flytectl/pkg/filters/util_test.go new file mode 100644 index 00000000000..6edcc797863 --- /dev/null +++ b/flytectl/pkg/filters/util_test.go @@ -0,0 +1,111 @@ +package filters + +import ( + "testing" + + "github.com/flyteorg/flytectl/cmd/config" + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/admin" + "github.com/stretchr/testify/assert" +) + +var ( + project = "flytesnack" + domain = "staging" + name = "test" + output = "json" +) + +func TestListRequestWithoutNameFunc(t *testing.T) { + config.GetConfig().Output = output + config.GetConfig().Project = project + config.GetConfig().Domain = domain + filter := Filters{ + Limit: 100, + SortBy: "created_at", + Asc: true, + } + request, err := BuildResourceListRequestWithName(filter, project, domain, "") + expectedResponse := &admin.ResourceListRequest{ + Id: &admin.NamedEntityIdentifier{ + Project: project, + Domain: domain, + }, + Limit: 100, + SortBy: &admin.Sort{ + Key: "created_at", + Direction: admin.Sort_ASCENDING, + }, + Filters: "", + } + assert.Nil(t, err) + assert.Equal(t, expectedResponse, request) +} + +func TestProjectListRequestFunc(t *testing.T) { + config.GetConfig().Output = output + config.GetConfig().Project = project + config.GetConfig().Domain = domain + filter := Filters{ + Limit: 100, + SortBy: "created_at", + } + request, err := BuildProjectListRequest(filter) + expectedResponse := &admin.ProjectListRequest{ + Limit: 100, + Filters: "", + SortBy: &admin.Sort{ + Key: "created_at", + Direction: admin.Sort_DESCENDING, + }, + } + assert.Nil(t, err) + assert.Equal(t, expectedResponse, request) +} + +func TestProjectListWithRequestFuncError(t *testing.T) { + config.GetConfig().Output = output + config.GetConfig().Project = project + config.GetConfig().Domain = domain + filter := Filters{ + FieldSelector: "Hello=", + Limit: 100, + } + request, err := BuildProjectListRequest(filter) + assert.NotNil(t, err) + assert.Nil(t, request) +} + +func TestListRequestWithNameFunc(t *testing.T) { + config.GetConfig().Output = output + filter := Filters{ + Limit: 100, + SortBy: "created_at", + } + request, err := BuildResourceListRequestWithName(filter, project, domain, name) + expectedResponse := &admin.ResourceListRequest{ + Id: &admin.NamedEntityIdentifier{ + Project: project, + Domain: domain, + Name: name, + }, + Limit: 100, + SortBy: &admin.Sort{ + Key: "created_at", + Direction: admin.Sort_DESCENDING, + }, + } + assert.Nil(t, err) + assert.Equal(t, expectedResponse, request) +} + +func TestListRequestWithNameFuncError(t *testing.T) { + config.GetConfig().Output = output + filter := Filters{ + Limit: 100, + SortBy: "created_at", + FieldSelector: "hello=", + } + request, err := BuildResourceListRequestWithName(filter, project, domain, name) + assert.NotNil(t, err) + assert.Nil(t, request) +}