diff --git a/get/all.go b/get/all.go index f68107f..d5fb565 100644 --- a/get/all.go +++ b/get/all.go @@ -22,7 +22,8 @@ import ( type allCmd struct { out io.Writer stdErr io.Writer - IncludeNineResources bool `help:"show resources which are owned by Nine" default:"false"` + Kinds []string `help:"specify the kind of resources which should be listed"` + IncludeNineResources bool `help:"show resources which are owned by Nine" default:"false"` } func (cmd *allCmd) Run(ctx context.Context, client *api.Client, get *Cmd) error { @@ -35,7 +36,7 @@ func (cmd *allCmd) Run(ctx context.Context, client *api.Client, get *Cmd) error return err } - items, warnings, err := getProjectContent(ctx, client, projectNames(projectList), cmd.IncludeNineResources) + items, warnings, err := cmd.getProjectContent(ctx, client, projectNames(projectList)) if err != nil { return err } @@ -70,11 +71,15 @@ func projectNames(projects []management.Project) []string { return result } -func getProjectContent(ctx context.Context, client *api.Client, projNames []string, includeNineOwned bool) ([]*unstructured.Unstructured, []string, error) { +func (cmd *allCmd) getProjectContent(ctx context.Context, client *api.Client, projNames []string) ([]*unstructured.Unstructured, []string, error) { var warnings []string var result []*unstructured.Unstructured + listTypes, err := filteredListTypes(client.Scheme(), cmd.Kinds) + if err != nil { + return nil, nil, err + } for _, project := range projNames { - for _, listType := range nineListTypes(client.Scheme()) { + for _, listType := range listTypes { u := &unstructured.UnstructuredList{} u.SetGroupVersionKind(listType) // if we get any errors during the listing of certain @@ -89,7 +94,7 @@ func getProjectContent(ctx context.Context, client *api.Client, projNames []stri // filter nine owned resources if needed for _, item := range u.Items { item := item - if includeNineOwned { + if cmd.IncludeNineResources { result = append(result, &item) continue } @@ -134,6 +139,26 @@ func printItems(items []*unstructured.Unstructured, get Cmd, out io.Writer, head return w.Flush() } +func filteredListTypes(s *runtime.Scheme, kinds []string) ([]schema.GroupVersionKind, error) { + result := []schema.GroupVersionKind{} + lists := nineListTypes(s) + if len(kinds) == 0 { + return lists, nil + } +OUTER: + for _, kind := range kinds { + for _, list := range lists { + if !strings.EqualFold(kind+"list", list.GroupKind().Kind) { + continue + } + result = append(result, list) + continue OUTER + } + return []schema.GroupVersionKind{}, fmt.Errorf("kind %s does not seem to be part of any nine.ch API", kind) + } + return result, nil +} + func nineListTypes(s *runtime.Scheme) []schema.GroupVersionKind { var lists []schema.GroupVersionKind for gvk := range s.AllKnownTypes() { diff --git a/get/all_test.go b/get/all_test.go index 9a4b93e..4745613 100644 --- a/get/all_test.go +++ b/get/all_test.go @@ -31,7 +31,9 @@ func TestAllContent(t *testing.T) { outputFormat output allProjects bool includeNineResources bool + kinds []string output string + errorExpected bool }{ "all resources from one project, full format": { projects: test.Projects(organization, "dev", "staging", "prod"), @@ -64,16 +66,16 @@ dev pear Release apps.nine.ch objects: []client.Object{ testApplication("banana", "dev"), testRelease("pear", "dev"), testApplication("apple", "staging"), testRelease("melon", "staging"), - testCluster("organge", "prod"), + testCluster("orange", "prod"), }, outputFormat: full, allProjects: true, - output: `PROJECT NAME KIND GROUP -dev banana Application apps.nine.ch -dev pear Release apps.nine.ch -prod organge KubernetesCluster infrastructure.nine.ch -staging apple Application apps.nine.ch -staging melon Release apps.nine.ch + output: `PROJECT NAME KIND GROUP +dev banana Application apps.nine.ch +dev pear Release apps.nine.ch +prod orange KubernetesCluster infrastructure.nine.ch +staging apple Application apps.nine.ch +staging melon Release apps.nine.ch `, }, "all projects, no headers format": { @@ -81,15 +83,15 @@ staging melon Release apps.nine.ch objects: []client.Object{ testApplication("banana", "dev"), testRelease("pear", "dev"), testApplication("apple", "staging"), testRelease("melon", "staging"), - testCluster("organge", "prod"), + testCluster("orange", "prod"), }, outputFormat: noHeader, allProjects: true, - output: `dev banana Application apps.nine.ch -dev pear Release apps.nine.ch -prod organge KubernetesCluster infrastructure.nine.ch -staging apple Application apps.nine.ch -staging melon Release apps.nine.ch + output: `dev banana Application apps.nine.ch +dev pear Release apps.nine.ch +prod orange KubernetesCluster infrastructure.nine.ch +staging apple Application apps.nine.ch +staging melon Release apps.nine.ch `, }, "empty resources of a specific project, full format": { @@ -156,6 +158,47 @@ staging cherry Release apps.nine.ch staging melon Release apps.nine.ch `, }, + "only certain kind": { + projects: test.Projects(organization, "dev", "staging", "prod"), + objects: []client.Object{ + testApplication("banana", "dev"), testRelease("pear", "dev"), + testApplication("apple", "staging"), testRelease("melon", "staging"), testRelease("cherry", "staging"), + testCluster("orange", "prod"), + }, + outputFormat: full, + allProjects: true, + kinds: []string{"application"}, + output: `PROJECT NAME KIND GROUP +dev banana Application apps.nine.ch +staging apple Application apps.nine.ch +`, + }, + "multiple certain kinds, no header format": { + projects: test.Projects(organization, "dev", "staging", "prod"), + objects: []client.Object{ + testApplication("banana", "dev"), testRelease("pear", "dev"), + testApplication("apple", "staging"), testRelease("melon", "staging"), testRelease("cherry", "staging"), + testCluster("orange", "prod"), + testCluster("dragonfruit", "dev"), + }, + outputFormat: noHeader, + allProjects: true, + kinds: []string{"release", "kubernetescluster"}, + output: `dev dragonfruit KubernetesCluster infrastructure.nine.ch +dev pear Release apps.nine.ch +prod orange KubernetesCluster infrastructure.nine.ch +staging cherry Release apps.nine.ch +staging melon Release apps.nine.ch +`, + }, + "not known kind leads to an error": { + projects: test.Projects(organization, "dev", "staging", "prod"), + objects: []client.Object{}, + outputFormat: noHeader, + allProjects: true, + kinds: []string{"jackofalltrades"}, + errorExpected: true, + }, } { t.Run(name, func(t *testing.T) { testCase := testCase @@ -186,12 +229,15 @@ staging melon Release apps.nine.ch cmd := allCmd{ out: outputBuffer, IncludeNineResources: testCase.includeNineResources, + Kinds: testCase.kinds, } - if err := cmd.Run(ctx, apiClient, get); err != nil { - t.Fatal(err) + err = cmd.Run(ctx, apiClient, get) + if testCase.errorExpected { + require.Error(t, err) + return } - + require.NoError(t, err) assert.Equal(t, testCase.output, outputBuffer.String()) }) }