simplify resource builder usage

This commit is contained in:
David Eads 2018-04-27 11:38:34 -04:00
parent 54cf942a05
commit b8aa7baa7d
47 changed files with 403 additions and 358 deletions

View File

@ -102,6 +102,7 @@ go_library(
"//vendor/github.com/renstrom/dedent:go_default_library", "//vendor/github.com/renstrom/dedent:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library", "//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library", "//vendor/github.com/spf13/pflag:go_default_library",
"//vendor/k8s.io/api/autoscaling/v1:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/api/policy/v1beta1:go_default_library", "//vendor/k8s.io/api/policy/v1beta1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
@ -129,7 +130,9 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library", "//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
"//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library", "//vendor/k8s.io/apiserver/pkg/util/flag:go_default_library",
"//vendor/k8s.io/client-go/discovery:go_default_library", "//vendor/k8s.io/client-go/discovery:go_default_library",
"//vendor/k8s.io/client-go/dynamic:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library", "//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/typed/autoscaling/v1:go_default_library",
"//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library", "//vendor/k8s.io/client-go/kubernetes/typed/core/v1:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library", "//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/scale:go_default_library", "//vendor/k8s.io/client-go/scale:go_default_library",

View File

@ -38,6 +38,7 @@ import (
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/strategicpatch" "k8s.io/apimachinery/pkg/util/strategicpatch"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/dynamic"
scaleclient "k8s.io/client-go/scale" scaleclient "k8s.io/client-go/scale"
oapi "k8s.io/kube-openapi/pkg/util/proto" oapi "k8s.io/kube-openapi/pkg/util/proto"
api "k8s.io/kubernetes/pkg/apis/core" api "k8s.io/kubernetes/pkg/apis/core"
@ -285,8 +286,13 @@ func (o *ApplyOptions) Run(f cmdutil.Factory, cmd *cobra.Command) error {
return err return err
} }
mapper, err := f.RESTMapper()
if err != nil {
return err
}
if o.Prune { if o.Prune {
o.PruneResources, err = parsePruneResources(r.Mapper().RESTMapper, o.PruneWhitelist) o.PruneResources, err = parsePruneResources(mapper, o.PruneWhitelist)
if err != nil { if err != nil {
return err return err
} }
@ -297,7 +303,6 @@ func (o *ApplyOptions) Run(f cmdutil.Factory, cmd *cobra.Command) error {
encoder := scheme.DefaultJSONEncoder() encoder := scheme.DefaultJSONEncoder()
deserializer := scheme.Codecs.UniversalDeserializer() deserializer := scheme.Codecs.UniversalDeserializer()
mapper := r.Mapper().RESTMapper
visitedUids := sets.NewString() visitedUids := sets.NewString()
visitedNamespaces := sets.NewString() visitedNamespaces := sets.NewString()
@ -382,12 +387,16 @@ func (o *ApplyOptions) Run(f cmdutil.Factory, cmd *cobra.Command) error {
return err return err
} }
helper := resource.NewHelper(info.Client, info.Mapping) helper := resource.NewHelper(info.Client, info.Mapping)
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
}
patcher := &patcher{ patcher := &patcher{
encoder: encoder, encoder: encoder,
decoder: deserializer, decoder: deserializer,
mapping: info.Mapping, mapping: info.Mapping,
helper: helper, helper: helper,
clientFunc: f.UnstructuredClientForMapping, dynamicClient: dynamicClient,
clientsetFunc: f.ClientSet, clientsetFunc: f.ClientSet,
overwrite: o.Overwrite, overwrite: o.Overwrite,
backOff: clockwork.NewRealClock(), backOff: clockwork.NewRealClock(),
@ -470,9 +479,14 @@ func (o *ApplyOptions) Run(f cmdutil.Factory, cmd *cobra.Command) error {
return nil return nil
} }
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
}
p := pruner{ p := pruner{
mapper: mapper, mapper: mapper,
clientFunc: f.UnstructuredClientForMapping, dynamicClient: dynamicClient,
clientsetFunc: f.ClientSet, clientsetFunc: f.ClientSet,
labelSelector: o.Selector, labelSelector: o.Selector,
@ -560,7 +574,7 @@ func getRESTMappings(mapper meta.RESTMapper, pruneResources *[]pruneResource) (n
type pruner struct { type pruner struct {
mapper meta.RESTMapper mapper meta.RESTMapper
clientFunc resource.ClientMapperFunc dynamicClient dynamic.DynamicInterface
clientsetFunc func() (internalclientset.Interface, error) clientsetFunc func() (internalclientset.Interface, error)
visitedUids sets.String visitedUids sets.String
@ -577,24 +591,17 @@ type pruner struct {
} }
func (p *pruner) prune(f cmdutil.Factory, namespace string, mapping *meta.RESTMapping, includeUninitialized bool) error { func (p *pruner) prune(f cmdutil.Factory, namespace string, mapping *meta.RESTMapping, includeUninitialized bool) error {
c, err := p.clientFunc(mapping) objList, err := p.dynamicClient.Resource(mapping.GroupVersionKind.GroupVersion().WithResource(mapping.Resource)).
Namespace(namespace).
List(metav1.ListOptions{
LabelSelector: p.labelSelector,
FieldSelector: p.fieldSelector,
IncludeUninitialized: includeUninitialized,
})
if err != nil { if err != nil {
return err return err
} }
objList, err := resource.NewHelper(c, mapping).List(
namespace,
mapping.GroupVersionKind.Version,
false,
&metav1.ListOptions{
LabelSelector: p.labelSelector,
FieldSelector: p.fieldSelector,
IncludeUninitialized: includeUninitialized,
},
)
if err != nil {
return err
}
objs, err := meta.ExtractList(objList) objs, err := meta.ExtractList(objList)
if err != nil { if err != nil {
return err return err
@ -635,20 +642,12 @@ func (p *pruner) prune(f cmdutil.Factory, namespace string, mapping *meta.RESTMa
} }
func (p *pruner) delete(namespace, name string, mapping *meta.RESTMapping, scaleClient scaleclient.ScalesGetter) error { func (p *pruner) delete(namespace, name string, mapping *meta.RESTMapping, scaleClient scaleclient.ScalesGetter) error {
c, err := p.clientFunc(mapping) return runDelete(namespace, name, mapping, p.dynamicClient, p.cascade, p.gracePeriod, p.clientsetFunc, scaleClient)
if err != nil {
return err
} }
return runDelete(namespace, name, mapping, c, nil, p.cascade, p.gracePeriod, p.clientsetFunc, scaleClient) func runDelete(namespace, name string, mapping *meta.RESTMapping, c dynamic.DynamicInterface, cascade bool, gracePeriod int, clientsetFunc func() (internalclientset.Interface, error), scaleClient scaleclient.ScalesGetter) error {
}
func runDelete(namespace, name string, mapping *meta.RESTMapping, c resource.RESTClient, helper *resource.Helper, cascade bool, gracePeriod int, clientsetFunc func() (internalclientset.Interface, error), scaleClient scaleclient.ScalesGetter) error {
if !cascade { if !cascade {
if helper == nil { return c.Resource(mapping.GroupVersionKind.GroupVersion().WithResource(mapping.Resource)).Namespace(namespace).Delete(name, nil)
helper = resource.NewHelper(c, mapping)
}
return helper.Delete(namespace, name)
} }
cs, err := clientsetFunc() cs, err := clientsetFunc()
if err != nil { if err != nil {
@ -659,7 +658,7 @@ func runDelete(namespace, name string, mapping *meta.RESTMapping, c resource.RES
if _, ok := err.(*kubectl.NoSuchReaperError); !ok { if _, ok := err.(*kubectl.NoSuchReaperError); !ok {
return err return err
} }
return resource.NewHelper(c, mapping).Delete(namespace, name) return c.Resource(mapping.GroupVersionKind.GroupVersion().WithResource(mapping.Resource)).Namespace(namespace).Delete(name, nil)
} }
var options *metav1.DeleteOptions var options *metav1.DeleteOptions
if gracePeriod >= 0 { if gracePeriod >= 0 {
@ -672,11 +671,7 @@ func runDelete(namespace, name string, mapping *meta.RESTMapping, c resource.RES
} }
func (p *patcher) delete(namespace, name string) error { func (p *patcher) delete(namespace, name string) error {
c, err := p.clientFunc(p.mapping) return runDelete(namespace, name, p.mapping, p.dynamicClient, p.cascade, p.gracePeriod, p.clientsetFunc, p.scaleClient)
if err != nil {
return err
}
return runDelete(namespace, name, p.mapping, c, p.helper, p.cascade, p.gracePeriod, p.clientsetFunc, p.scaleClient)
} }
type patcher struct { type patcher struct {
@ -685,7 +680,7 @@ type patcher struct {
mapping *meta.RESTMapping mapping *meta.RESTMapping
helper *resource.Helper helper *resource.Helper
clientFunc resource.ClientMapperFunc dynamicClient dynamic.DynamicInterface
clientsetFunc func() (internalclientset.Interface, error) clientsetFunc func() (internalclientset.Interface, error)
overwrite bool overwrite bool

View File

@ -146,7 +146,7 @@ func (p *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn [
} }
builder := f.NewBuilder(). builder := f.NewBuilder().
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
NamespaceParam(namespace).DefaultNamespace() NamespaceParam(namespace).DefaultNamespace()
switch len(argsIn) { switch len(argsIn) {

View File

@ -96,7 +96,7 @@ func (o *ReconcileOptions) Complete(cmd *cobra.Command, f cmdutil.Factory, args
} }
r := f.NewBuilder(). r := f.NewBuilder().
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
ContinueOnError(). ContinueOnError().
NamespaceParam(namespace).DefaultNamespace(). NamespaceParam(namespace).DefaultNamespace().
FilenameParam(enforceNamespace, options). FilenameParam(enforceNamespace, options).

View File

@ -22,8 +22,10 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"github.com/spf13/cobra" "github.com/spf13/cobra"
autoscalingv1 "k8s.io/api/autoscaling/v1"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
autoscalingv1client "k8s.io/client-go/kubernetes/typed/autoscaling/v1"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
@ -70,11 +72,11 @@ type AutoscaleOptions struct {
namespace string namespace string
dryRun bool dryRun bool
builder *resource.Builder builder *resource.Builder
mapper meta.RESTMapper
canBeAutoscaled func(kind schema.GroupKind) error canBeAutoscaled func(kind schema.GroupKind) error
clientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
generatorFunc func(string, *meta.RESTMapping) (kubectl.StructuredGenerator, error) generatorFunc func(string, *meta.RESTMapping) (kubectl.StructuredGenerator, error)
HPAClient autoscalingv1client.HorizontalPodAutoscalersGetter
genericclioptions.IOStreams genericclioptions.IOStreams
} }
@ -132,12 +134,6 @@ func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
o.createAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) o.createAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
o.builder = f.NewBuilder() o.builder = f.NewBuilder()
o.canBeAutoscaled = f.CanBeAutoscaled o.canBeAutoscaled = f.CanBeAutoscaled
o.mapper, err = f.RESTMapper()
if err != nil {
return err
}
o.clientForMapping = f.ClientForMapping
o.args = args o.args = args
o.RecordFlags.Complete(f.Command(cmd, false)) o.RecordFlags.Complete(f.Command(cmd, false))
@ -146,6 +142,12 @@ func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
return err return err
} }
kubeClient, err := f.KubernetesClientSet()
if err != nil {
return err
}
o.HPAClient = kubeClient.AutoscalingV1()
// get the generator // get the generator
o.generatorFunc = func(name string, mapping *meta.RESTMapping) (kubectl.StructuredGenerator, error) { o.generatorFunc = func(name string, mapping *meta.RESTMapping) (kubectl.StructuredGenerator, error) {
switch o.Generator { switch o.Generator {
@ -199,7 +201,7 @@ func (o *AutoscaleOptions) Validate() error {
func (o *AutoscaleOptions) Run() error { func (o *AutoscaleOptions) Run() error {
r := o.builder. r := o.builder.
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
ContinueOnError(). ContinueOnError().
NamespaceParam(o.namespace).DefaultNamespace(). NamespaceParam(o.namespace).DefaultNamespace().
FilenameParam(o.enforceNamespace, o.FilenameOptions). FilenameParam(o.enforceNamespace, o.FilenameOptions).
@ -231,20 +233,14 @@ func (o *AutoscaleOptions) Run() error {
if err != nil { if err != nil {
return err return err
} }
hpa, ok := object.(*autoscalingv1.HorizontalPodAutoscaler)
if !ok {
return fmt.Errorf("generator made %T, not autoscalingv1.HorizontalPodAutoscaler", object)
}
resourceMapper := &resource.Mapper{ if err := o.Recorder.Record(hpa); err != nil {
RESTMapper: o.mapper,
ClientMapper: resource.ClientMapperFunc(o.clientForMapping),
Decoder: cmdutil.InternalVersionDecoder(),
}
hpa, err := resourceMapper.InfoForObject(object, legacyscheme.Scheme, nil)
if err != nil {
return err
}
if err := o.Recorder.Record(hpa.Object); err != nil {
glog.V(4).Infof("error recording current command: %v", err) glog.V(4).Infof("error recording current command: %v", err)
} }
object = hpa.Object
if o.dryRun { if o.dryRun {
count++ count++
@ -253,14 +249,14 @@ func (o *AutoscaleOptions) Run() error {
if err != nil { if err != nil {
return err return err
} }
return printer.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(hpa.Object, hpa.Mapping), o.Out) return printer.PrintObj(hpa, o.Out)
} }
if err := kubectl.CreateOrUpdateAnnotation(o.createAnnotation, hpa.Object, cmdutil.InternalVersionJSONEncoder()); err != nil { if err := kubectl.CreateOrUpdateAnnotation(o.createAnnotation, hpa, cmdutil.InternalVersionJSONEncoder()); err != nil {
return err return err
} }
_, err = resource.NewHelper(hpa.Client, hpa.Mapping).Create(o.namespace, false, object) actualHPA, err := o.HPAClient.HorizontalPodAutoscalers(o.namespace).Create(hpa)
if err != nil { if err != nil {
return err return err
} }
@ -270,7 +266,7 @@ func (o *AutoscaleOptions) Run() error {
if err != nil { if err != nil {
return err return err
} }
return printer.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(info.Object, hpa.Mapping), o.Out) return printer.PrintObj(actualHPA, o.Out)
}) })
if err != nil { if err != nil {
return err return err

View File

@ -204,7 +204,7 @@ func (o *CertificateOptions) RunCertificateDeny(force bool) error {
func (options *CertificateOptions) modifyCertificateCondition(builder *resource.Builder, clientSet internalclientset.Interface, force bool, modify func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool)) error { func (options *CertificateOptions) modifyCertificateCondition(builder *resource.Builder, clientSet internalclientset.Interface, force bool, modify func(csr *certificates.CertificateSigningRequest) (*certificates.CertificateSigningRequest, bool)) error {
var found int var found int
r := builder. r := builder.
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
ContinueOnError(). ContinueOnError().
FilenameParam(false, &options.FilenameOptions). FilenameParam(false, &options.FilenameOptions).
ResourceNames("certificatesigningrequest", options.csrNames...). ResourceNames("certificatesigningrequest", options.csrNames...).

View File

@ -96,7 +96,7 @@ func (o *ClusterInfoOptions) Run() error {
// TODO use generalized labels once they are implemented (#341) // TODO use generalized labels once they are implemented (#341)
b := o.Builder. b := o.Builder.
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
NamespaceParam(o.Namespace).DefaultNamespace(). NamespaceParam(o.Namespace).DefaultNamespace().
LabelSelectorParam("kubernetes.io/cluster-service=true"). LabelSelectorParam("kubernetes.io/cluster-service=true").
ResourceTypeOrNameArgs(false, []string{"services"}...). ResourceTypeOrNameArgs(false, []string{"services"}...).

View File

@ -129,7 +129,7 @@ func (o *ConvertOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) (err er
// build the builder // build the builder
o.builder = f.NewBuilder(). o.builder = f.NewBuilder().
Internal(scheme.Scheme). WithScheme(scheme.Scheme).
LocalParam(o.local) LocalParam(o.local)
if !o.local { if !o.local {
schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate")) schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"))

View File

@ -41,6 +41,7 @@ go_library(
"//vendor/k8s.io/api/rbac/v1:go_default_library", "//vendor/k8s.io/api/rbac/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",

View File

@ -29,6 +29,7 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
kruntime "k8s.io/apimachinery/pkg/runtime" kruntime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
@ -404,29 +405,29 @@ func RunCreateSubcommand(f cmdutil.Factory, options *CreateSubcommandOptions) er
if err != nil { if err != nil {
return err return err
} }
client, err := f.ClientForMapping(mapping)
if err != nil { if err := kubectl.CreateOrUpdateAnnotation(options.CreateAnnotation, obj, cmdutil.InternalVersionJSONEncoder()); err != nil {
return err
}
resourceMapper := &resource.Mapper{
RESTMapper: mapper,
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
}
info, err := resourceMapper.InfoForObject(obj, legacyscheme.Scheme, nil)
if err != nil {
return err
}
if err := kubectl.CreateOrUpdateAnnotation(options.CreateAnnotation, info.Object, cmdutil.InternalVersionJSONEncoder()); err != nil {
return err return err
} }
obj, err = resource.NewHelper(client, mapping).Create(namespace, false, info.Object) asUnstructured := &unstructured.Unstructured{}
if err := legacyscheme.Scheme.Convert(obj, asUnstructured, nil); err != nil {
return err
}
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
}
if mapping.Scope.Name() == meta.RESTScopeNameRoot {
namespace = ""
}
actualObject, err := dynamicClient.Resource(mapping.GroupVersionKind.GroupVersion().WithResource(mapping.Resource)).Namespace(namespace).Create(asUnstructured)
if err != nil { if err != nil {
return err return err
} }
// ensure we pass a versioned object to the printer // ensure we pass a versioned object to the printer
obj = cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping) obj = actualObject
} else { } else {
if meta, err := meta.Accessor(obj); err == nil && nsOverriden { if meta, err := meta.Accessor(obj); err == nil && nsOverriden {
meta.SetNamespace(namespace) meta.SetNamespace(namespace)

View File

@ -17,41 +17,16 @@ limitations under the License.
package create package create
import ( import (
"net/http"
"testing" "testing"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api/legacyscheme"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions" "k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/scheme"
) )
func TestCreateQuota(t *testing.T) { func TestCreateQuota(t *testing.T) {
resourceQuotaObject := &v1.ResourceQuota{} resourceQuotaObject := &v1.ResourceQuota{}
resourceQuotaObject.Name = "my-quota" resourceQuotaObject.Name = "my-quota"
tf := cmdtesting.NewTestFactory()
defer tf.Cleanup()
codec := legacyscheme.Codecs.LegacyCodec(scheme.Versions...)
ns := legacyscheme.Codecs
tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Version: "v1"},
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == "/namespaces/test/resourcequotas" && m == "POST":
return &http.Response{StatusCode: 201, Header: defaultHeader(), Body: objBody(codec, resourceQuotaObject)}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
}
}),
}
tf.Namespace = "test"
tests := map[string]struct { tests := map[string]struct {
flags []string flags []string
@ -75,6 +50,12 @@ func TestCreateQuota(t *testing.T) {
}, },
} }
for name, test := range tests { for name, test := range tests {
t.Run(name, func(t *testing.T) {
tf := cmdtesting.NewTestFactory()
defer tf.Cleanup()
tf.Namespace = "test"
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams() ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
cmd := NewCmdCreateQuota(tf, ioStreams) cmd := NewCmdCreateQuota(tf, ioStreams)
cmd.Flags().Parse(test.flags) cmd.Flags().Parse(test.flags)
@ -84,5 +65,6 @@ func TestCreateQuota(t *testing.T) {
if buf.String() != test.expectedOutput { if buf.String() != test.expectedOutput {
t.Errorf("%s: expected output: %s, but got: %s", name, test.expectedOutput, buf.String()) t.Errorf("%s: expected output: %s, but got: %s", name, test.expectedOutput, buf.String())
} }
})
} }
} }

View File

@ -174,7 +174,11 @@ func (o *DeleteOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, args
return err return err
} }
o.Result = r o.Result = r
o.Mapper = r.Mapper().RESTMapper
o.Mapper, err = f.RESTMapper()
if err != nil {
return err
}
// Set up writer // Set up writer
o.Out = out o.Out = out

View File

@ -282,7 +282,7 @@ func (o *DrainOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st
} }
builder := f.NewBuilder(). builder := f.NewBuilder().
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
NamespaceParam(o.Namespace).DefaultNamespace(). NamespaceParam(o.Namespace).DefaultNamespace().
ResourceNames("nodes", args...). ResourceNames("nodes", args...).
SingleResourceType(). SingleResourceType().

View File

@ -32,7 +32,7 @@ import (
yaml "gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/diff" "k8s.io/apimachinery/pkg/util/diff"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
@ -211,12 +211,12 @@ func TestEdit(t *testing.T) {
tf := cmdtesting.NewTestFactory() tf := cmdtesting.NewTestFactory()
defer tf.Cleanup() defer tf.Cleanup()
tf.UnstructuredClientForMappingFunc = func(mapping *meta.RESTMapping) (resource.RESTClient, error) { tf.UnstructuredClientForMappingFunc = func(gv schema.GroupVersion) (resource.RESTClient, error) {
versionedAPIPath := "" versionedAPIPath := ""
if mapping.GroupVersionKind.Group == "" { if gv.Group == "" {
versionedAPIPath = "/api/" + mapping.GroupVersionKind.Version versionedAPIPath = "/api/" + gv.Version
} else { } else {
versionedAPIPath = "/apis/" + mapping.GroupVersionKind.Group + "/" + mapping.GroupVersionKind.Version versionedAPIPath = "/apis/" + gv.Group + "/" + gv.Version
} }
return &fake.RESTClient{ return &fake.RESTClient{
VersionedAPIPath: versionedAPIPath, VersionedAPIPath: versionedAPIPath,

View File

@ -24,9 +24,12 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation"
"k8s.io/client-go/dynamic"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
@ -97,6 +100,7 @@ type ExposeServiceOptions struct {
Namespace string Namespace string
Mapper meta.RESTMapper Mapper meta.RESTMapper
DynamicClient dynamic.DynamicInterface
Builder *resource.Builder Builder *resource.Builder
Recorder genericclioptions.Recorder Recorder genericclioptions.Recorder
@ -180,6 +184,11 @@ func (o *ExposeServiceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) e
return err return err
} }
o.DynamicClient, err = f.DynamicClient()
if err != nil {
return err
}
o.Generators = f.Generators o.Generators = f.Generators
o.Builder = f.NewBuilder() o.Builder = f.NewBuilder()
o.CanBeExposed = f.CanBeExposed o.CanBeExposed = f.CanBeExposed
@ -203,7 +212,7 @@ func (o *ExposeServiceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) e
func (o *ExposeServiceOptions) RunExpose(cmd *cobra.Command, args []string) error { func (o *ExposeServiceOptions) RunExpose(cmd *cobra.Command, args []string) error {
r := o.Builder. r := o.Builder.
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
ContinueOnError(). ContinueOnError().
NamespaceParam(o.Namespace).DefaultNamespace(). NamespaceParam(o.Namespace).DefaultNamespace().
FilenameParam(o.EnforceNamespace, &o.FilenameOptions). FilenameParam(o.EnforceNamespace, &o.FilenameOptions).
@ -313,33 +322,36 @@ func (o *ExposeServiceOptions) RunExpose(cmd *cobra.Command, args []string) erro
} }
} }
resourceMapper := &resource.Mapper{
RESTMapper: o.Mapper,
ClientMapper: resource.ClientMapperFunc(o.ClientForMapping),
Decoder: cmdutil.InternalVersionDecoder(),
}
info, err = resourceMapper.InfoForObject(object, legacyscheme.Scheme, nil)
if err != nil {
return err
}
if err := o.Recorder.Record(object); err != nil { if err := o.Recorder.Record(object); err != nil {
glog.V(4).Infof("error recording current command: %v", err) glog.V(4).Infof("error recording current command: %v", err)
} }
info.Refresh(object, true)
if o.DryRun { if o.DryRun {
return o.PrintObj(object, o.Out) return o.PrintObj(object, o.Out)
} }
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info.Object, cmdutil.InternalVersionJSONEncoder()); err != nil { if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), object, cmdutil.InternalVersionJSONEncoder()); err != nil {
return err return err
} }
asUnstructured := &unstructured.Unstructured{}
if err := legacyscheme.Scheme.Convert(object, asUnstructured, nil); err != nil {
return err
}
gvks, _, err := unstructuredscheme.NewUnstructuredObjectTyper().ObjectKinds(asUnstructured)
if err != nil {
return err
}
objMapping, err := o.Mapper.RESTMapping(gvks[0].GroupKind(), gvks[0].Version)
if err != nil {
return err
}
// Serialize the object with the annotation applied. // Serialize the object with the annotation applied.
object, err = resource.NewHelper(info.Client, info.Mapping).Create(o.Namespace, false, object) actualObject, err := o.DynamicClient.Resource(objMapping.GroupVersionKind.GroupVersion().WithResource(objMapping.Resource)).Namespace(o.Namespace).Create(asUnstructured)
if err != nil { if err != nil {
return err return err
} }
return o.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping), o.Out) return o.PrintObj(actualObject, o.Out)
}) })
if err != nil { if err != nil {
return err return err

View File

@ -480,8 +480,6 @@ func TestRunExposeService(t *testing.T) {
switch p, m := req.URL.Path, req.Method; { switch p, m := req.URL.Path, req.Method; {
case p == test.calls[m] && m == "GET": case p == test.calls[m] && m == "GET":
return &http.Response{StatusCode: test.status, Header: defaultHeader(), Body: objBody(codec, test.input)}, nil return &http.Response{StatusCode: test.status, Header: defaultHeader(), Body: objBody(codec, test.input)}, nil
case p == test.calls[m] && m == "POST":
return &http.Response{StatusCode: test.status, Header: defaultHeader(), Body: objBody(codec, test.output)}, nil
default: default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req) t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil return nil, nil

View File

@ -202,7 +202,7 @@ func (o *LogsOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.Comm
if o.Object == nil { if o.Object == nil {
builder := f.NewBuilder(). builder := f.NewBuilder().
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
NamespaceParam(o.Namespace).DefaultNamespace(). NamespaceParam(o.Namespace).DefaultNamespace().
SingleResourceType() SingleResourceType()
if o.ResourceArg != "" { if o.ResourceArg != "" {

View File

@ -180,7 +180,7 @@ func (o *PortForwardOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, arg
} }
builder := f.NewBuilder(). builder := f.NewBuilder().
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
ContinueOnError(). ContinueOnError().
NamespaceParam(o.Namespace).DefaultNamespace() NamespaceParam(o.Namespace).DefaultNamespace()

View File

@ -82,7 +82,7 @@ func RunHistory(f cmdutil.Factory, cmd *cobra.Command, out io.Writer, args []str
} }
r := f.NewBuilder(). r := f.NewBuilder().
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
NamespaceParam(cmdNamespace).DefaultNamespace(). NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, options). FilenameParam(enforceNamespace, options).
ResourceTypeOrNameArgs(true, args...). ResourceTypeOrNameArgs(true, args...).

View File

@ -111,7 +111,7 @@ func (o *PauseConfig) CompletePause(f cmdutil.Factory, cmd *cobra.Command, args
} }
r := f.NewBuilder(). r := f.NewBuilder().
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
NamespaceParam(cmdNamespace).DefaultNamespace(). NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions). FilenameParam(enforceNamespace, &o.FilenameOptions).
ResourceTypeOrNameArgs(true, args...). ResourceTypeOrNameArgs(true, args...).

View File

@ -119,7 +119,7 @@ func (o *ResumeConfig) CompleteResume(f cmdutil.Factory, cmd *cobra.Command, arg
} }
r := f.NewBuilder(). r := f.NewBuilder().
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
NamespaceParam(cmdNamespace).DefaultNamespace(). NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions). FilenameParam(enforceNamespace, &o.FilenameOptions).
ResourceTypeOrNameArgs(true, args...). ResourceTypeOrNameArgs(true, args...).

View File

@ -124,7 +124,7 @@ func (o *RolloutStatusOptions) Validate(cmd *cobra.Command, args []string) error
func (o *RolloutStatusOptions) Run() error { func (o *RolloutStatusOptions) Run() error {
r := o.Builder. r := o.Builder.
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
NamespaceParam(o.Namespace).DefaultNamespace(). NamespaceParam(o.Namespace).DefaultNamespace().
FilenameParam(o.EnforceNamespace, o.FilenameOptions). FilenameParam(o.EnforceNamespace, o.FilenameOptions).
ResourceTypeOrNameArgs(true, o.BuilderArgs...). ResourceTypeOrNameArgs(true, o.BuilderArgs...).

View File

@ -127,7 +127,7 @@ func (o *UndoOptions) CompleteUndo(f cmdutil.Factory, cmd *cobra.Command, out io
} }
r := f.NewBuilder(). r := f.NewBuilder().
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
NamespaceParam(cmdNamespace).DefaultNamespace(). NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions). FilenameParam(enforceNamespace, &o.FilenameOptions).
ResourceTypeOrNameArgs(true, args...). ResourceTypeOrNameArgs(true, args...).

View File

@ -20,6 +20,7 @@ import (
"fmt" "fmt"
"io" "io"
"k8s.io/client-go/dynamic"
"k8s.io/kubernetes/pkg/printers" "k8s.io/kubernetes/pkg/printers"
"github.com/docker/distribution/reference" "github.com/docker/distribution/reference"
@ -40,6 +41,7 @@ import (
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions" "k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/kubectl/scheme"
"k8s.io/kubernetes/pkg/kubectl/util/i18n" "k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/util/interrupt" "k8s.io/kubernetes/pkg/util/interrupt"
uexec "k8s.io/utils/exec" uexec "k8s.io/utils/exec"
@ -90,9 +92,7 @@ var (
) )
type RunObject struct { type RunObject struct {
Versioned runtime.Object
Object runtime.Object Object runtime.Object
Kind string
Mapping *meta.RESTMapping Mapping *meta.RESTMapping
} }
@ -107,6 +107,8 @@ type RunOptions struct {
PrintObj func(runtime.Object) error PrintObj func(runtime.Object) error
Recorder genericclioptions.Recorder Recorder genericclioptions.Recorder
DynamicClient dynamic.DynamicInterface
ArgsLenAtDash int ArgsLenAtDash int
Attach bool Attach bool
Expose bool Expose bool
@ -197,6 +199,11 @@ func (o *RunOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
return err return err
} }
o.DynamicClient, err = f.DynamicClient()
if err != nil {
return err
}
o.ArgsLenAtDash = cmd.ArgsLenAtDash() o.ArgsLenAtDash = cmd.ArgsLenAtDash()
o.DryRun = cmdutil.GetFlagBool(cmd, "dry-run") o.DryRun = cmdutil.GetFlagBool(cmd, "dry-run")
o.Expose = cmdutil.GetFlagBool(cmd, "expose") o.Expose = cmdutil.GetFlagBool(cmd, "expose")
@ -438,7 +445,7 @@ func (o *RunOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []string) e
} }
if runObject != nil { if runObject != nil {
if err := o.PrintObj(runObject.Versioned); err != nil { if err := o.PrintObj(runObject.Object); err != nil {
return err return err
} }
} }
@ -458,7 +465,7 @@ func (o *RunOptions) removeCreatedObjects(f cmdutil.Factory, createdObjects []*R
return err return err
} }
r := f.NewBuilder(). r := f.NewBuilder().
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
ContinueOnError(). ContinueOnError().
NamespaceParam(namespace).DefaultNamespace(). NamespaceParam(namespace).DefaultNamespace().
ResourceNames(obj.Mapping.Resource.Resource+"."+obj.Mapping.Resource.Group, name). ResourceNames(obj.Mapping.Resource.Resource+"."+obj.Mapping.Resource.Group, name).
@ -620,7 +627,7 @@ func (o *RunOptions) generateService(f cmdutil.Factory, cmd *cobra.Command, serv
return nil, err return nil, err
} }
if err := o.PrintObj(runObject.Versioned); err != nil { if err := o.PrintObj(runObject.Object); err != nil {
return nil, err return nil, err
} }
// separate yaml objects // separate yaml objects
@ -648,60 +655,45 @@ func (o *RunOptions) createGeneratedObject(f cmdutil.Factory, cmd *cobra.Command
return nil, err return nil, err
} }
// run has compiled knowledge of the thing is is creating // run has compiled knowledge of the thing is is creating
groupVersionKinds, _, err := legacyscheme.Scheme.ObjectKinds(obj) gvks, _, err := scheme.Scheme.ObjectKinds(obj)
if err != nil {
return nil, err
}
mapping, err := mapper.RESTMapping(gvks[0].GroupKind(), gvks[0].Version)
if err != nil { if err != nil {
return nil, err return nil, err
} }
groupVersionKind := groupVersionKinds[0]
if len(overrides) > 0 { if len(overrides) > 0 {
codec := runtime.NewCodec(cmdutil.InternalVersionJSONEncoder(), cmdutil.InternalVersionDecoder()) codec := runtime.NewCodec(scheme.DefaultJSONEncoder(), scheme.Codecs.UniversalDecoder(scheme.Registry.RegisteredGroupVersions()...))
obj, err = cmdutil.Merge(codec, obj, overrides) obj, err = cmdutil.Merge(codec, obj, overrides)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
mapping, err := mapper.RESTMapping(groupVersionKind.GroupKind(), groupVersionKind.Version) if err := o.Recorder.Record(obj); err != nil {
if err != nil { glog.V(4).Infof("error recording current command: %v", err)
}
actualObj := obj
if !o.DryRun {
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), obj, scheme.DefaultJSONEncoder()); err != nil {
return nil, err return nil, err
} }
client, err := f.ClientForMapping(mapping) client, err := f.ClientForMapping(mapping)
if err != nil { if err != nil {
return nil, err return nil, err
} }
actualObj, err = resource.NewHelper(client, mapping).Create(namespace, false, obj)
if err := o.Recorder.Record(obj); err != nil {
glog.V(4).Infof("error recording current command: %v", err)
}
versioned := obj
if !o.DryRun {
resourceMapper := &resource.Mapper{
RESTMapper: mapper,
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
Decoder: cmdutil.InternalVersionDecoder(),
}
info, err := resourceMapper.InfoForObject(obj, legacyscheme.Scheme, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info.Object, cmdutil.InternalVersionJSONEncoder()); err != nil {
return nil, err
} }
actualObj = cmdutil.AsDefaultVersionedOrOriginal(actualObj, mapping)
obj, err = resource.NewHelper(client, mapping).Create(namespace, false, info.Object)
if err != nil {
return nil, err
}
versioned = cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping)
}
return &RunObject{ return &RunObject{
Versioned: versioned, Object: actualObj,
Object: obj,
Kind: groupVersionKind.Kind,
Mapping: mapping, Mapping: mapping,
}, nil }, nil
} }

View File

@ -33,7 +33,6 @@ go_library(
"//vendor/github.com/spf13/cobra:go_default_library", "//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library", "//vendor/k8s.io/apimachinery/pkg/types:go_default_library",

View File

@ -241,7 +241,7 @@ func (o *EnvOptions) RunEnv() error {
if len(o.From) != 0 { if len(o.From) != 0 {
b := o.builder(). b := o.builder().
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
LocalParam(o.Local). LocalParam(o.Local).
ContinueOnError(). ContinueOnError().
NamespaceParam(o.namespace).DefaultNamespace(). NamespaceParam(o.namespace).DefaultNamespace().
@ -309,7 +309,7 @@ func (o *EnvOptions) RunEnv() error {
} }
b := o.builder(). b := o.builder().
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
LocalParam(o.Local). LocalParam(o.Local).
ContinueOnError(). ContinueOnError().
NamespaceParam(o.namespace).DefaultNamespace(). NamespaceParam(o.namespace).DefaultNamespace().

View File

@ -161,7 +161,7 @@ func (o *SetImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false) includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
builder := f.NewBuilder(). builder := f.NewBuilder().
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
LocalParam(o.Local). LocalParam(o.Local).
ContinueOnError(). ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace(). NamespaceParam(cmdNamespace).DefaultNamespace().

View File

@ -173,7 +173,7 @@ func (o *SetResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, ar
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false) includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
builder := f.NewBuilder(). builder := f.NewBuilder().
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
LocalParam(o.Local). LocalParam(o.Local).
ContinueOnError(). ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace(). NamespaceParam(cmdNamespace).DefaultNamespace().

View File

@ -146,7 +146,7 @@ func (o *SetSelectorOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, arg
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false) includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
o.builder = f.NewBuilder(). o.builder = f.NewBuilder().
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
LocalParam(o.local). LocalParam(o.local).
ContinueOnError(). ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace(). NamespaceParam(cmdNamespace).DefaultNamespace().

View File

@ -152,7 +152,7 @@ func (o *SetServiceAccountOptions) Complete(f cmdutil.Factory, cmd *cobra.Comman
resources := args[:len(args)-1] resources := args[:len(args)-1]
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false) includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
builder := f.NewBuilder(). builder := f.NewBuilder().
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
LocalParam(o.local). LocalParam(o.local).
ContinueOnError(). ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace(). NamespaceParam(cmdNamespace).DefaultNamespace().

View File

@ -138,7 +138,7 @@ func (o *SubjectOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false) includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
builder := f.NewBuilder(). builder := f.NewBuilder().
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
LocalParam(o.Local). LocalParam(o.Local).
ContinueOnError(). ContinueOnError().
NamespaceParam(o.namespace).DefaultNamespace(). NamespaceParam(o.namespace).DefaultNamespace().

View File

@ -172,7 +172,7 @@ func (o *TaintOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st
return cmdutil.UsageErrorf(cmd, err.Error()) return cmdutil.UsageErrorf(cmd, err.Error())
} }
o.builder = f.NewBuilder(). o.builder = f.NewBuilder().
Internal(legacyscheme.Scheme). WithScheme(legacyscheme.Scheme).
ContinueOnError(). ContinueOnError().
NamespaceParam(namespace).DefaultNamespace() NamespaceParam(namespace).DefaultNamespace()
if o.selector != "" { if o.selector != "" {

View File

@ -24,11 +24,12 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta/testrestmapper:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/meta/testrestmapper:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
"//vendor/k8s.io/client-go/discovery:go_default_library", "//vendor/k8s.io/client-go/discovery:go_default_library",
"//vendor/k8s.io/client-go/dynamic:go_default_library",
"//vendor/k8s.io/client-go/dynamic/fake:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library", "//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library", "//vendor/k8s.io/client-go/rest:go_default_library",
"//vendor/k8s.io/client-go/rest/fake:go_default_library", "//vendor/k8s.io/client-go/rest/fake:go_default_library",

View File

@ -30,11 +30,12 @@ import (
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/api/meta/testrestmapper" "k8s.io/apimachinery/pkg/api/meta/testrestmapper"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/client-go/discovery" "k8s.io/client-go/discovery"
"k8s.io/client-go/dynamic"
fakedynamic "k8s.io/client-go/dynamic/fake"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
@ -241,10 +242,11 @@ type TestFactory struct {
Namespace string Namespace string
ClientConfigVal *restclient.Config ClientConfigVal *restclient.Config
CommandVal string CommandVal string
FakeDynamicClient *fakedynamic.FakeDynamicClient
tempConfigFile *os.File tempConfigFile *os.File
UnstructuredClientForMappingFunc func(mapping *meta.RESTMapping) (resource.RESTClient, error) UnstructuredClientForMappingFunc resource.FakeClientFunc
OpenAPISchemaFunc func() (openapi.Resources, error) OpenAPISchemaFunc func() (openapi.Resources, error)
} }
@ -254,6 +256,7 @@ func NewTestFactory() *TestFactory {
config, configFile := defaultFakeClientConfig() config, configFile := defaultFakeClientConfig()
return &TestFactory{ return &TestFactory{
Factory: cmdutil.NewFactory(config), Factory: cmdutil.NewFactory(config),
FakeDynamicClient: fakedynamic.NewSimpleDynamicClient(legacyscheme.Scheme),
tempConfigFile: configFile, tempConfigFile: configFile,
} }
} }
@ -309,7 +312,7 @@ func (f *TestFactory) ClientForMapping(mapping *meta.RESTMapping) (resource.REST
func (f *TestFactory) UnstructuredClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error) { func (f *TestFactory) UnstructuredClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error) {
if f.UnstructuredClientForMappingFunc != nil { if f.UnstructuredClientForMappingFunc != nil {
return f.UnstructuredClientForMappingFunc(mapping) return f.UnstructuredClientForMappingFunc(mapping.GroupVersionKind.GroupVersion())
} }
return f.UnstructuredClient, nil return f.UnstructuredClient, nil
} }
@ -340,17 +343,17 @@ func (f *TestFactory) Command(*cobra.Command, bool) string {
func (f *TestFactory) NewBuilder() *resource.Builder { func (f *TestFactory) NewBuilder() *resource.Builder {
mapper, err := f.RESTMapper() mapper, err := f.RESTMapper()
return resource.NewBuilder( return resource.NewFakeBuilder(
&resource.Mapper{ func(version schema.GroupVersion) (resource.RESTClient, error) {
RESTMapper: mapper, if f.UnstructuredClientForMappingFunc != nil {
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping), return f.UnstructuredClientForMappingFunc(version)
Decoder: cmdutil.InternalVersionDecoder(), }
}, if f.UnstructuredClient != nil {
&resource.Mapper{ return f.UnstructuredClient, nil
RESTMapper: mapper, }
ClientMapper: resource.ClientMapperFunc(f.UnstructuredClientForMapping), return f.Client, nil
Decoder: unstructured.UnstructuredJSONScheme,
}, },
mapper,
f.CategoryExpander(), f.CategoryExpander(),
).AddError(err) ).AddError(err)
} }
@ -402,6 +405,13 @@ func (f *TestFactory) ClientSet() (internalclientset.Interface, error) {
return clientset, nil return clientset, nil
} }
func (f *TestFactory) DynamicClient() (dynamic.DynamicInterface, error) {
if f.FakeDynamicClient != nil {
return f.FakeDynamicClient, nil
}
return f.Factory.DynamicClient()
}
func (f *TestFactory) RESTClient() (*restclient.RESTClient, error) { func (f *TestFactory) RESTClient() (*restclient.RESTClient, error) {
// Swap out the HTTP client out of the client with the fake's version. // Swap out the HTTP client out of the client with the fake's version.
fakeClient := f.Client.(*fake.RESTClient) fakeClient := f.Client.(*fake.RESTClient)

View File

@ -66,7 +66,6 @@ type EditOptions struct {
cmdutil.ValidateOptions cmdutil.ValidateOptions
ResourceMapper *resource.Mapper
OriginalResult *resource.Result OriginalResult *resource.Result
EditMode EditMode EditMode EditMode

View File

@ -33,6 +33,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/watch" "k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/discovery" "k8s.io/client-go/discovery"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
scaleclient "k8s.io/client-go/scale" scaleclient "k8s.io/client-go/scale"
@ -92,6 +93,9 @@ type ClientAccessFactory interface {
// ClientSet gives you back an internal, generated clientset // ClientSet gives you back an internal, generated clientset
ClientSet() (internalclientset.Interface, error) ClientSet() (internalclientset.Interface, error)
// DynamicClient returns a dynamic client ready for use
DynamicClient() (dynamic.DynamicInterface, error)
// KubernetesClientSet gives you back an external clientset // KubernetesClientSet gives you back an external clientset
KubernetesClientSet() (*kubernetes.Clientset, error) KubernetesClientSet() (*kubernetes.Clientset, error)

View File

@ -22,7 +22,6 @@ import (
"os" "os"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/client-go/dynamic" "k8s.io/client-go/dynamic"
scaleclient "k8s.io/client-go/scale" scaleclient "k8s.io/client-go/scale"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
@ -46,24 +45,12 @@ func NewBuilderFactory(clientAccessFactory ClientAccessFactory, objectMappingFac
// NewBuilder returns a new resource builder for structured api objects. // NewBuilder returns a new resource builder for structured api objects.
func (f *ring2Factory) NewBuilder() *resource.Builder { func (f *ring2Factory) NewBuilder() *resource.Builder {
clientMapperFunc := resource.ClientMapperFunc(f.objectMappingFactory.ClientForMapping)
mapper, mapperErr := f.objectMappingFactory.RESTMapper() mapper, mapperErr := f.objectMappingFactory.RESTMapper()
unstructuredClientMapperFunc := resource.ClientMapperFunc(f.objectMappingFactory.UnstructuredClientForMapping)
categoryExpander := f.objectMappingFactory.CategoryExpander() categoryExpander := f.objectMappingFactory.CategoryExpander()
return resource.NewBuilder( return resource.NewBuilder(
&resource.Mapper{ f.clientAccessFactory.ClientConfig,
RESTMapper: mapper, mapper,
ClientMapper: clientMapperFunc,
Decoder: InternalVersionDecoder(),
},
&resource.Mapper{
RESTMapper: mapper,
ClientMapper: unstructuredClientMapperFunc,
Decoder: unstructured.UnstructuredJSONScheme,
},
categoryExpander, categoryExpander,
).AddError(mapperErr) ).AddError(mapperErr)
} }

View File

@ -52,6 +52,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
utilflag "k8s.io/apiserver/pkg/util/flag" utilflag "k8s.io/apiserver/pkg/util/flag"
"k8s.io/client-go/discovery" "k8s.io/client-go/discovery"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/clientcmd"
@ -199,6 +200,13 @@ func (f *ring0Factory) ClientSet() (internalclientset.Interface, error) {
return internalclientset.NewForConfig(clientConfig) return internalclientset.NewForConfig(clientConfig)
} }
func (f *ring0Factory) DynamicClient() (dynamic.DynamicInterface, error) {
clientConfig, err := f.ClientConfig()
if err != nil {
return nil, err
}
return dynamic.NewForConfig(clientConfig)
}
func (f *ring0Factory) checkMatchingServerVersion() error { func (f *ring0Factory) checkMatchingServerVersion() error {
f.checkServerVersion.Do(func() { f.checkServerVersion.Do(func() {
if !f.requireMatchedServerVersion { if !f.requireMatchedServerVersion {

View File

@ -25,7 +25,6 @@ import (
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
apiequality "k8s.io/apimachinery/pkg/api/equality" apiequality "k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/api/meta/testrestmapper" "k8s.io/apimachinery/pkg/api/meta/testrestmapper"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
@ -36,7 +35,6 @@ import (
manualfake "k8s.io/client-go/rest/fake" manualfake "k8s.io/client-go/rest/fake"
testcore "k8s.io/client-go/testing" testcore "k8s.io/client-go/testing"
"k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/api/testapi"
api "k8s.io/kubernetes/pkg/apis/core" api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
"k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/controller"
@ -442,10 +440,10 @@ func TestMakePortsString(t *testing.T) {
} }
} }
func fakeClient() resource.ClientMapper { func fakeClient() resource.FakeClientFunc {
return resource.ClientMapperFunc(func(*meta.RESTMapping) (resource.RESTClient, error) { return func(version schema.GroupVersion) (resource.RESTClient, error) {
return &manualfake.RESTClient{}, nil return &manualfake.RESTClient{}, nil
}) }
} }
func TestDiscoveryReplaceAliases(t *testing.T) { func TestDiscoveryReplaceAliases(t *testing.T) {
@ -473,15 +471,7 @@ func TestDiscoveryReplaceAliases(t *testing.T) {
ds := &fakeDiscoveryClient{} ds := &fakeDiscoveryClient{}
mapper := NewShortcutExpander(testrestmapper.TestOnlyStaticRESTMapper(legacyscheme.Registry, legacyscheme.Scheme), ds) mapper := NewShortcutExpander(testrestmapper.TestOnlyStaticRESTMapper(legacyscheme.Registry, legacyscheme.Scheme), ds)
b := resource.NewBuilder( b := resource.NewFakeBuilder(fakeClient(), mapper, categories.LegacyCategoryExpander)
&resource.Mapper{
RESTMapper: mapper,
ClientMapper: fakeClient(),
Decoder: testapi.Default.Codec(),
},
nil,
categories.LegacyCategoryExpander,
)
for _, test := range tests { for _, test := range tests {
replaced := b.ReplaceAliases(test.arg) replaced := b.ReplaceAliases(test.arg)

View File

@ -8,6 +8,7 @@ go_library(
name = "go_default_library", name = "go_default_library",
srcs = [ srcs = [
"builder.go", "builder.go",
"client.go",
"doc.go", "doc.go",
"helper.go", "helper.go",
"interfaces.go", "interfaces.go",
@ -29,16 +30,19 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/fields:go_default_library", "//vendor/k8s.io/apimachinery/pkg/fields:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library", "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library", "//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/yaml:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/yaml:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library", "//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
"//vendor/k8s.io/client-go/dynamic:go_default_library",
"//vendor/k8s.io/client-go/rest:go_default_library", "//vendor/k8s.io/client-go/rest:go_default_library",
], ],
) )
@ -56,10 +60,10 @@ go_test(
], ],
embed = [":go_default_library"], embed = [":go_default_library"],
deps = [ deps = [
"//pkg/api/legacyscheme:go_default_library",
"//pkg/apis/core/install:go_default_library", "//pkg/apis/core/install:go_default_library",
"//pkg/kubectl/categories:go_default_library", "//pkg/kubectl/categories:go_default_library",
"//pkg/kubectl/scheme:go_default_library", "//pkg/kubectl/scheme:go_default_library",
"//vendor/github.com/davecgh/go-spew/spew:go_default_library",
"//vendor/github.com/ghodss/yaml:go_default_library", "//vendor/github.com/ghodss/yaml:go_default_library",
"//vendor/github.com/stretchr/testify/assert:go_default_library", "//vendor/github.com/stretchr/testify/assert:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library",

View File

@ -26,10 +26,12 @@ import (
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
utilerrors "k8s.io/apimachinery/pkg/util/errors" utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/sets"
"k8s.io/kubernetes/pkg/kubectl/categories" "k8s.io/kubernetes/pkg/kubectl/categories"
@ -48,14 +50,22 @@ type Builder struct {
categoryExpander categories.CategoryExpander categoryExpander categories.CategoryExpander
// mapper is set explicitly by resource builders // mapper is set explicitly by resource builders
mapper *Mapper mapper *mapper
internal *Mapper internal *mapper
unstructured *Mapper unstructured *mapper
// clientConfigFn is a function to produce a client, *if* you need one
clientConfigFn ClientConfigFunc
restMapper meta.RESTMapper
// objectTyper is statically determinant per-command invocation based on your internal or unstructured choice // objectTyper is statically determinant per-command invocation based on your internal or unstructured choice
// it does not ever need to rely upon discovery. // it does not ever need to rely upon discovery.
objectTyper runtime.ObjectTyper objectTyper runtime.ObjectTyper
// codecFactory describes which codecs you want to use
codecFactory *serializer.CodecFactory
// local indicates that we cannot make server calls // local indicates that we cannot make server calls
local bool local bool
@ -96,6 +106,9 @@ type Builder struct {
export bool export bool
schema validation.Schema schema validation.Schema
// fakeClientFn is used for testing
fakeClientFn FakeClientFunc
} }
var missingResourceError = fmt.Errorf(`You must provide one or more resources by argument or filename. var missingResourceError = fmt.Errorf(`You must provide one or more resources by argument or filename.
@ -128,13 +141,22 @@ type resourceTuple struct {
Name string Name string
} }
type FakeClientFunc func(version schema.GroupVersion) (RESTClient, error)
func NewFakeBuilder(fakeClientFn FakeClientFunc, restMapper meta.RESTMapper, categoryExpander categories.CategoryExpander) *Builder {
ret := NewBuilder(nil, restMapper, categoryExpander)
ret.fakeClientFn = fakeClientFn
return ret
}
// NewBuilder creates a builder that operates on generic objects. At least one of // NewBuilder creates a builder that operates on generic objects. At least one of
// internal or unstructured must be specified. // internal or unstructured must be specified.
// TODO: Add versioned client (although versioned is still lossy) // TODO: Add versioned client (although versioned is still lossy)
func NewBuilder(internal, unstructured *Mapper, categoryExpander categories.CategoryExpander) *Builder { // TODO remove internal and unstructured mapper and instead have them set the negotiated serializer for use in the client
func NewBuilder(clientConfigFn ClientConfigFunc, restMapper meta.RESTMapper, categoryExpander categories.CategoryExpander) *Builder {
return &Builder{ return &Builder{
internal: internal, clientConfigFn: clientConfigFn,
unstructured: unstructured, restMapper: restMapper,
categoryExpander: categoryExpander, categoryExpander: categoryExpander,
requireObject: true, requireObject: true,
} }
@ -194,39 +216,39 @@ func (b *Builder) FilenameParam(enforceNamespace bool, filenameOptions *Filename
// reads and then writes an object. Use this mode in preference to Internal unless you // reads and then writes an object. Use this mode in preference to Internal unless you
// are working with Go types directly. // are working with Go types directly.
func (b *Builder) Unstructured() *Builder { func (b *Builder) Unstructured() *Builder {
if b.unstructured == nil { if b.mapper != nil {
b.errs = append(b.errs, fmt.Errorf("no unstructured mapper provided"))
return b
}
if b.mapper != nil && b.mapper != b.unstructured {
b.errs = append(b.errs, fmt.Errorf("another mapper was already selected, cannot use unstructured types")) b.errs = append(b.errs, fmt.Errorf("another mapper was already selected, cannot use unstructured types"))
return b return b
} }
b.mapper = b.unstructured
b.mapper.localFn = b.isLocal
b.objectTyper = unstructuredscheme.NewUnstructuredObjectTyper() b.objectTyper = unstructuredscheme.NewUnstructuredObjectTyper()
b.mapper = &mapper{
localFn: b.isLocal,
restMapper: b.restMapper,
clientFn: b.getClient,
decoder: unstructured.UnstructuredJSONScheme,
}
return b return b
} }
// Internal updates the builder so that it will convert objects off the wire // WithScheme uses the scheme to manage typing, conversion (optional), and decoding. If decodingVersions
// into the internal form if necessary. Using internal types is lossy - fields added // is empty, then you can end up with internal types. You have been warned.
// to the server will not be seen by the client code and may result in failure. Only func (b *Builder) WithScheme(scheme *runtime.Scheme, decodingVersions ...schema.GroupVersion) *Builder {
// use this mode when working offline, or when generating patches to send to the server. if b.mapper != nil {
// Use Unstructured if you are reading an object and performing a POST or PUT.
func (b *Builder) Internal(typer runtime.ObjectTyper) *Builder {
if b.internal == nil {
b.errs = append(b.errs, fmt.Errorf("no internal mapper provided"))
return b
}
if b.mapper != nil && b.mapper != b.internal {
b.errs = append(b.errs, fmt.Errorf("another mapper was already selected, cannot use internal types")) b.errs = append(b.errs, fmt.Errorf("another mapper was already selected, cannot use internal types"))
return b return b
} }
b.mapper = b.internal b.objectTyper = scheme
b.mapper.localFn = b.isLocal codecFactory := serializer.NewCodecFactory(scheme)
b.codecFactory = &codecFactory
b.mapper = &mapper{
localFn: b.isLocal,
restMapper: b.restMapper,
clientFn: b.getClient,
decoder: b.codecFactory.UniversalDecoder(decodingVersions...),
}
b.objectTyper = typer
return b return b
} }
@ -241,9 +263,6 @@ func (b *Builder) LocalParam(local bool) *Builder {
// Local will avoid asking the server for results. // Local will avoid asking the server for results.
func (b *Builder) Local() *Builder { func (b *Builder) Local() *Builder {
b.local = true b.local = true
mapper := *b.mapper
mapper.ClientMapper = DisabledClientForMapping{ClientMapper: mapper.ClientMapper}
b.mapper = &mapper
return b return b
} }
@ -252,7 +271,7 @@ func (b *Builder) isLocal() bool {
} }
// Mapper returns a copy of the current mapper. // Mapper returns a copy of the current mapper.
func (b *Builder) Mapper() *Mapper { func (b *Builder) Mapper() *mapper {
mapper := *b.mapper mapper := *b.mapper
return &mapper return &mapper
} }
@ -636,13 +655,13 @@ func (b *Builder) mappingFor(resourceOrKindArg string) (*meta.RESTMapping, error
fullySpecifiedGVR, groupResource := schema.ParseResourceArg(resourceOrKindArg) fullySpecifiedGVR, groupResource := schema.ParseResourceArg(resourceOrKindArg)
gvk := schema.GroupVersionKind{} gvk := schema.GroupVersionKind{}
if fullySpecifiedGVR != nil { if fullySpecifiedGVR != nil {
gvk, _ = b.mapper.RESTMapper.KindFor(*fullySpecifiedGVR) gvk, _ = b.mapper.restMapper.KindFor(*fullySpecifiedGVR)
} }
if gvk.Empty() { if gvk.Empty() {
gvk, _ = b.mapper.RESTMapper.KindFor(groupResource.WithVersion("")) gvk, _ = b.mapper.restMapper.KindFor(groupResource.WithVersion(""))
} }
if !gvk.Empty() { if !gvk.Empty() {
return b.mapper.RESTMapper.RESTMapping(gvk.GroupKind(), gvk.Version) return b.mapper.restMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
} }
fullySpecifiedGVK, groupKind := schema.ParseKindArg(resourceOrKindArg) fullySpecifiedGVK, groupKind := schema.ParseKindArg(resourceOrKindArg)
@ -652,12 +671,12 @@ func (b *Builder) mappingFor(resourceOrKindArg string) (*meta.RESTMapping, error
} }
if !fullySpecifiedGVK.Empty() { if !fullySpecifiedGVK.Empty() {
if mapping, err := b.mapper.RESTMapper.RESTMapping(fullySpecifiedGVK.GroupKind(), fullySpecifiedGVK.Version); err == nil { if mapping, err := b.mapper.restMapper.RESTMapping(fullySpecifiedGVK.GroupKind(), fullySpecifiedGVK.Version); err == nil {
return mapping, nil return mapping, nil
} }
} }
mapping, err := b.mapper.RESTMapper.RESTMapping(groupKind, gvk.Version) mapping, err := b.mapper.restMapper.RESTMapping(groupKind, gvk.Version)
if err != nil { if err != nil {
// if we error out here, it is because we could not match a resource or a kind // if we error out here, it is because we could not match a resource or a kind
// for the given argument. To maintain consistency with previous behavior, // for the given argument. To maintain consistency with previous behavior,
@ -782,7 +801,7 @@ func (b *Builder) visitBySelector() *Result {
visitors := []Visitor{} visitors := []Visitor{}
for _, mapping := range mappings { for _, mapping := range mappings {
client, err := b.mapper.ClientMapper.ClientForMapping(mapping) client, err := b.getClient(mapping.GroupVersionKind.GroupVersion())
if err != nil { if err != nil {
result.err = err result.err = err
return result return result
@ -803,6 +822,18 @@ func (b *Builder) visitBySelector() *Result {
return result return result
} }
func (b *Builder) getClient(gv schema.GroupVersion) (RESTClient, error) {
if b.fakeClientFn != nil {
return b.fakeClientFn(gv)
}
if b.codecFactory != nil {
return b.clientConfigFn.clientForGroupVersion(gv, b.codecFactory)
}
return b.clientConfigFn.unstructuredClientForGroupVersion(gv)
}
func (b *Builder) visitByResource() *Result { func (b *Builder) visitByResource() *Result {
// if b.singleItemImplied is false, this could be by default, so double-check length // if b.singleItemImplied is false, this could be by default, so double-check length
// of resourceTuples to determine if in fact it is singleItemImplied or not // of resourceTuples to determine if in fact it is singleItemImplied or not
@ -832,7 +863,7 @@ func (b *Builder) visitByResource() *Result {
if _, ok := clients[s]; ok { if _, ok := clients[s]; ok {
continue continue
} }
client, err := b.mapper.ClientMapper.ClientForMapping(mapping) client, err := b.getClient(mapping.GroupVersionKind.GroupVersion())
if err != nil { if err != nil {
result.err = err result.err = err
return result return result
@ -910,7 +941,7 @@ func (b *Builder) visitByName() *Result {
} }
mapping := mappings[0] mapping := mappings[0]
client, err := b.mapper.ClientMapper.ClientForMapping(mapping) client, err := b.getClient(mapping.GroupVersionKind.GroupVersion())
if err != nil { if err != nil {
result.err = err result.err = err
return result return result

View File

@ -47,11 +47,11 @@ import (
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
restclientwatch "k8s.io/client-go/rest/watch" restclientwatch "k8s.io/client-go/rest/watch"
utiltesting "k8s.io/client-go/util/testing" utiltesting "k8s.io/client-go/util/testing"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/kubectl/categories" "k8s.io/kubernetes/pkg/kubectl/categories"
"k8s.io/kubernetes/pkg/kubectl/scheme" "k8s.io/kubernetes/pkg/kubectl/scheme"
// install the pod scheme into the legacy scheme for test typer resolution // install the pod scheme into the legacy scheme for test typer resolution
"github.com/davecgh/go-spew/spew"
_ "k8s.io/kubernetes/pkg/apis/core/install" _ "k8s.io/kubernetes/pkg/apis/core/install"
) )
@ -76,14 +76,14 @@ func watchBody(events ...watch.Event) string {
return buf.String() return buf.String()
} }
func fakeClient() ClientMapper { func fakeClient() FakeClientFunc {
return ClientMapperFunc(func(*meta.RESTMapping) (RESTClient, error) { return func(version schema.GroupVersion) (RESTClient, error) {
return &fake.RESTClient{}, nil return &fake.RESTClient{}, nil
}) }
} }
func fakeClientWith(testName string, t *testing.T, data map[string]string) ClientMapper { func fakeClientWith(testName string, t *testing.T, data map[string]string) FakeClientFunc {
return ClientMapperFunc(func(*meta.RESTMapping) (RESTClient, error) { return func(version schema.GroupVersion) (RESTClient, error) {
return &fake.RESTClient{ return &fake.RESTClient{
GroupVersion: corev1GV, GroupVersion: corev1GV,
NegotiatedSerializer: serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}, NegotiatedSerializer: serializer.DirectCodecFactory{CodecFactory: scheme.Codecs},
@ -106,7 +106,7 @@ func fakeClientWith(testName string, t *testing.T, data map[string]string) Clien
}, nil }, nil
}), }),
}, nil }, nil
}) }
} }
func testData() (*v1.PodList, *v1.ServiceList) { func testData() (*v1.PodList, *v1.ServiceList) {
@ -272,16 +272,9 @@ func newDefaultBuilder() *Builder {
return newDefaultBuilderWith(fakeClient()) return newDefaultBuilderWith(fakeClient())
} }
func newDefaultBuilderWith(client ClientMapper) *Builder { func newDefaultBuilderWith(fakeClientFn FakeClientFunc) *Builder {
return NewBuilder( return NewFakeBuilder(fakeClientFn, restmapper, categories.LegacyCategoryExpander).
&Mapper{ WithScheme(scheme.Scheme, scheme.Registry.RegisteredGroupVersions()...)
RESTMapper: restmapper,
ClientMapper: client,
Decoder: corev1Codec,
},
nil,
categories.LegacyCategoryExpander,
).Internal(legacyscheme.Scheme)
} }
func TestPathBuilderAndVersionedObjectNotDefaulted(t *testing.T) { func TestPathBuilderAndVersionedObjectNotDefaulted(t *testing.T) {
@ -407,11 +400,11 @@ func TestPathBuilderWithMultiple(t *testing.T) {
switch test.object.(type) { switch test.object.(type) {
case *v1.Pod: case *v1.Pod:
if _, ok := v.Object.(*v1.Pod); !ok || v.Name != test.expectedNames[i] || v.Namespace != "test" { if _, ok := v.Object.(*v1.Pod); !ok || v.Name != test.expectedNames[i] || v.Namespace != "test" {
t.Errorf("unexpected info: %#v", v) t.Errorf("unexpected info: %v", spew.Sdump(v.Object))
} }
case *v1.ReplicationController: case *v1.ReplicationController:
if _, ok := v.Object.(*v1.ReplicationController); !ok || v.Name != test.expectedNames[i] || v.Namespace != "test" { if _, ok := v.Object.(*v1.ReplicationController); !ok || v.Name != test.expectedNames[i] || v.Namespace != "test" {
t.Errorf("unexpected info: %#v", v) t.Errorf("unexpected info: %v", spew.Sdump(v.Object))
} }
} }
} }

View File

@ -0,0 +1,59 @@
/*
Copyright 2018 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 (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/rest"
)
// TODO require negotiatedSerializer. leaving it optional lets us plumb current behavior and deal with the difference after major plumbing is complete
func (clientConfigFn ClientConfigFunc) clientForGroupVersion(gv schema.GroupVersion, negotiatedSerializer runtime.NegotiatedSerializer) (RESTClient, error) {
cfg, err := clientConfigFn()
if err != nil {
return nil, err
}
if negotiatedSerializer != nil {
cfg.ContentConfig.NegotiatedSerializer = negotiatedSerializer
}
cfg.GroupVersion = &gv
if len(gv.Group) == 0 {
cfg.APIPath = "/api"
} else {
cfg.APIPath = "/apis"
}
return rest.RESTClientFor(cfg)
}
func (clientConfigFn ClientConfigFunc) unstructuredClientForGroupVersion(gv schema.GroupVersion) (RESTClient, error) {
cfg, err := clientConfigFn()
if err != nil {
return nil, err
}
cfg.ContentConfig = dynamic.ContentConfig()
cfg.GroupVersion = &gv
if len(gv.Group) == 0 {
cfg.APIPath = "/api"
} else {
cfg.APIPath = "/apis"
}
return rest.RESTClientFor(cfg)
}

View File

@ -17,38 +17,24 @@ limitations under the License.
package resource package resource
import ( import (
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
client "k8s.io/client-go/rest" "k8s.io/client-go/rest"
) )
type RESTMapperFunc func() (meta.RESTMapper, error) type ClientConfigFunc func() (*rest.Config, error)
// RESTClient is a client helper for dealing with RESTful resources // RESTClient is a client helper for dealing with RESTful resources
// in a generic way. // in a generic way.
type RESTClient interface { type RESTClient interface {
Get() *client.Request Get() *rest.Request
Post() *client.Request Post() *rest.Request
Patch(types.PatchType) *client.Request Patch(types.PatchType) *rest.Request
Delete() *client.Request Delete() *rest.Request
Put() *client.Request Put() *rest.Request
}
// ClientMapper abstracts retrieving a Client for mapped objects.
type ClientMapper interface {
ClientForMapping(mapping *meta.RESTMapping) (RESTClient, error)
}
// ClientMapperFunc implements ClientMapper for a function
type ClientMapperFunc func(mapping *meta.RESTMapping) (RESTClient, error)
// ClientForMapping implements ClientMapper
func (f ClientMapperFunc) ClientForMapping(mapping *meta.RESTMapping) (RESTClient, error) {
return f(mapping)
} }
// RequestTransform is a function that is given a chance to modify the outgoing request. // RequestTransform is a function that is given a chance to modify the outgoing request.
type RequestTransform func(*client.Request) type RequestTransform func(*rest.Request)
// NewClientWithOptions wraps the provided RESTClient and invokes each transform on each // NewClientWithOptions wraps the provided RESTClient and invokes each transform on each
// newly created request. // newly created request.
@ -61,26 +47,26 @@ type clientOptions struct {
transforms []RequestTransform transforms []RequestTransform
} }
func (c *clientOptions) modify(req *client.Request) *client.Request { func (c *clientOptions) modify(req *rest.Request) *rest.Request {
for _, transform := range c.transforms { for _, transform := range c.transforms {
transform(req) transform(req)
} }
return req return req
} }
func (c *clientOptions) Get() *client.Request { func (c *clientOptions) Get() *rest.Request {
return c.modify(c.c.Get()) return c.modify(c.c.Get())
} }
func (c *clientOptions) Post() *client.Request { func (c *clientOptions) Post() *rest.Request {
return c.modify(c.c.Post()) return c.modify(c.c.Post())
} }
func (c *clientOptions) Patch(t types.PatchType) *client.Request { func (c *clientOptions) Patch(t types.PatchType) *rest.Request {
return c.modify(c.c.Patch(t)) return c.modify(c.c.Patch(t))
} }
func (c *clientOptions) Delete() *client.Request { func (c *clientOptions) Delete() *rest.Request {
return c.modify(c.c.Delete()) return c.modify(c.c.Delete())
} }
func (c *clientOptions) Put() *client.Request { func (c *clientOptions) Put() *rest.Request {
return c.modify(c.c.Put()) return c.modify(c.c.Put())
} }

View File

@ -27,20 +27,20 @@ import (
// Mapper is a convenience struct for holding references to the interfaces // Mapper is a convenience struct for holding references to the interfaces
// needed to create Info for arbitrary objects. // needed to create Info for arbitrary objects.
type Mapper struct { type mapper struct {
// localFn indicates the call can't make server requests // localFn indicates the call can't make server requests
localFn func() bool localFn func() bool
RESTMapper meta.RESTMapper restMapper meta.RESTMapper
ClientMapper ClientMapper clientFn func(version schema.GroupVersion) (RESTClient, error)
Decoder runtime.Decoder decoder runtime.Decoder
} }
// InfoForData creates an Info object for the given data. An error is returned // InfoForData creates an Info object for the given data. An error is returned
// if any of the decoding or client lookup steps fail. Name and namespace will be // if any of the decoding or client lookup steps fail. Name and namespace will be
// set into Info if the mapping's MetadataAccessor can retrieve them. // set into Info if the mapping's MetadataAccessor can retrieve them.
func (m *Mapper) InfoForData(data []byte, source string) (*Info, error) { func (m *mapper) infoForData(data []byte, source string) (*Info, error) {
obj, gvk, err := m.Decoder.Decode(data, nil, nil) obj, gvk, err := m.decoder.Decode(data, nil, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to decode %q: %v", source, err) return nil, fmt.Errorf("unable to decode %q: %v", source, err)
} }
@ -59,13 +59,13 @@ func (m *Mapper) InfoForData(data []byte, source string) (*Info, error) {
} }
if m.localFn == nil || !m.localFn() { if m.localFn == nil || !m.localFn() {
mapping, err := m.RESTMapper.RESTMapping(gvk.GroupKind(), gvk.Version) mapping, err := m.restMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to recognize %q: %v", source, err) return nil, fmt.Errorf("unable to recognize %q: %v", source, err)
} }
ret.Mapping = mapping ret.Mapping = mapping
client, err := m.ClientMapper.ClientForMapping(mapping) client, err := m.clientFn(gvk.GroupVersion())
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to connect to a server to handle %q: %v", mapping.Resource, err) return nil, fmt.Errorf("unable to connect to a server to handle %q: %v", mapping.Resource, err)
} }
@ -78,7 +78,7 @@ func (m *Mapper) InfoForData(data []byte, source string) (*Info, error) {
// InfoForObject creates an Info object for the given Object. An error is returned // InfoForObject creates an Info object for the given Object. An error is returned
// if the object cannot be introspected. Name and namespace will be set into Info // if the object cannot be introspected. Name and namespace will be set into Info
// if the mapping's MetadataAccessor can retrieve them. // if the mapping's MetadataAccessor can retrieve them.
func (m *Mapper) InfoForObject(obj runtime.Object, typer runtime.ObjectTyper, preferredGVKs []schema.GroupVersionKind) (*Info, error) { func (m *mapper) infoForObject(obj runtime.Object, typer runtime.ObjectTyper, preferredGVKs []schema.GroupVersionKind) (*Info, error) {
groupVersionKinds, _, err := typer.ObjectKinds(obj) groupVersionKinds, _, err := typer.ObjectKinds(obj)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to get type info from the object %q: %v", reflect.TypeOf(obj), err) return nil, fmt.Errorf("unable to get type info from the object %q: %v", reflect.TypeOf(obj), err)
@ -101,13 +101,13 @@ func (m *Mapper) InfoForObject(obj runtime.Object, typer runtime.ObjectTyper, pr
} }
if m.localFn == nil || !m.localFn() { if m.localFn == nil || !m.localFn() {
mapping, err := m.RESTMapper.RESTMapping(gvk.GroupKind(), gvk.Version) mapping, err := m.restMapper.RESTMapping(gvk.GroupKind(), gvk.Version)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to recognize %v", err) return nil, fmt.Errorf("unable to recognize %v", err)
} }
ret.Mapping = mapping ret.Mapping = mapping
client, err := m.ClientMapper.ClientForMapping(mapping) client, err := m.clientFn(gvk.GroupVersion())
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to connect to a server to handle %q: %v", mapping.Resource, err) return nil, fmt.Errorf("unable to connect to a server to handle %q: %v", mapping.Resource, err)
} }
@ -152,13 +152,3 @@ func preferredObjectKind(possibilities []schema.GroupVersionKind, preferences []
// Just pick the first // Just pick the first
return possibilities[0] return possibilities[0]
} }
// DisabledClientForMapping allows callers to avoid allowing remote calls when handling
// resources.
type DisabledClientForMapping struct {
ClientMapper
}
func (f DisabledClientForMapping) ClientForMapping(mapping *meta.RESTMapping) (RESTClient, error) {
return nil, nil
}

View File

@ -42,7 +42,7 @@ type Result struct {
singleItemImplied bool singleItemImplied bool
targetsSingleItems bool targetsSingleItems bool
mapper *Mapper mapper *mapper
ignoreErrors []utilerrors.Matcher ignoreErrors []utilerrors.Matcher
// populated by a call to Infos // populated by a call to Infos
@ -77,7 +77,7 @@ func (r *Result) IgnoreErrors(fns ...ErrMatchFunc) *Result {
} }
// Mapper returns a copy of the builder's mapper. // Mapper returns a copy of the builder's mapper.
func (r *Result) Mapper() *Mapper { func (r *Result) Mapper() *mapper {
return r.mapper return r.mapper
} }

View File

@ -372,12 +372,12 @@ func (v ContinueOnErrorVisitor) Visit(fn VisitorFunc) error {
type FlattenListVisitor struct { type FlattenListVisitor struct {
visitor Visitor visitor Visitor
typer runtime.ObjectTyper typer runtime.ObjectTyper
mapper *Mapper mapper *mapper
} }
// NewFlattenListVisitor creates a visitor that will expand list style runtime.Objects // NewFlattenListVisitor creates a visitor that will expand list style runtime.Objects
// into individual items and then visit them individually. // into individual items and then visit them individually.
func NewFlattenListVisitor(v Visitor, typer runtime.ObjectTyper, mapper *Mapper) Visitor { func NewFlattenListVisitor(v Visitor, typer runtime.ObjectTyper, mapper *mapper) Visitor {
return FlattenListVisitor{v, typer, mapper} return FlattenListVisitor{v, typer, mapper}
} }
@ -393,7 +393,7 @@ func (v FlattenListVisitor) Visit(fn VisitorFunc) error {
if err != nil { if err != nil {
return fn(info, nil) return fn(info, nil)
} }
if errs := runtime.DecodeList(items, v.mapper.Decoder); len(errs) > 0 { if errs := runtime.DecodeList(items, v.mapper.decoder); len(errs) > 0 {
return utilerrors.NewAggregate(errs) return utilerrors.NewAggregate(errs)
} }
@ -404,7 +404,7 @@ func (v FlattenListVisitor) Visit(fn VisitorFunc) error {
} }
for i := range items { for i := range items {
item, err := v.mapper.InfoForObject(items[i], v.typer, preferredGVKs) item, err := v.mapper.infoForObject(items[i], v.typer, preferredGVKs)
if err != nil { if err != nil {
return err return err
} }
@ -433,7 +433,7 @@ func ignoreFile(path string, extensions []string) bool {
} }
// FileVisitorForSTDIN return a special FileVisitor just for STDIN // FileVisitorForSTDIN return a special FileVisitor just for STDIN
func FileVisitorForSTDIN(mapper *Mapper, schema validation.Schema) Visitor { func FileVisitorForSTDIN(mapper *mapper, schema validation.Schema) Visitor {
return &FileVisitor{ return &FileVisitor{
Path: constSTDINstr, Path: constSTDINstr,
StreamVisitor: NewStreamVisitor(nil, mapper, constSTDINstr, schema), StreamVisitor: NewStreamVisitor(nil, mapper, constSTDINstr, schema),
@ -443,7 +443,7 @@ func FileVisitorForSTDIN(mapper *Mapper, schema validation.Schema) Visitor {
// ExpandPathsToFileVisitors will return a slice of FileVisitors that will handle files from the provided path. // ExpandPathsToFileVisitors will return a slice of FileVisitors that will handle files from the provided path.
// After FileVisitors open the files, they will pass an io.Reader to a StreamVisitor to do the reading. (stdin // After FileVisitors open the files, they will pass an io.Reader to a StreamVisitor to do the reading. (stdin
// is also taken care of). Paths argument also accepts a single file, and will return a single visitor // is also taken care of). Paths argument also accepts a single file, and will return a single visitor
func ExpandPathsToFileVisitors(mapper *Mapper, paths string, recursive bool, extensions []string, schema validation.Schema) ([]Visitor, error) { func ExpandPathsToFileVisitors(mapper *mapper, paths string, recursive bool, extensions []string, schema validation.Schema) ([]Visitor, error) {
var visitors []Visitor var visitors []Visitor
err := filepath.Walk(paths, func(path string, fi os.FileInfo, err error) error { err := filepath.Walk(paths, func(path string, fi os.FileInfo, err error) error {
if err != nil { if err != nil {
@ -510,17 +510,17 @@ func (v *FileVisitor) Visit(fn VisitorFunc) error {
// a stream decoder method on runtime.Codec to properly handle this. // a stream decoder method on runtime.Codec to properly handle this.
type StreamVisitor struct { type StreamVisitor struct {
io.Reader io.Reader
*Mapper *mapper
Source string Source string
Schema validation.Schema Schema validation.Schema
} }
// NewStreamVisitor is a helper function that is useful when we want to change the fields of the struct but keep calls the same. // NewStreamVisitor is a helper function that is useful when we want to change the fields of the struct but keep calls the same.
func NewStreamVisitor(r io.Reader, mapper *Mapper, source string, schema validation.Schema) *StreamVisitor { func NewStreamVisitor(r io.Reader, mapper *mapper, source string, schema validation.Schema) *StreamVisitor {
return &StreamVisitor{ return &StreamVisitor{
Reader: r, Reader: r,
Mapper: mapper, mapper: mapper,
Source: source, Source: source,
Schema: schema, Schema: schema,
} }
@ -545,7 +545,7 @@ func (v *StreamVisitor) Visit(fn VisitorFunc) error {
if err := ValidateSchema(ext.Raw, v.Schema); err != nil { if err := ValidateSchema(ext.Raw, v.Schema); err != nil {
return fmt.Errorf("error validating %q: %v", v.Source, err) return fmt.Errorf("error validating %q: %v", v.Source, err)
} }
info, err := v.InfoForData(ext.Raw, v.Source) info, err := v.infoForData(ext.Raw, v.Source)
if err != nil { if err != nil {
if fnErr := fn(info, err); fnErr != nil { if fnErr := fn(info, err); fnErr != nil {
return fnErr return fnErr