Merge pull request #43622 from deads2k/cli-10-category

Automatic merge from submit-queue (batch tested with PRs 42087, 43383, 43622)

move category expansion out of restmapper

RESTMapping isn't related to CategoryExpansion (the bit that expands "all" into items to be RESTMapped).  This provides that separation and simplifies the RESTMapper interface.

@kubernetes/sig-cli-pr-reviews
This commit is contained in:
Kubernetes Submit Queue 2017-03-27 16:08:20 -07:00 committed by GitHub
commit f14618a56b
51 changed files with 298 additions and 245 deletions

View File

@ -83,9 +83,6 @@ func enableVersions(externalVersions []schema.GroupVersion) error {
return nil
}
// userResources is a group of resources mostly used by a kubectl user
var userResources = []string{"svc"}
func newRESTMapper(externalVersions []schema.GroupVersion) meta.RESTMapper {
// the list of kinds that are scoped at the root of the api hierarchy
// if a kind is not enumerated here, it is assumed to have a namespace scope
@ -100,8 +97,6 @@ func newRESTMapper(externalVersions []schema.GroupVersion) meta.RESTMapper {
"Status")
mapper := meta.NewDefaultRESTMapperFromScheme(externalVersions, interfacesFor, importPrefix, ignoredKinds, rootScoped, core.Scheme)
// setup aliases for groups of resources
mapper.AddResourceAlias("all", userResources...)
return mapper
}

View File

@ -190,7 +190,7 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro
if err != nil {
return err
}
b := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
b := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
ContinueOnError().
NamespaceParam(namespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).

View File

@ -205,7 +205,7 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, opti
}
}
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
Schema(schema).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().

View File

