Skip to content

Commit

Permalink
allow to list only certain resource types
Browse files Browse the repository at this point in the history
This allows to only show certain resource types when listing all
existing resources. It helps in finding resources without the need for a
specific nctl implementation.
  • Loading branch information
thirdeyenick committed Jul 23, 2024
1 parent c29ba6a commit 2daaa85
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 21 deletions.
35 changes: 30 additions & 5 deletions get/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
}
Expand Down Expand Up @@ -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
Expand All @@ -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
}
Expand Down Expand Up @@ -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() {
Expand Down
78 changes: 62 additions & 16 deletions get/all_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down Expand Up @@ -64,32 +66,32 @@ 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": {
projects: test.Projects(organization, "dev", "staging", "prod"),
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": {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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())
})
}
Expand Down

0 comments on commit 2daaa85

Please sign in to comment.