From 9d056c6bd88d4947050231ca1385b7114e54f537 Mon Sep 17 00:00:00 2001 From: kargakis Date: Wed, 8 Apr 2015 17:05:41 +0200 Subject: [PATCH] Support setting up aliases for groups of resources Closes #5278 --- examples/cassandra/cassandra-service.yaml | 2 ++ hack/test-cmd.sh | 12 +++++++++ pkg/api/latest/latest.go | 6 +++++ pkg/api/meta/interfaces.go | 1 + pkg/api/meta/restmapper.go | 19 +++++++++++++ pkg/kubectl/resource/builder.go | 13 +++++++++ pkg/kubectl/resource/builder_test.go | 33 +++++++++++++++++++++++ 7 files changed, 86 insertions(+) diff --git a/examples/cassandra/cassandra-service.yaml b/examples/cassandra/cassandra-service.yaml index 2efde01ba2..ad17bce72c 100644 --- a/examples/cassandra/cassandra-service.yaml +++ b/examples/cassandra/cassandra-service.yaml @@ -5,3 +5,5 @@ port: 9042 containerPort: 9042 selector: name: cassandra +labels: + name: cassandra diff --git a/hack/test-cmd.sh b/hack/test-cmd.sh index d57b487db9..cee4dbf1b8 100755 --- a/hack/test-cmd.sh +++ b/hack/test-cmd.sh @@ -608,6 +608,18 @@ __EOF__ kube::test::get_object_assert 'nodes/127.0.0.1 service/kubernetes' "{{range.items}}{{$id_field}}:{{end}}" '127.0.0.1:kubernetes:' + ##################### + # Resource aliasing # + ##################### + + kube::log::status "Testing resource aliasing" + kubectl create -f examples/cassandra/cassandra.yaml + kubectl create -f examples/cassandra/cassandra-controller.yaml + kubectl create -f examples/cassandra/cassandra-service.yaml + kube::test::get_object_assert "all -l'name=cassandra'" "{{range.items}}{{$id_field}}:{{end}}" 'cassandra:cassandra:cassandra:' + kubectl delete all -l name=cassandra + + ########### # Swagger # ########### diff --git a/pkg/api/latest/latest.go b/pkg/api/latest/latest.go index 63b131c54e..ca5983073c 100644 --- a/pkg/api/latest/latest.go +++ b/pkg/api/latest/latest.go @@ -61,6 +61,9 @@ var SelfLinker = runtime.SelfLinker(accessor) // Kubernetes versions. var RESTMapper meta.RESTMapper +// userResources is a group of resources mostly used by a kubectl user +var userResources = []string{"rc", "svc", "pods", "pvc"} + // InterfacesFor returns the default Codec and ResourceVersioner for a given version // string, or an error if the version is not known. func InterfacesFor(version string) (*meta.VersionInterfaces, error) { @@ -124,6 +127,9 @@ func init() { "PersistentVolume": true, } + // setup aliases for groups of resources + mapper.AddResourceAlias("all", userResources...) + // these kinds should be excluded from the list of resources ignoredKinds := util.NewStringSet("ListOptions", "DeleteOptions", "Status", "ContainerManifest") diff --git a/pkg/api/meta/interfaces.go b/pkg/api/meta/interfaces.go index 64d17ffd7d..2ab02b6cd1 100644 --- a/pkg/api/meta/interfaces.go +++ b/pkg/api/meta/interfaces.go @@ -142,4 +142,5 @@ type RESTMapping struct { type RESTMapper interface { VersionAndKindForResource(resource string) (defaultVersion, kind string, err error) RESTMapping(kind string, versions ...string) (*RESTMapping, error) + AliasesForResource(resource string) ([]string, bool) } diff --git a/pkg/api/meta/restmapper.go b/pkg/api/meta/restmapper.go index fb0480298f..249752a276 100644 --- a/pkg/api/meta/restmapper.go +++ b/pkg/api/meta/restmapper.go @@ -226,3 +226,22 @@ func (m *DefaultRESTMapper) RESTMapping(kind string, versions ...string) (*RESTM MetadataAccessor: interfaces.MetadataAccessor, }, nil } + +// aliasToResource is used for mapping aliases to resources +var aliasToResource = map[string][]string{} + +// AddResourceAlias maps aliases to resources +func (m *DefaultRESTMapper) AddResourceAlias(alias string, resources ...string) { + if len(resources) == 0 { + return + } + aliasToResource[alias] = resources +} + +// AliasesForResource returns whether a resource has an alias or not +func (m *DefaultRESTMapper) AliasesForResource(alias string) ([]string, bool) { + if res, ok := aliasToResource[alias]; ok { + return res, true + } + return nil, false +} diff --git a/pkg/kubectl/resource/builder.go b/pkg/kubectl/resource/builder.go index 7e7aceaa23..f49f78425b 100644 --- a/pkg/kubectl/resource/builder.go +++ b/pkg/kubectl/resource/builder.go @@ -230,6 +230,7 @@ func (b *Builder) SelectAllParam(selectAll bool) *Builder { // When two or more arguments are received, they must be a single type and resource name(s). // The allowEmptySelector permits to select all the resources (via Everything func). func (b *Builder) ResourceTypeOrNameArgs(allowEmptySelector bool, args ...string) *Builder { + args = b.replaceAliases(args) if ok, err := hasCombinedTypeArgs(args); ok { if err != nil { b.errs = append(b.errs, err) @@ -269,6 +270,18 @@ func (b *Builder) ResourceTypeOrNameArgs(allowEmptySelector bool, args ...string return b } +func (b *Builder) replaceAliases(args []string) []string { + replaced := []string{} + for _, arg := range args { + if aliases, ok := b.mapper.AliasesForResource(arg); ok { + arg = strings.Join(aliases, ",") + } + replaced = append(replaced, arg) + } + + return replaced +} + func hasCombinedTypeArgs(args []string) (bool, error) { hasSlash := 0 for _, s := range args { diff --git a/pkg/kubectl/resource/builder_test.go b/pkg/kubectl/resource/builder_test.go index b6d61eca5a..a7a63736f3 100644 --- a/pkg/kubectl/resource/builder_test.go +++ b/pkg/kubectl/resource/builder_test.go @@ -783,3 +783,36 @@ func TestReceiveMultipleErrors(t *testing.T) { t.Errorf("unexpected errors %v", errs) } } + +func TestReplaceAliases(t *testing.T) { + tests := []struct { + name string + args []string + expected []string + }{ + { + name: "no-replacement", + args: []string{"service", "pods", "rc"}, + expected: []string{"service", "pods", "rc"}, + }, + { + name: "all-replacement", + args: []string{"all"}, + expected: []string{"rc,svc,pods,pvc"}, + }, + } + + b := NewBuilder(latest.RESTMapper, api.Scheme, fakeClient()) + + for _, test := range tests { + replaced := b.replaceAliases(test.args) + if len(replaced) != len(test.expected) { + t.Errorf("%s: unexpected args length: expected %d, got %d", test.name, len(test.expected), len(replaced)) + } + for i, arg := range test.expected { + if arg != replaced[i] { + t.Errorf("%s: unexpected argument: expected %s, got %s", test.name, arg, replaced[i]) + } + } + } +}