@ -120,7 +120,7 @@ func (o *SetLastAppliedOptions) Complete(f cmdutil.Factory, cmd *cobra.Command)
}
func (o *SetLastAppliedOptions) Validate(f cmdutil.Factory, cmd *cobra.Command) error {
r := resource.NewBuilder(o.Mapper, o.Typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
r := resource.NewBuilder(o.Mapper, f.CategoryExpander(), o.Typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
NamespaceParam(o.Namespace).DefaultNamespace().
FilenameParam(o.EnforceNamespace, &o.FilenameOptions).
Latest().

View File

@ -90,7 +90,7 @@ func (o *ViewLastAppliedOptions) Complete(f cmdutil.Factory, args []string) erro
return err
}
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).
ResourceTypeOrNameArgs(enforceNamespace, args...).

View File

@ -146,7 +146,7 @@ func (p *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn [
}
mapper, typer := f.Object()
builder := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
builder := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
NamespaceParam(namespace).DefaultNamespace()
switch len(argsIn) {

View File

@ -91,7 +91,7 @@ func RunAutoscale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []s
}
mapper, typer := f.Object()
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
ContinueOnError().
NamespaceParam(namespace).DefaultNamespace().
FilenameParam(enforceNamespace, options).

View File

@ -167,7 +167,7 @@ func (options *CertificateOptions) modifyCertificateCondition(f cmdutil.Factory,
if err != nil {
return err
}
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
ContinueOnError().
FilenameParam(false, &options.FilenameOptions).
ResourceNames("certificatesigningrequest", options.csrNames...).

View File

@ -79,7 +79,7 @@ func RunClusterInfo(f cmdutil.Factory, out io.Writer, cmd *cobra.Command) error
}
// TODO use generalized labels once they are implemented (#341)
b := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
b := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
NamespaceParam(cmdNamespace).DefaultNamespace().
SelectorParam("kubernetes.io/cluster-service=true").
ResourceTypeOrNameArgs(false, []string{"services"}...).

View File

@ -132,9 +132,9 @@ func (o *ConvertOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.C
if o.local {
fmt.Fprintln(os.Stderr, "running in local mode...")
o.builder = resource.NewBuilder(mapper, typer, resource.DisabledClientForMapping{ClientMapper: clientMapper}, f.Decoder(true))
o.builder = resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.DisabledClientForMapping{ClientMapper: clientMapper}, f.Decoder(true))
} else {
o.builder = resource.NewBuilder(mapper, typer, clientMapper, f.Decoder(true))
o.builder = resource.NewBuilder(mapper, f.CategoryExpander(), typer, clientMapper, f.Decoder(true))
schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"), cmdutil.GetFlagString(cmd, "schema-cache-dir"))
if err != nil {
return err

View File

@ -128,7 +128,7 @@ func RunCreate(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, opt
if err != nil {
return err
}
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
Schema(schema).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().

View File

@ -175,7 +175,7 @@ func (o *DeleteOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, args
return err
}
o.Mapper = mapper
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).

View File

@ -121,7 +121,7 @@ func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, a
if err != nil {
return err
}
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
FilenameParam(enforceNamespace, options).
@ -181,7 +181,7 @@ func DescribeMatchingResources(mapper meta.RESTMapper, typer runtime.ObjectTyper
if err != nil {
return err
}
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
NamespaceParam(namespace).DefaultNamespace().
ResourceTypeOrNameArgs(true, rsrc).
SingleResourceType().

View File

@ -385,7 +385,7 @@ func getMapperAndResult(f cmdutil.Factory, args []string, options *resource.File
return nil, nil, nil, "", err
}
b := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme)
b := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme)
if editMode == NormalEditMode {
// if in normal mode, also read from args, and fetch latest from the server
b = b.ResourceTypeOrNameArgs(true, args...).Latest()
@ -403,7 +403,7 @@ func getMapperAndResult(f cmdutil.Factory, args []string, options *resource.File
updatedResultGetter := func(data []byte) *resource.Result {
// resource builder to read objects from edited data
return resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
return resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
Stream(bytes.NewReader(data), "edited-file").
ContinueOnError().
Flatten().

View File

@ -127,7 +127,7 @@ func RunExpose(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
}
mapper, typer := f.Object()
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
ContinueOnError().
NamespaceParam(namespace).DefaultNamespace().
FilenameParam(enforceNamespace, options).

View File

@ -193,7 +193,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
// handle watch separately since we cannot watch multiple resource types
isWatch, isWatchOnly := cmdutil.GetFlagBool(cmd, "watch"), cmdutil.GetFlagBool(cmd, "watch-only")
if isWatch || isWatchOnly {
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
FilenameParam(enforceNamespace, &options.FilenameOptions).
SelectorParam(selector).
@ -283,7 +283,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
return nil
}
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
FilenameParam(enforceNamespace, &options.FilenameOptions).
SelectorParam(selector).

View File

@ -185,7 +185,7 @@ func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
if err != nil {
return err
}
b := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
b := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).

View File

@ -198,7 +198,7 @@ func (o *LogsOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.Comm
mapper, typer := f.Object()
decoder := f.Decoder(true)
if o.Object == nil {
builder := resource.NewBuilder(mapper, typer, o.ClientMapper, decoder).
builder := resource.NewBuilder(mapper, f.CategoryExpander(), typer, o.ClientMapper, decoder).
NamespaceParam(o.Namespace).DefaultNamespace().
SingleResourceType()
if o.ResourceArg != "" {

View File

@ -153,7 +153,7 @@ func RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
if err != nil {
return err
}
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &options.FilenameOptions).

View File

@ -129,7 +129,7 @@ func RunReplace(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str
if err != nil {
return err
}
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
Schema(schema).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
@ -200,7 +200,7 @@ func forceReplace(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []s
if err != nil {
return err
}
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, options).
@ -249,7 +249,7 @@ func forceReplace(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []s
})
})
r = resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
r = resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
Schema(schema).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().

View File

@ -205,7 +205,7 @@ func RunRollingUpdate(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args
return err
}
request := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
request := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
Schema(schema).
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &resource.FilenameOptions{Recursive: false, Filenames: []string{filename}}).

View File

@ -81,7 +81,7 @@ func RunHistory(f cmdutil.Factory, cmd *cobra.Command, out io.Writer, args []str
return err
}
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, options).
ResourceTypeOrNameArgs(true, args...).

View File

@ -111,7 +111,7 @@ func (o *PauseConfig) CompletePause(f cmdutil.Factory, cmd *cobra.Command, out i
return err
}
r := resource.NewBuilder(o.Mapper, o.Typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
r := resource.NewBuilder(o.Mapper, f.CategoryExpander(), o.Typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).
ResourceTypeOrNameArgs(true, args...).

View File

@ -109,7 +109,7 @@ func (o *ResumeConfig) CompleteResume(f cmdutil.Factory, cmd *cobra.Command, out
return err
}
r := resource.NewBuilder(o.Mapper, o.Typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
r := resource.NewBuilder(o.Mapper, f.CategoryExpander(), o.Typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).
ResourceTypeOrNameArgs(true, args...).

View File

@ -84,7 +84,7 @@ func RunStatus(f cmdutil.Factory, cmd *cobra.Command, out io.Writer, args []stri
return err
}
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, options).
ResourceTypeOrNameArgs(true, args...).

View File

@ -110,7 +110,7 @@ func (o *UndoOptions) CompleteUndo(f cmdutil.Factory, cmd *cobra.Command, out io
return err
}
r := resource.NewBuilder(o.Mapper, o.Typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
r := resource.NewBuilder(o.Mapper, f.CategoryExpander(), o.Typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).
ResourceTypeOrNameArgs(true, args...).

View File

@ -339,7 +339,7 @@ func Run(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cobr
return err
}
_, typer := f.Object()
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
ContinueOnError().
NamespaceParam(namespace).DefaultNamespace().
ResourceNames(mapping.Resource, name).

View File

@ -106,7 +106,7 @@ func RunScale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
}
mapper, typer := f.Object()
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, options).

View File

@ -136,7 +136,7 @@ func (o *ImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st
return err
}
builder := resource.NewBuilder(o.Mapper, o.Typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
builder := resource.NewBuilder(o.Mapper, f.CategoryExpander(), o.Typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).

View File

@ -140,7 +140,7 @@ func (o *ResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
return err
}
builder := resource.NewBuilder(o.Mapper, o.Typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
builder := resource.NewBuilder(o.Mapper, f.CategoryExpander(), o.Typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
//FilenameParam(enforceNamespace, o.Filenames...).

View File

@ -84,7 +84,7 @@ func RunStop(f cmdutil.Factory, cmd *cobra.Command, args []string, out io.Writer
}
mapper, typer := f.Object()
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
ResourceTypeOrNameArgs(false, args...).

View File

@ -226,7 +226,7 @@ func (o *TaintOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.Com
}
mapper, typer := f.Object()
o.builder = resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
o.builder = resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
ContinueOnError().
NamespaceParam(namespace).DefaultNamespace()
if o.all {

View File

@ -277,6 +277,10 @@ func (f *FakeFactory) UnstructuredObject() (meta.RESTMapper, runtime.ObjectTyper
return expander, typer, err
}
func (f *FakeFactory) CategoryExpander() resource.CategoryExpander {
return resource.LegacyCategoryExpander
}
func (f *FakeFactory) Decoder(bool) runtime.Decoder {
return f.Codec
}
@ -689,7 +693,7 @@ func (f *fakeAPIFactory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RES
func (f *fakeAPIFactory) NewBuilder() *resource.Builder {
mapper, typer := f.Object()
return resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true))
return resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true))
}
func (f *fakeAPIFactory) SuggestedPodTemplateResources() []schema.GroupResource {

View File

@ -189,6 +189,8 @@ type ObjectMappingFactory interface {
// Returns interfaces for dealing with arbitrary
// runtime.Unstructured. This performs API calls to discover types.
UnstructuredObject() (meta.RESTMapper, runtime.ObjectTyper, error)
// Returns interface for expanding categories like `all`.
CategoryExpander() resource.CategoryExpander
// Returns a RESTClient for working with the specified RESTMapping or an error. This is intended
// for working with arbitrary resources and is not guaranteed to point to a Kubernetes APIServer.
ClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error)

View File

@ -126,6 +126,7 @@ func (f *ring2Factory) PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, o
func (f *ring2Factory) NewBuilder() *resource.Builder {
mapper, typer := f.objectMappingFactory.Object()
categoryExpander := f.objectMappingFactory.CategoryExpander()
return resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.objectMappingFactory.ClientForMapping), f.clientAccessFactory.Decoder(true))
return resource.NewBuilder(mapper, categoryExpander, typer, resource.ClientMapperFunc(f.objectMappingFactory.ClientForMapping), f.clientAccessFactory.Decoder(true))
}

View File

@ -105,6 +105,20 @@ func (f *ring1Factory) UnstructuredObject() (meta.RESTMapper, runtime.ObjectType
return expander, typer, err
}
func (f *ring1Factory) CategoryExpander() resource.CategoryExpander {
var categoryExpander resource.CategoryExpander
categoryExpander = resource.LegacyCategoryExpander
discoveryClient, err := f.clientAccessFactory.DiscoveryClient()
if err == nil {
// wrap with discovery based filtering
categoryExpander, err = resource.NewDiscoveryFilteredExpander(categoryExpander, discoveryClient)
// you only have an error on missing discoveryClient, so this shouldn't fail. Check anyway.
CheckErr(err)
}
return categoryExpander
}
func (f *ring1Factory) ClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error) {
cfg, err := f.clientAccessFactory.ClientConfig()
if err != nil {

View File

@ -740,12 +740,12 @@ func TestDiscoveryReplaceAliases(t *testing.T) {
{
name: "all-replacement",
arg: "all",
expected: "pods,replicationcontrollers,services,statefulsets,horizontalpodautoscalers,jobs,deployments,replicasets",
expected: "pods,replicationcontrollers,services,statefulsets.apps,horizontalpodautoscalers.autoscaling,jobs.batch,deployments.extensions,replicasets.extensions",
},
{
name: "alias-in-comma-separated-arg",
arg: "all,secrets",
expected: "pods,replicationcontrollers,services,statefulsets,horizontalpodautoscalers,jobs,deployments,replicasets,secrets",
expected: "pods,replicationcontrollers,services,statefulsets.apps,horizontalpodautoscalers.autoscaling,jobs.batch,deployments.extensions,replicasets.extensions,secrets",
},
}
@ -754,7 +754,7 @@ func TestDiscoveryReplaceAliases(t *testing.T) {
if err != nil {
t.Fatalf("Unable to create shortcut expander, err = %s", err.Error())
}
b := resource.NewBuilder(mapper, api.Scheme, fakeClient(), testapi.Default.Codec())
b := resource.NewBuilder(mapper, resource.LegacyCategoryExpander, api.Scheme, fakeClient(), testapi.Default.Codec())
for _, test := range tests {
replaced := b.ReplaceAliases(test.arg)

View File

@ -21,6 +21,7 @@ import (
"strings"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery"
@ -31,8 +32,6 @@ import (
type shortcutExpander struct {
RESTMapper meta.RESTMapper
All []schema.GroupResource
discoveryClient discovery.DiscoveryInterface
}
@ -42,33 +41,7 @@ func NewShortcutExpander(delegate meta.RESTMapper, client discovery.DiscoveryInt
if client == nil {
return shortcutExpander{}, errors.New("Please provide discovery client to shortcut expander")
}
return shortcutExpander{All: UserResources, RESTMapper: delegate, discoveryClient: client}, nil
}
func (e shortcutExpander) getAll() []schema.GroupResource {
// Check if we have access to server resources
apiResources, err := e.discoveryClient.ServerResources()
if err != nil {
return e.All
}
availableResources, err := discovery.GroupVersionResources(apiResources)
if err != nil {
return e.All
}
availableAll := []schema.GroupResource{}
for _, requestedResource := range e.All {
for availableResource := range availableResources {
if requestedResource.Group == availableResource.Group &&
requestedResource.Resource == availableResource.Resource {
availableAll = append(availableAll, requestedResource)
break
}
}
}
return availableAll
return shortcutExpander{RESTMapper: delegate, discoveryClient: client}, nil
}
func (e shortcutExpander) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
@ -99,38 +72,6 @@ func (e shortcutExpander) RESTMappings(gk schema.GroupKind, versions ...string)
return e.RESTMapper.RESTMappings(gk, versions...)
}
// UserResources are the resource names that apply to the primary, user facing resources used by
// client tools. They are in deletion-first order - dependent resources should be last.
// Should remain exported in order to expose a current list of resources to downstream
// composition that wants to build on the concept of 'all' for their CLIs.
var UserResources = []schema.GroupResource{
{Group: "", Resource: "pods"},
{Group: "", Resource: "replicationcontrollers"},
{Group: "", Resource: "services"},
{Group: "apps", Resource: "statefulsets"},
{Group: "autoscaling", Resource: "horizontalpodautoscalers"},
{Group: "batch", Resource: "jobs"},
{Group: "extensions", Resource: "deployments"},
{Group: "extensions", Resource: "replicasets"},
}
// AliasesForResource returns whether a resource has an alias or not
func (e shortcutExpander) AliasesForResource(resource string) ([]string, bool) {
if strings.ToLower(resource) == "all" {
var resources []schema.GroupResource
if resources = e.getAll(); len(resources) == 0 {
resources = UserResources
}
aliases := []string{}
for _, r := range resources {
aliases = append(aliases, r.Resource)
}
return aliases, true
}
expanded := e.expandResourceShortcut(schema.GroupVersionResource{Resource: resource}).Resource
return []string{expanded}, (expanded != resource)
}
// getShortcutMappings returns a set of tuples which holds short names for resources.
// First the list of potential resources will be taken from the API server.
// Next we will append the hardcoded list of resources - to be backward compatible with old servers.

View File

@ -17,7 +17,6 @@ limitations under the License.
package util
import (
"strings"
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -29,43 +28,25 @@ func TestReplaceAliases(t *testing.T) {
tests := []struct {
name string
arg string
expected string
expected schema.GroupVersionResource
srvRes []*metav1.APIResourceList
}{
{
name: "no-replacement",
arg: "service",
expected: "service",
srvRes: []*metav1.APIResourceList{},
},
{
name: "all-replacement",
arg: "all",
expected: "pods,replicationcontrollers,services,statefulsets,horizontalpodautoscalers,jobs,deployments,replicasets",
srvRes: []*metav1.APIResourceList{},
},
{
name: "alias-in-comma-separated-arg",
arg: "all,secrets",
expected: "pods,replicationcontrollers,services,statefulsets,horizontalpodautoscalers,jobs,deployments,replicasets,secrets",
srvRes: []*metav1.APIResourceList{},
},
{
name: "rc-resolves-to-replicationcontrollers",
arg: "rc",
expected: "replicationcontrollers",
expected: schema.GroupVersionResource{Resource: "replicationcontrollers"},
srvRes: []*metav1.APIResourceList{},
},
{
name: "storageclasses-no-replacement",
arg: "storageclasses",
expected: "storageclasses",
expected: schema.GroupVersionResource{Resource: "storageclasses"},
srvRes: []*metav1.APIResourceList{},
},
{
name: "hpa-priority",
arg: "hpa",
expected: "superhorizontalpodautoscalers",
expected: schema.GroupVersionResource{Resource: "superhorizontalpodautoscalers"},
srvRes: []*metav1.APIResourceList{
{
GroupVersion: "autoscaling/v1",
@ -96,16 +77,12 @@ func TestReplaceAliases(t *testing.T) {
}
for _, test := range tests {
resources := []string{}
ds.serverResourcesHandler = func() ([]*metav1.APIResourceList, error) {
return test.srvRes, nil
}
for _, arg := range strings.Split(test.arg, ",") {
curr, _ := mapper.AliasesForResource(arg)
resources = append(resources, curr...)
}
if strings.Join(resources, ",") != test.expected {
t.Errorf("%s: unexpected argument: expected %s, got %s", test.name, test.expected, resources)
actual := mapper.expandResourceShortcut(schema.GroupVersionResource{Resource: test.arg})
if actual != test.expected {
t.Errorf("%s: unexpected argument: expected %s, got %s", test.name, test.expected, actual)
}
}
}

View File

@ -12,6 +12,7 @@ go_library(
name = "go_default_library",
srcs = [
"builder.go",
"categories.go",
"doc.go",
"helper.go",
"interfaces.go",
@ -40,6 +41,7 @@ go_library(
"//vendor:k8s.io/apimachinery/pkg/util/sets",
"//vendor:k8s.io/apimachinery/pkg/util/yaml",
"//vendor:k8s.io/apimachinery/pkg/watch",
"//vendor:k8s.io/client-go/discovery",
"//vendor:k8s.io/client-go/rest",
],
)
@ -48,6 +50,7 @@ go_test(
name = "go_default_test",
srcs = [
"builder_test.go",
"categories_test.go",
"helper_test.go",
"visitor_test.go",
],
@ -72,6 +75,7 @@ go_test(
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/labels",
"//vendor:k8s.io/apimachinery/pkg/runtime",
"//vendor:k8s.io/apimachinery/pkg/runtime/schema",
"//vendor:k8s.io/apimachinery/pkg/runtime/serializer/streaming",
"//vendor:k8s.io/apimachinery/pkg/util/errors",
"//vendor:k8s.io/apimachinery/pkg/watch",

View File

@ -42,7 +42,8 @@ const defaultHttpGetAttempts int = 3
// from the command line and converting them to a list of resources to iterate
// over using the Visitor interface.
type Builder struct {
mapper *Mapper
mapper *Mapper
categoryExpander CategoryExpander
errs []error
@ -105,10 +106,11 @@ type resourceTuple struct {
}
// NewBuilder creates a builder that operates on generic objects.
func NewBuilder(mapper meta.RESTMapper, typer runtime.ObjectTyper, clientMapper ClientMapper, decoder runtime.Decoder) *Builder {
func NewBuilder(mapper meta.RESTMapper, categoryExpander CategoryExpander, typer runtime.ObjectTyper, clientMapper ClientMapper, decoder runtime.Decoder) *Builder {
return &Builder{
mapper: &Mapper{typer, mapper, clientMapper, decoder},
requireObject: true,
mapper: &Mapper{typer, mapper, clientMapper, decoder},
categoryExpander: categoryExpander,
requireObject: true,
}
}
@ -371,8 +373,16 @@ func (b *Builder) ResourceTypeOrNameArgs(allowEmptySelector bool, args ...string
func (b *Builder) ReplaceAliases(input string) string {
replaced := []string{}
for _, arg := range strings.Split(input, ",") {
if aliases, ok := b.mapper.AliasesForResource(arg); ok {
arg = strings.Join(aliases, ",")
if resources, ok := b.categoryExpander.Expand(arg); ok {
asStrings := []string{}
for _, resource := range resources {
if len(resource.Group) == 0 {
asStrings = append(asStrings, resource.Resource)
continue
}
asStrings = append(asStrings, resource.Resource+"."+resource.Group)
}
arg = strings.Join(asStrings, ",")
}
replaced = append(replaced, arg)
}

View File

@ -255,7 +255,7 @@ var aRC string = `
`
func TestPathBuilderAndVersionedObjectNotDefaulted(t *testing.T) {
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClient(), testapi.Default.Codec()).
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{"../../../test/fixtures/pkg/kubectl/builder/kitten-rc.yaml"}})
test := &testVisitor{}
@ -294,7 +294,7 @@ func TestNodeBuilder(t *testing.T) {
w.Write([]byte(runtime.EncodeOrDie(testapi.Default.Codec(), node)))
}()
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClient(), testapi.Default.Codec()).
NamespaceParam("test").Stream(r, "STDIN")
test := &testVisitor{}
@ -358,7 +358,7 @@ func TestPathBuilderWithMultiple(t *testing.T) {
}
for _, test := range tests {
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClient(), testapi.Default.Codec()).
FilenameParam(false, &FilenameOptions{Recursive: test.recursive, Filenames: []string{test.directory}}).
NamespaceParam("test").DefaultNamespace()
@ -417,7 +417,7 @@ func TestPathBuilderWithMultipleInvalid(t *testing.T) {
}
for _, test := range tests {
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClient(), testapi.Default.Codec()).
FilenameParam(false, &FilenameOptions{Recursive: test.recursive, Filenames: []string{test.directory}}).
NamespaceParam("test").DefaultNamespace()
@ -432,7 +432,7 @@ func TestPathBuilderWithMultipleInvalid(t *testing.T) {
}
func TestDirectoryBuilder(t *testing.T) {
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClient(), testapi.Default.Codec()).
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{"../../../examples/guestbook/legacy"}}).
NamespaceParam("test").DefaultNamespace()
@ -463,7 +463,7 @@ func TestNamespaceOverride(t *testing.T) {
}))
defer s.Close()
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClient(), testapi.Default.Codec()).
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{s.URL}}).
NamespaceParam("test")
@ -474,7 +474,7 @@ func TestNamespaceOverride(t *testing.T) {
t.Fatalf("unexpected response: %v %#v", err, test.Infos)
}
b = NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
b = NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClient(), testapi.Default.Codec()).
FilenameParam(true, &FilenameOptions{Recursive: false, Filenames: []string{s.URL}}).
NamespaceParam("test")
@ -494,7 +494,7 @@ func TestURLBuilder(t *testing.T) {
}))
defer s.Close()
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClient(), testapi.Default.Codec()).
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{s.URL}}).
NamespaceParam("foo")
@ -523,7 +523,7 @@ func TestURLBuilderRequireNamespace(t *testing.T) {
}))
defer s.Close()
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClient(), testapi.Default.Codec()).
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{s.URL}}).
NamespaceParam("test").RequireNamespace()
@ -538,7 +538,7 @@ func TestURLBuilderRequireNamespace(t *testing.T) {
func TestResourceByName(t *testing.T) {
pods, _ := testData()
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClientWith("", t, map[string]string{
"/namespaces/test/pods/foo": runtime.EncodeOrDie(testapi.Default.Codec(), &pods.Items[0]),
}), testapi.Default.Codec()).
NamespaceParam("test")
@ -571,7 +571,7 @@ func TestResourceByName(t *testing.T) {
func TestMultipleResourceByTheSameName(t *testing.T) {
pods, svcs := testData()
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClientWith("", t, map[string]string{
"/namespaces/test/pods/foo": runtime.EncodeOrDie(testapi.Default.Codec(), &pods.Items[0]),
"/namespaces/test/pods/baz": runtime.EncodeOrDie(testapi.Default.Codec(), &pods.Items[1]),
"/namespaces/test/services/foo": runtime.EncodeOrDie(testapi.Default.Codec(), &svcs.Items[0]),
@ -603,7 +603,7 @@ func TestMultipleResourceByTheSameName(t *testing.T) {
func TestResourceNames(t *testing.T) {
pods, svc := testData()
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClientWith("", t, map[string]string{
"/namespaces/test/pods/foo": runtime.EncodeOrDie(testapi.Default.Codec(), &pods.Items[0]),
"/namespaces/test/services/baz": runtime.EncodeOrDie(testapi.Default.Codec(), &svc.Items[0]),
}), testapi.Default.Codec()).
@ -631,7 +631,7 @@ func TestResourceNames(t *testing.T) {
func TestResourceNamesWithoutResource(t *testing.T) {
pods, svc := testData()
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClientWith("", t, map[string]string{
"/namespaces/test/pods/foo": runtime.EncodeOrDie(testapi.Default.Codec(), &pods.Items[0]),
"/namespaces/test/services/baz": runtime.EncodeOrDie(testapi.Default.Codec(), &svc.Items[0]),
}), testapi.Default.Codec()).
@ -652,7 +652,7 @@ func TestResourceNamesWithoutResource(t *testing.T) {
}
func TestResourceByNameWithoutRequireObject(t *testing.T) {
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{}), testapi.Default.Codec()).
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClientWith("", t, map[string]string{}), testapi.Default.Codec()).
NamespaceParam("test")
test := &testVisitor{}
@ -686,7 +686,7 @@ func TestResourceByNameWithoutRequireObject(t *testing.T) {
func TestResourceByNameAndEmptySelector(t *testing.T) {
pods, _ := testData()
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClientWith("", t, map[string]string{
"/namespaces/test/pods/foo": runtime.EncodeOrDie(testapi.Default.Codec(), &pods.Items[0]),
}), testapi.Default.Codec()).
NamespaceParam("test").
@ -714,7 +714,7 @@ func TestResourceByNameAndEmptySelector(t *testing.T) {
func TestSelector(t *testing.T) {
pods, svc := testData()
labelKey := metav1.LabelSelectorQueryParam(api.Registry.GroupOrDie(api.GroupName).GroupVersion.String())
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClientWith("", t, map[string]string{
"/namespaces/test/pods?" + labelKey + "=a%3Db": runtime.EncodeOrDie(testapi.Default.Codec(), pods),
"/namespaces/test/services?" + labelKey + "=a%3Db": runtime.EncodeOrDie(testapi.Default.Codec(), svc),
}), testapi.Default.Codec()).
@ -745,7 +745,7 @@ func TestSelector(t *testing.T) {
}
func TestSelectorRequiresKnownTypes(t *testing.T) {
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClient(), testapi.Default.Codec()).
SelectorParam("a=b").
NamespaceParam("test").
ResourceTypes("unknown")
@ -756,7 +756,7 @@ func TestSelectorRequiresKnownTypes(t *testing.T) {
}
func TestSingleResourceType(t *testing.T) {
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClient(), testapi.Default.Codec()).
SelectorParam("a=b").
SingleResourceType().
ResourceTypeOrNameArgs(true, "pods,services")
@ -826,7 +826,7 @@ func TestResourceTuple(t *testing.T) {
}
}
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith(k, t, expectedRequests), testapi.Default.Codec()).
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClientWith(k, t, expectedRequests), testapi.Default.Codec()).
NamespaceParam("test").DefaultNamespace().
ResourceTypeOrNameArgs(true, testCase.args...).RequireObject(requireObject)
@ -857,7 +857,7 @@ func TestResourceTuple(t *testing.T) {
func TestStream(t *testing.T) {
r, pods, rc := streamTestData()
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClient(), testapi.Default.Codec()).
NamespaceParam("test").Stream(r, "STDIN").Flatten()
test := &testVisitor{}
@ -874,7 +874,7 @@ func TestStream(t *testing.T) {
func TestYAMLStream(t *testing.T) {
r, pods, rc := streamYAMLTestData()
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClient(), testapi.Default.Codec()).
NamespaceParam("test").Stream(r, "STDIN").Flatten()
test := &testVisitor{}
@ -891,7 +891,7 @@ func TestYAMLStream(t *testing.T) {
func TestMultipleObject(t *testing.T) {
r, pods, svc := streamTestData()
obj, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
obj, err := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClient(), testapi.Default.Codec()).
NamespaceParam("test").Stream(r, "STDIN").Flatten().
Do().Object()
@ -913,7 +913,7 @@ func TestMultipleObject(t *testing.T) {
func TestContinueOnErrorVisitor(t *testing.T) {
r, _, _ := streamTestData()
req := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
req := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClient(), testapi.Default.Codec()).
ContinueOnError().
NamespaceParam("test").Stream(r, "STDIN").Flatten().
Do()
@ -942,7 +942,7 @@ func TestContinueOnErrorVisitor(t *testing.T) {
}
func TestSingleItemImpliedObject(t *testing.T) {
obj, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
obj, err := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClient(), testapi.Default.Codec()).
NamespaceParam("test").DefaultNamespace().
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{"../../../examples/guestbook/legacy/redis-master-controller.yaml"}}).
Flatten().
@ -962,7 +962,7 @@ func TestSingleItemImpliedObject(t *testing.T) {
}
func TestSingleItemImpliedObjectNoExtension(t *testing.T) {
obj, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
obj, err := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClient(), testapi.Default.Codec()).
NamespaceParam("test").DefaultNamespace().
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{"../../../examples/pod"}}).
Flatten().
@ -984,7 +984,7 @@ func TestSingleItemImpliedObjectNoExtension(t *testing.T) {
func TestSingleItemImpliedRootScopedObject(t *testing.T) {
node := &api.Node{ObjectMeta: metav1.ObjectMeta{Name: "test"}, Spec: api.NodeSpec{ExternalID: "test"}}
r := streamTestObject(node)
infos, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
infos, err := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClient(), testapi.Default.Codec()).
NamespaceParam("test").DefaultNamespace().
Stream(r, "STDIN").
Flatten().
@ -1009,7 +1009,7 @@ func TestSingleItemImpliedRootScopedObject(t *testing.T) {
func TestListObject(t *testing.T) {
pods, _ := testData()
labelKey := metav1.LabelSelectorQueryParam(api.Registry.GroupOrDie(api.GroupName).GroupVersion.String())
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClientWith("", t, map[string]string{
"/namespaces/test/pods?" + labelKey + "=a%3Db": runtime.EncodeOrDie(testapi.Default.Codec(), pods),
}), testapi.Default.Codec()).
SelectorParam("a=b").
@ -1042,7 +1042,7 @@ func TestListObject(t *testing.T) {
func TestListObjectWithDifferentVersions(t *testing.T) {
pods, svc := testData()
labelKey := metav1.LabelSelectorQueryParam(api.Registry.GroupOrDie(api.GroupName).GroupVersion.String())
obj, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
obj, err := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClientWith("", t, map[string]string{
"/namespaces/test/pods?" + labelKey + "=a%3Db": runtime.EncodeOrDie(testapi.Default.Codec(), pods),
"/namespaces/test/services?" + labelKey + "=a%3Db": runtime.EncodeOrDie(testapi.Default.Codec(), svc),
}), testapi.Default.Codec()).
@ -1068,7 +1068,7 @@ func TestListObjectWithDifferentVersions(t *testing.T) {
func TestWatch(t *testing.T) {
_, svc := testData()
w, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
w, err := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClientWith("", t, map[string]string{
"/namespaces/test/services?fieldSelector=metadata.name%3Dredis-master&resourceVersion=12&watch=true": watchBody(watch.Event{
Type: watch.Added,
Object: &svc.Items[0],
@ -1100,7 +1100,7 @@ func TestWatch(t *testing.T) {
}
func TestWatchMultipleError(t *testing.T) {
_, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
_, err := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClient(), testapi.Default.Codec()).
NamespaceParam("test").DefaultNamespace().
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{"../../../examples/guestbook/legacy/redis-master-controller.yaml"}}).Flatten().
FilenameParam(false, &FilenameOptions{Recursive: false, Filenames: []string{"../../../examples/guestbook/legacy/redis-master-controller.yaml"}}).Flatten().
@ -1123,7 +1123,7 @@ func TestLatest(t *testing.T) {
ObjectMeta: metav1.ObjectMeta{Name: "baz", Namespace: "test", ResourceVersion: "15"},
}
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClientWith("", t, map[string]string{
"/namespaces/test/pods/foo": runtime.EncodeOrDie(testapi.Default.Codec(), newPod),
"/namespaces/test/pods/bar": runtime.EncodeOrDie(testapi.Default.Codec(), newPod2),
"/namespaces/test/services/baz": runtime.EncodeOrDie(testapi.Default.Codec(), newSvc),
@ -1159,7 +1159,7 @@ func TestReceiveMultipleErrors(t *testing.T) {
w2.Write([]byte(runtime.EncodeOrDie(testapi.Default.Codec(), &svc.Items[0])))
}()
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
b := NewBuilder(testapi.Default.RESTMapper(), LegacyCategoryExpander, api.Scheme, fakeClient(), testapi.Default.Codec()).
Stream(r, "1").Stream(r2, "2").
ContinueOnError()

View File

@ -0,0 +1,109 @@
/*
Copyright 2017 The Kubernetes Authors.
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 resource
import (
"errors"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery"
)
type CategoryExpander interface {
Expand(category string) ([]schema.GroupResource, bool)
}
type SimpleCategoryExpander struct {
Expansions map[string][]schema.GroupResource
}
func (e SimpleCategoryExpander) Expand(category string) ([]schema.GroupResource, bool) {
ret, ok := e.Expansions[category]
return ret, ok
}
type discoveryFilteredExpander struct {
delegate CategoryExpander
discoveryClient discovery.DiscoveryInterface
}
// NewDiscoveryFilteredExpander returns a category expander that filters the returned groupresources by
// what the server has available
func NewDiscoveryFilteredExpander(delegate CategoryExpander, client discovery.DiscoveryInterface) (discoveryFilteredExpander, error) {
if client == nil {
return discoveryFilteredExpander{}, errors.New("Please provide discovery client to shortcut expander")
}
return discoveryFilteredExpander{delegate: delegate, discoveryClient: client}, nil
}
func (e discoveryFilteredExpander) Expand(category string) ([]schema.GroupResource, bool) {
delegateExpansion, ok := e.delegate.Expand(category)
// Check if we have access to server resources
apiResources, err := e.discoveryClient.ServerResources()
if err != nil {
return delegateExpansion, ok
}
availableResources, err := discovery.GroupVersionResources(apiResources)
if err != nil {
return delegateExpansion, ok
}
available := []schema.GroupResource{}
for _, requestedResource := range delegateExpansion {
for availableResource := range availableResources {
if requestedResource.Group == availableResource.Group &&
requestedResource.Resource == availableResource.Resource {
available = append(available, requestedResource)
break
}
}
}
return available, ok
}
// legacyUserResources are the resource names that apply to the primary, user facing resources used by
// client tools. They are in deletion-first order - dependent resources should be last.
// Should remain exported in order to expose a current list of resources to downstream
// composition that wants to build on the concept of 'all' for their CLIs.
var legacyUserResources = []schema.GroupResource{
{Group: "", Resource: "pods"},
{Group: "", Resource: "replicationcontrollers"},
{Group: "", Resource: "services"},
{Group: "apps", Resource: "statefulsets"},
{Group: "autoscaling", Resource: "horizontalpodautoscalers"},
{Group: "batch", Resource: "jobs"},
{Group: "extensions", Resource: "deployments"},
{Group: "extensions", Resource: "replicasets"},
}
// LegacyCategoryExpander is the old hardcoded expansion
var LegacyCategoryExpander CategoryExpander = SimpleCategoryExpander{
Expansions: map[string][]schema.GroupResource{
"all": legacyUserResources,
},
}
// LegacyFederationCategoryExpander is the old hardcoded expansion for federation
var LegacyFederationCategoryExpander CategoryExpander = SimpleCategoryExpander{
Expansions: map[string][]schema.GroupResource{
"all": {{Group: "", Resource: "services"}},
},
}

View File

@ -0,0 +1,65 @@
/*
Copyright 2017 The Kubernetes Authors.
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 resource
import (
"reflect"
"testing"
"k8s.io/apimachinery/pkg/runtime/schema"
)
func TestCategoryExpansion(t *testing.T) {
tests := []struct {
name string
arg string
expected []schema.GroupResource
expectedOk bool
}{
{
name: "no-replacement",
arg: "service",
expected: nil,
},
{
name: "all-replacement",
arg: "all",
expected: []schema.GroupResource{
{Resource: "pods"},
{Resource: "replicationcontrollers"},
{Resource: "services"},
{Resource: "statefulsets", Group: "apps"},
{Resource: "horizontalpodautoscalers", Group: "autoscaling"},
{Resource: "jobs", Group: "batch"},
{Resource: "deployments", Group: "extensions"},
{Resource: "replicasets", Group: "extensions"},
},
expectedOk: true,
},
}
for _, test := range tests {
actual, actualOk := LegacyCategoryExpander.Expand(test.arg)
if e, a := test.expected, actual; !reflect.DeepEqual(e, a) {
t.Errorf("%s: expected %s, got %s", test.name, e, a)
}
if e, a := test.expectedOk, actualOk; e != a {
t.Errorf("%s: expected %v, got %v", test.name, e, a)
}
}
}

View File

@ -171,10 +171,6 @@ func (t *thirdPartyResourceDataMapper) RESTMappings(gk schema.GroupKind, version
return mappings, nil
}
func (t *thirdPartyResourceDataMapper) AliasesForResource(resource string) ([]string, bool) {
return t.mapper.AliasesForResource(resource)
}
func (t *thirdPartyResourceDataMapper) ResourceSingularizer(resource string) (singular string, err error) {
return t.mapper.ResourceSingularizer(resource)
}

View File

@ -142,6 +142,5 @@ type RESTMapper interface {
// the provided version(s).
RESTMappings(gk schema.GroupKind, versions ...string) ([]*RESTMapping, error)
AliasesForResource(resource string) ([]string, bool)
ResourceSingularizer(resource string) (singular string, err error)
}

View File

@ -22,7 +22,6 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/sets"
)
// MultiRESTMapper is a wrapper for multiple RESTMappers.
@ -209,23 +208,3 @@ func (m MultiRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) (
}
return allMappings, nil
}
// AliasesForResource finds the first alias response for the provided mappers.
func (m MultiRESTMapper) AliasesForResource(alias string) ([]string, bool) {
seenAliases := sets.NewString()
allAliases := []string{}
handled := false
for _, t := range m {
if currAliases, currOk := t.AliasesForResource(alias); currOk {
for _, currAlias := range currAliases {
if !seenAliases.Has(currAlias) {
allAliases = append(allAliases, currAlias)
seenAliases.Insert(currAlias)
}
}
handled = true
}
}
return allAliases, handled
}

View File

@ -350,10 +350,6 @@ func (m fixedRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string) (
return m.mappings, m.err
}
func (m fixedRESTMapper) AliasesForResource(alias string) (aliases []string, ok bool) {
return nil, false
}
func (m fixedRESTMapper) ResourceIsValid(resource schema.GroupVersionResource) bool {
return false
}

View File

@ -209,10 +209,6 @@ func (m PriorityRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string
return m.Delegate.RESTMappings(gk, versions...)
}
func (m PriorityRESTMapper) AliasesForResource(alias string) (aliases []string, ok bool) {
return m.Delegate.AliasesForResource(alias)
}
func (m PriorityRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
return m.Delegate.ResourceSingularizer(resource)
}

View File

@ -79,9 +79,6 @@ type DefaultRESTMapper struct {
pluralToSingular map[schema.GroupVersionResource]schema.GroupVersionResource
interfacesFunc VersionInterfacesFunc
// aliasToResource is used for mapping aliases to resources
aliasToResource map[string][]string
}
func (m *DefaultRESTMapper) String() string {
@ -105,7 +102,6 @@ func NewDefaultRESTMapper(defaultGroupVersions []schema.GroupVersion, f VersionI
kindToScope := make(map[schema.GroupVersionKind]RESTScope)
singularToPlural := make(map[schema.GroupVersionResource]schema.GroupVersionResource)
pluralToSingular := make(map[schema.GroupVersionResource]schema.GroupVersionResource)
aliasToResource := make(map[string][]string)
// TODO: verify name mappings work correctly when versions differ
return &DefaultRESTMapper{
@ -115,7 +111,6 @@ func NewDefaultRESTMapper(defaultGroupVersions []schema.GroupVersion, f VersionI
defaultGroupVersions: defaultGroupVersions,
singularToPlural: singularToPlural,
pluralToSingular: pluralToSingular,
aliasToResource: aliasToResource,
interfacesFunc: f,
}
}
@ -548,19 +543,3 @@ func (m *DefaultRESTMapper) RESTMappings(gk schema.GroupKind, versions ...string
}
return mappings, nil
}
// AddResourceAlias maps aliases to resources
func (m *DefaultRESTMapper) AddResourceAlias(alias string, resources ...string) {
if len(resources) == 0 {
return
}
m.aliasToResource[alias] = resources
}
// AliasesForResource returns whether a resource has an alias or not
func (m *DefaultRESTMapper) AliasesForResource(alias string) ([]string, bool) {
if res, ok := m.aliasToResource[alias]; ok {
return res, true
}
return nil, false
}

View File

@ -277,20 +277,6 @@ func (d *DeferredDiscoveryRESTMapper) RESTMappings(gk schema.GroupKind, versions
return
}
// AliasesForResource returns whether a resource has an alias or not.
func (d *DeferredDiscoveryRESTMapper) AliasesForResource(resource string) (as []string, ok bool) {
del, err := d.getDelegate()
if err != nil {
return nil, false
}
as, ok = del.AliasesForResource(resource)
if len(as) == 0 && !d.cl.Fresh() {
d.Reset()
as, ok = d.AliasesForResource(resource)
}
return
}
// ResourceSingularizer converts a resource name from plural to
// singular (e.g., from pods to pod).
func (d *DeferredDiscoveryRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {