diff --git a/examples/cassandra/cassandra-service.yaml b/examples/cassandra/cassandra-service.yaml index 2efde01ba2d..ad17bce72c5 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 f58fbcd1de7..1583184b0b2 100755 --- a/hack/test-cmd.sh +++ b/hack/test-cmd.sh @@ -615,6 +615,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 887bba1a5b9..a58d44d437f 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", diff --git a/pkg/api/meta/interfaces.go b/pkg/api/meta/interfaces.go index 8d471a9a69a..fca198458b0 100644 --- a/pkg/api/meta/interfaces.go +++ b/pkg/api/meta/interfaces.go @@ -147,4 +147,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 fb0480298fa..249752a276c 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 7e7aceaa23f..f49f78425be 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 b6d61eca5ac..a7a63736f35 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]) + } + } + } +}