diff --git a/.travis.yml b/.travis.yml index ac2f983..02c71b5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,8 +15,8 @@ script: - make dev - make coverage -#after_success: -# - bash <(curl -s https://codecov.io/bash) +after_success: + - bash <(curl -s https://codecov.io/bash) before_deploy: - make deploy diff --git a/cmd/root.go b/cmd/root.go index f90a7c0..88282d0 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -42,16 +42,23 @@ Like 'kubectl get all', but get _really_ all resources Ketall retrieves all resources which allow to be fetched. This complements the usual "kubectl get all" command, which excludes all cluster-level and some namespaced resources. + +More on https://github.com/corneliusweig/ketall/blob/v0.0.2/doc/USAGE.md ` ketallExamples = ` - Get all resources + Get all resources, excluding events $ ketall + Get all resources, including events + $ ketall --exclude= + Get all cluster level resources $ ketall --only-scope=cluster Get all resources in a particular namespace $ ketall --only-scope=namespace --namespace= + + Some options can also be configured in the config file 'ketall' ` ) @@ -80,6 +87,7 @@ func init() { rootCmd.Flags().BoolVar(&ketallOptions.UseCache, constants.FlagUseCache, false, "use cached list of server resources") rootCmd.Flags().StringVar(&ketallOptions.Scope, constants.FlagScope, "", "only resources with scope cluster|namespace") + rootCmd.Flags().StringSliceVar(&ketallOptions.Exclusions, constants.FlagExclude, []string{"events"}, "filter by resource name (plural form or short name)") ketallOptions.GenericCliFlags.AddFlags(rootCmd.Flags()) ketallOptions.PrintFlags.AddFlags(rootCmd) diff --git a/doc/USAGE.md b/doc/USAGE.md index 02b3d93..1265afe 100644 --- a/doc/USAGE.md +++ b/doc/USAGE.md @@ -64,6 +64,10 @@ The following settings can be configured: only-scope: cluster namespace: default use-cache: true +# only plural form or abbreviations +exclude: +- componentstatuses +- cm # configmaps ``` ## Installation diff --git a/pkg/client/client.go b/pkg/client/client.go index 8b87e87..ce53348 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -20,6 +20,7 @@ import ( "fmt" "github.com/corneliusweig/ketall/pkg/constants" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "github.com/spf13/viper" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -42,11 +43,13 @@ func GetAllServerResources(flags *genericclioptions.ConfigFlags) (runtime.Object useCache := viper.GetBool(constants.FlagUseCache) scope := viper.GetString(constants.FlagScope) - resNames, err := FetchAvailableResourceNames(useCache, scope, flags) + grs, err := FetchAvailableGroupResources(useCache, scope, flags) if err != nil { - return nil, errors.Wrap(err, "fetch available resources") + return nil, errors.Wrap(err, "fetch available group resources") } + resNames := extractRelevantResourceNames(grs, viper.GetStringSlice(constants.FlagExclude)) + request := resource.NewBuilder(flags). Unstructured(). SelectAllParam(true). @@ -70,7 +73,7 @@ func GetAllServerResources(flags *genericclioptions.ConfigFlags) (runtime.Object return response.Object() } -func FetchAvailableResourceNames(cache bool, scope string, flags *genericclioptions.ConfigFlags) ([]string, error) { +func FetchAvailableGroupResources(cache bool, scope string, flags *genericclioptions.ConfigFlags) ([]groupResource, error) { client, err := flags.ToDiscoveryClient() if err != nil { return nil, errors.Wrap(err, "discovery client") @@ -120,13 +123,27 @@ func FetchAvailableResourceNames(cache bool, scope string, flags *genericcliopti } } + return grs, nil +} + +func extractRelevantResourceNames(grs []groupResource, exclusions []string) []string { sort.Stable(sortableGroupResource(grs)) + forbidden := sets.NewString(exclusions...) + result := []string{} for _, r := range grs { - result = append(result, r.fullName()) + name := r.fullName() + resourceIds := r.APIResource.ShortNames + resourceIds = append(resourceIds, r.APIResource.Name) + if forbidden.HasAny(resourceIds...) { + logrus.Debugf("Excluding %s", name) + continue + } + result = append(result, name) } - return result, nil + logrus.Debugf("Resources to fetch: %s", result) + return result } func getResourceScope(scope string) (skipCluster, skipNamespace bool, err error) { diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go new file mode 100644 index 0000000..5ac42da --- /dev/null +++ b/pkg/client/client_test.go @@ -0,0 +1,81 @@ +/* +Copyright 2019 Cornelius Weig + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package client + +import ( + "github.com/stretchr/testify/assert" + "k8s.io/apimachinery/pkg/apis/meta/v1" + "testing" +) + +func TestExtractRelevantResourceNames(t *testing.T) { + var tests = []struct { + testName string + resources []v1.APIResource + groups []string + exclude []string + expected []string + }{ + { + testName: "a single resource", + resources: []v1.APIResource{{Name: "foo"}}, + groups: []string{"group"}, + expected: []string{"foo.group"}, + }, + { + testName: "two resources, without group", + resources: []v1.APIResource{{Name: "foo"}, {Name: "bar"}}, + groups: []string{"group", ""}, + expected: []string{"bar", "foo.group"}, + }, + { + testName: "two resources, same group", + resources: []v1.APIResource{{Name: "foo"}, {Name: "bar"}}, + groups: []string{"group", "group"}, + expected: []string{"bar.group", "foo.group"}, + }, + { + testName: "two filtered by Name", + resources: []v1.APIResource{{Name: "foo"}, {Name: "bar"}}, + groups: []string{"group", "puorg"}, + exclude: []string{"bar"}, + expected: []string{"foo.group"}, + }, + { + testName: "two filtered by ShortName", + resources: []v1.APIResource{{Name: "foo", ShortNames: []string{"baz"}}, {Name: "bar"}}, + groups: []string{"group", "puorg"}, + exclude: []string{"baz"}, + expected: []string{"bar.puorg"}, + }, + } + + for _, test := range tests { + t.Run(test.testName, func(t *testing.T) { + var grs []groupResource + for i := range test.resources { + grs = append(grs, groupResource{ + APIGroup: test.groups[i], + APIResource: test.resources[i], + }) + } + + names := extractRelevantResourceNames(grs, test.exclude) + assert.Equal(t, test.expected, names) + }) + } +} diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 6fafc1b..efb0ce3 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -23,5 +23,6 @@ const ( FlagUseCache = "use-cache" FlagScope = "only-scope" + FlagExclude = "exclude" FlagNamespace = "namespace" ) diff --git a/pkg/options/options.go b/pkg/options/options.go index 49f2c68..b3ac3c7 100644 --- a/pkg/options/options.go +++ b/pkg/options/options.go @@ -31,6 +31,7 @@ type KetallOptions struct { PrintFlags KAPrintFlags UseCache bool Scope string + Exclusions []string Streams *genericclioptions.IOStreams }