Unverified Commit 238fda9e authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #63318 from deads2k/cli-40-mapperfunc

Automatic merge from submit-queue (batch tested with PRs 63315, 63383, 63318, 63439). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. drive resourcebuilder from kubeconfig, allow scheme specification This updates the resource builder to work based on a kubeconfig to allow future chaining of flags. It also allow specification of the scheme you want for your actual decoding. @kubernetes/sig-cli-maintainers ```release-note NONE ```
parents 31511f9e a53a72e2
...@@ -102,6 +102,7 @@ go_library( ...@@ -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( ...@@ -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",
......
...@@ -38,6 +38,7 @@ import ( ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 ...@@ -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 { ...@@ -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.Resource).
if err != nil { Namespace(namespace).
return err List(metav1.ListOptions{
}
objList, err := resource.NewHelper(c, mapping).List(
namespace,
mapping.GroupVersionKind.Version,
false,
&metav1.ListOptions{
LabelSelector: p.labelSelector, LabelSelector: p.labelSelector,
FieldSelector: p.fieldSelector, FieldSelector: p.fieldSelector,
IncludeUninitialized: includeUninitialized, IncludeUninitialized: includeUninitialized,
}, })
)
if err != nil { if err != nil {
return err 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 ...@@ -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 resource.RESTClient, helper *resource.Helper, cascade bool, gracePeriod int, clientsetFunc func() (internalclientset.Interface, error), scaleClient scaleclient.ScalesGetter) error { func runDelete(namespace, name string, mapping *meta.RESTMapping, c dynamic.DynamicInterface, cascade bool, gracePeriod int, clientsetFunc func() (internalclientset.Interface, error), scaleClient scaleclient.ScalesGetter) error {
if !cascade { if !cascade {
if helper == nil { return c.Resource(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 ...@@ -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.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 ...@@ -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 { ...@@ -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
......
...@@ -146,7 +146,7 @@ func (p *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn [ ...@@ -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) {
......
...@@ -96,7 +96,7 @@ func (o *ReconcileOptions) Complete(cmd *cobra.Command, f cmdutil.Factory, args ...@@ -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).
......
...@@ -22,8 +22,10 @@ import ( ...@@ -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 { ...@@ -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 ...@@ -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 ...@@ -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 { ...@@ -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 { ...@@ -231,20 +233,14 @@ func (o *AutoscaleOptions) Run() error {
if err != nil { if err != nil {
return err return err
} }
hpa, ok := object.(*autoscalingv1.HorizontalPodAutoscaler)
resourceMapper := &resource.Mapper{ if !ok {
RESTMapper: o.mapper, return fmt.Errorf("generator made %T, not autoscalingv1.HorizontalPodAutoscaler", object)
ClientMapper: resource.ClientMapperFunc(o.clientForMapping),
Decoder: cmdutil.InternalVersionDecoder(),
} }
hpa, err := resourceMapper.InfoForObject(object, legacyscheme.Scheme, nil)
if err != nil { if err := o.Recorder.Record(hpa); 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 { ...@@ -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 { ...@@ -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
......
...@@ -204,7 +204,7 @@ func (o *CertificateOptions) RunCertificateDeny(force bool) error { ...@@ -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...).
......
...@@ -96,7 +96,7 @@ func (o *ClusterInfoOptions) Run() error { ...@@ -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"}...).
......
...@@ -129,7 +129,7 @@ func (o *ConvertOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) (err er ...@@ -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"))
......
...@@ -41,6 +41,7 @@ go_library( ...@@ -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",
......
...@@ -29,6 +29,7 @@ import ( ...@@ -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 ...@@ -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 return err
} }
resourceMapper := &resource.Mapper{
RESTMapper: mapper, asUnstructured := &unstructured.Unstructured{}
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping), if err := legacyscheme.Scheme.Convert(obj, asUnstructured, nil); err != nil {
return err
} }
info, err := resourceMapper.InfoForObject(obj, legacyscheme.Scheme, nil) dynamicClient, err := f.DynamicClient()
if err != nil { if err != nil {
return err return err
} }
if err := kubectl.CreateOrUpdateAnnotation(options.CreateAnnotation, info.Object, cmdutil.InternalVersionJSONEncoder()); err != nil { if mapping.Scope.Name() == meta.RESTScopeNameRoot {
return err namespace = ""
} }
actualObject, err := dynamicClient.Resource(mapping.Resource).Namespace(namespace).Create(asUnstructured)
obj, err = resource.NewHelper(client, mapping).Create(namespace, false, info.Object)
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)
......
...@@ -17,41 +17,16 @@ limitations under the License. ...@@ -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,14 +50,21 @@ func TestCreateQuota(t *testing.T) { ...@@ -75,14 +50,21 @@ func TestCreateQuota(t *testing.T) {
}, },
} }
for name, test := range tests { for name, test := range tests {
ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams() t.Run(name, func(t *testing.T) {
cmd := NewCmdCreateQuota(tf, ioStreams) tf := cmdtesting.NewTestFactory()
cmd.Flags().Parse(test.flags) defer tf.Cleanup()
cmd.Flags().Set("output", "name")
cmd.Run(cmd, []string{resourceQuotaObject.Name})
if buf.String() != test.expectedOutput { tf.Namespace = "test"
t.Errorf("%s: expected output: %s, but got: %s", name, test.expectedOutput, buf.String())
} ioStreams, _, buf, _ := genericclioptions.NewTestIOStreams()
cmd := NewCmdCreateQuota(tf, ioStreams)
cmd.Flags().Parse(test.flags)
cmd.Flags().Set("output", "name")
cmd.Run(cmd, []string{resourceQuotaObject.Name})
if buf.String() != test.expectedOutput {
t.Errorf("%s: expected output: %s, but got: %s", name, test.expectedOutput, buf.String())
}
})
} }
} }
...@@ -171,7 +171,11 @@ func (o *DeleteOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, args ...@@ -171,7 +171,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
......
...@@ -282,7 +282,7 @@ func (o *DrainOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st ...@@ -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().
......
...@@ -32,7 +32,7 @@ import ( ...@@ -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) { ...@@ -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,
......
...@@ -24,9 +24,12 @@ import ( ...@@ -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,7 +100,8 @@ type ExposeServiceOptions struct { ...@@ -97,7 +100,8 @@ type ExposeServiceOptions struct {
Namespace string Namespace string
Mapper meta.RESTMapper Mapper meta.RESTMapper
Builder *resource.Builder DynamicClient dynamic.DynamicInterface
Builder *resource.Builder
Recorder genericclioptions.Recorder Recorder genericclioptions.Recorder
genericclioptions.IOStreams genericclioptions.IOStreams
...@@ -180,6 +184,11 @@ func (o *ExposeServiceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) e ...@@ -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 ...@@ -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 ...@@ -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.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
......
...@@ -480,8 +480,6 @@ func TestRunExposeService(t *testing.T) { ...@@ -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
......
...@@ -202,7 +202,7 @@ func (o *LogsOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.Comm ...@@ -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 != "" {
......
...@@ -180,7 +180,7 @@ func (o *PortForwardOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, arg ...@@ -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()
......
...@@ -82,7 +82,7 @@ func RunHistory(f cmdutil.Factory, cmd *cobra.Command, out io.Writer, args []str ...@@ -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...).
......
...@@ -111,7 +111,7 @@ func (o *PauseConfig) CompletePause(f cmdutil.Factory, cmd *cobra.Command, args ...@@ -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...).
......
...@@ -119,7 +119,7 @@ func (o *ResumeConfig) CompleteResume(f cmdutil.Factory, cmd *cobra.Command, arg ...@@ -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...).
......
...@@ -124,7 +124,7 @@ func (o *RolloutStatusOptions) Validate(cmd *cobra.Command, args []string) error ...@@ -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...).
......
...@@ -127,7 +127,7 @@ func (o *UndoOptions) CompleteUndo(f cmdutil.Factory, cmd *cobra.Command, out io ...@@ -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...).
......
...@@ -20,6 +20,7 @@ import ( ...@@ -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 ( ...@@ -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,10 +92,8 @@ var ( ...@@ -90,10 +92,8 @@ var (
) )
type RunObject struct { type RunObject struct {
Versioned runtime.Object Object runtime.Object
Object runtime.Object Mapping *meta.RESTMapping
Kind string
Mapping *meta.RESTMapping
} }
type RunOptions struct { type RunOptions struct {
...@@ -107,6 +107,8 @@ type RunOptions struct { ...@@ -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 { ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 != nil {
return nil, err
}
client, err := f.ClientForMapping(mapping)
if err != nil {
return nil, err
}
if err := o.Recorder.Record(obj); err != nil { if err := o.Recorder.Record(obj); err != nil {
glog.V(4).Infof("error recording current command: %v", err) glog.V(4).Infof("error recording current command: %v", err)
} }
versioned := obj actualObj := obj
if !o.DryRun { if !o.DryRun {
resourceMapper := &resource.Mapper{ if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), obj, scheme.DefaultJSONEncoder()); err != nil {
RESTMapper: mapper,
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
Decoder: cmdutil.InternalVersionDecoder(),
}
info, err := resourceMapper.InfoForObject(obj, legacyscheme.Scheme, nil)
if err != nil {
return nil, err return nil, err
} }
client, err := f.ClientForMapping(mapping)
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info.Object, cmdutil.InternalVersionJSONEncoder()); err != nil { if err != nil {
return nil, err return nil, err
} }
actualObj, err = resource.NewHelper(client, mapping).Create(namespace, false, obj)
obj, err = resource.NewHelper(client, mapping).Create(namespace, false, info.Object)
if err != nil { if err != nil {
return nil, err return nil, err
} }
versioned = cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping)
} }
actualObj = cmdutil.AsDefaultVersionedOrOriginal(actualObj, mapping)
return &RunObject{ return &RunObject{
Versioned: versioned, Object: actualObj,
Object: obj, Mapping: mapping,
Kind: groupVersionKind.Kind,
Mapping: mapping,
}, nil }, nil
} }
...@@ -27,6 +27,7 @@ go_library( ...@@ -27,6 +27,7 @@ go_library(
"//pkg/kubectl/cmd/util/env:go_default_library", "//pkg/kubectl/cmd/util/env:go_default_library",
"//pkg/kubectl/genericclioptions:go_default_library", "//pkg/kubectl/genericclioptions:go_default_library",
"//pkg/kubectl/resource:go_default_library", "//pkg/kubectl/resource:go_default_library",
"//pkg/kubectl/scheme:go_default_library",
"//pkg/kubectl/util/i18n:go_default_library", "//pkg/kubectl/util/i18n:go_default_library",
"//pkg/printers:go_default_library", "//pkg/printers:go_default_library",
"//vendor/github.com/golang/glog:go_default_library", "//vendor/github.com/golang/glog:go_default_library",
...@@ -82,6 +83,7 @@ go_test( ...@@ -82,6 +83,7 @@ go_test(
"//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/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/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",
], ],
......
...@@ -30,12 +30,12 @@ import ( ...@@ -30,12 +30,12 @@ import (
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
utilerrors "k8s.io/apimachinery/pkg/util/errors" utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
envutil "k8s.io/kubernetes/pkg/kubectl/cmd/util/env" envutil "k8s.io/kubernetes/pkg/kubectl/cmd/util/env"
"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/printers" "k8s.io/kubernetes/pkg/printers"
) )
...@@ -241,7 +241,7 @@ func (o *EnvOptions) RunEnv() error { ...@@ -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(scheme.Scheme, scheme.Registry.RegisteredGroupVersions()...).
LocalParam(o.Local). LocalParam(o.Local).
ContinueOnError(). ContinueOnError().
NamespaceParam(o.namespace).DefaultNamespace(). NamespaceParam(o.namespace).DefaultNamespace().
...@@ -261,11 +261,7 @@ func (o *EnvOptions) RunEnv() error { ...@@ -261,11 +261,7 @@ func (o *EnvOptions) RunEnv() error {
} }
for _, info := range infos { for _, info := range infos {
versionedObject, err := legacyscheme.Scheme.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion()) switch from := info.Object.(type) {
if err != nil {
return err
}
switch from := versionedObject.(type) {
case *v1.Secret: case *v1.Secret:
for key := range from.Data { for key := range from.Data {
envVar := v1.EnvVar{ envVar := v1.EnvVar{
...@@ -309,7 +305,7 @@ func (o *EnvOptions) RunEnv() error { ...@@ -309,7 +305,7 @@ func (o *EnvOptions) RunEnv() error {
} }
b := o.builder(). b := o.builder().
Internal(legacyscheme.Scheme). WithScheme(scheme.Scheme, scheme.Registry.RegisteredGroupVersions()...).
LocalParam(o.Local). LocalParam(o.Local).
ContinueOnError(). ContinueOnError().
NamespaceParam(o.namespace).DefaultNamespace(). NamespaceParam(o.namespace).DefaultNamespace().
...@@ -326,8 +322,7 @@ func (o *EnvOptions) RunEnv() error { ...@@ -326,8 +322,7 @@ func (o *EnvOptions) RunEnv() error {
if err != nil { if err != nil {
return err return err
} }
patches := CalculatePatches(infos, cmdutil.InternalVersionJSONEncoder(), func(info *resource.Info) ([]byte, error) { patches := CalculatePatches(infos, scheme.DefaultJSONEncoder(), func(info *resource.Info) ([]byte, error) {
info.Object = cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping)
_, err := o.updatePodSpecForObject(info.Object, func(spec *v1.PodSpec) error { _, err := o.updatePodSpecForObject(info.Object, func(spec *v1.PodSpec) error {
resolutionErrorsEncountered := false resolutionErrorsEncountered := false
containers, _ := selectContainers(spec.Containers, o.ContainerSelector) containers, _ := selectContainers(spec.Containers, o.ContainerSelector)
...@@ -394,7 +389,7 @@ func (o *EnvOptions) RunEnv() error { ...@@ -394,7 +389,7 @@ func (o *EnvOptions) RunEnv() error {
}) })
if err == nil { if err == nil {
return runtime.Encode(cmdutil.InternalVersionJSONEncoder(), info.Object) return runtime.Encode(scheme.DefaultJSONEncoder(), info.Object)
} }
return nil, err return nil, err
}) })
...@@ -418,7 +413,7 @@ func (o *EnvOptions) RunEnv() error { ...@@ -418,7 +413,7 @@ func (o *EnvOptions) RunEnv() error {
} }
if o.Local || o.dryRun { if o.Local || o.dryRun {
if err := o.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(patch.Info.Object, patch.Info.Mapping), o.Out); err != nil { if err := o.PrintObj(patch.Info.Object, o.Out); err != nil {
return err return err
} }
continue continue
...@@ -437,7 +432,7 @@ func (o *EnvOptions) RunEnv() error { ...@@ -437,7 +432,7 @@ func (o *EnvOptions) RunEnv() error {
return fmt.Errorf("at least one environment variable must be provided") return fmt.Errorf("at least one environment variable must be provided")
} }
if err := o.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping), o.Out); err != nil { if err := o.PrintObj(info.Object, o.Out); err != nil {
return err return err
} }
} }
......
...@@ -36,9 +36,9 @@ import ( ...@@ -36,9 +36,9 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"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"
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
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"
...@@ -50,7 +50,7 @@ func TestSetEnvLocal(t *testing.T) { ...@@ -50,7 +50,7 @@ func TestSetEnvLocal(t *testing.T) {
tf := cmdtesting.NewTestFactory() tf := cmdtesting.NewTestFactory()
defer tf.Cleanup() defer tf.Cleanup()
ns := legacyscheme.Codecs ns := serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Version: ""}, GroupVersion: schema.GroupVersion{Version: ""},
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
...@@ -93,7 +93,7 @@ func TestSetMultiResourcesEnvLocal(t *testing.T) { ...@@ -93,7 +93,7 @@ func TestSetMultiResourcesEnvLocal(t *testing.T) {
tf := cmdtesting.NewTestFactory() tf := cmdtesting.NewTestFactory()
defer tf.Cleanup() defer tf.Cleanup()
ns := legacyscheme.Codecs ns := serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Version: ""}, GroupVersion: schema.GroupVersion{Version: ""},
NegotiatedSerializer: ns, NegotiatedSerializer: ns,
...@@ -464,7 +464,7 @@ func TestSetEnvRemote(t *testing.T) { ...@@ -464,7 +464,7 @@ func TestSetEnvRemote(t *testing.T) {
defer tf.Cleanup() defer tf.Cleanup()
codec := scheme.Codecs.CodecForVersions(scheme.Codecs.LegacyCodec(groupVersion), scheme.Codecs.UniversalDecoder(groupVersion), groupVersion, groupVersion) codec := scheme.Codecs.CodecForVersions(scheme.Codecs.LegacyCodec(groupVersion), scheme.Codecs.UniversalDecoder(groupVersion), groupVersion, groupVersion)
ns := legacyscheme.Codecs ns := serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}
tf.Namespace = "test" tf.Namespace = "test"
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
GroupVersion: groupVersion, GroupVersion: groupVersion,
......
...@@ -19,11 +19,9 @@ package set ...@@ -19,11 +19,9 @@ package set
import ( import (
"fmt" "fmt"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/printers"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
...@@ -32,7 +30,9 @@ import ( ...@@ -32,7 +30,9 @@ 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/printers"
) )
// ImageOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of // ImageOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of
...@@ -161,7 +161,7 @@ func (o *SetImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [ ...@@ -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(scheme.Scheme, scheme.Registry.RegisteredGroupVersions()...).
LocalParam(o.Local). LocalParam(o.Local).
ContinueOnError(). ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace(). NamespaceParam(cmdNamespace).DefaultNamespace().
...@@ -209,9 +209,8 @@ func (o *SetImageOptions) Validate() error { ...@@ -209,9 +209,8 @@ func (o *SetImageOptions) Validate() error {
func (o *SetImageOptions) Run() error { func (o *SetImageOptions) Run() error {
allErrs := []error{} allErrs := []error{}
patches := CalculatePatches(o.Infos, cmdutil.InternalVersionJSONEncoder(), func(info *resource.Info) ([]byte, error) { patches := CalculatePatches(o.Infos, scheme.DefaultJSONEncoder(), func(info *resource.Info) ([]byte, error) {
transformed := false transformed := false
info.Object = cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping)
_, err := o.UpdatePodSpecForObject(info.Object, func(spec *v1.PodSpec) error { _, err := o.UpdatePodSpecForObject(info.Object, func(spec *v1.PodSpec) error {
for name, image := range o.ContainerImages { for name, image := range o.ContainerImages {
var ( var (
...@@ -259,7 +258,7 @@ func (o *SetImageOptions) Run() error { ...@@ -259,7 +258,7 @@ func (o *SetImageOptions) Run() error {
glog.V(4).Infof("error recording current command: %v", err) glog.V(4).Infof("error recording current command: %v", err)
} }
return runtime.Encode(cmdutil.InternalVersionJSONEncoder(), info.Object) return runtime.Encode(scheme.DefaultJSONEncoder(), info.Object)
}) })
for _, patch := range patches { for _, patch := range patches {
...@@ -275,7 +274,7 @@ func (o *SetImageOptions) Run() error { ...@@ -275,7 +274,7 @@ func (o *SetImageOptions) Run() error {
} }
if o.Local || o.DryRun { if o.Local || o.DryRun {
if err := o.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(patch.Info.Object, patch.Info.Mapping), o.Out); err != nil { if err := o.PrintObj(patch.Info.Object, o.Out); err != nil {
return err return err
} }
continue continue
...@@ -289,7 +288,7 @@ func (o *SetImageOptions) Run() error { ...@@ -289,7 +288,7 @@ func (o *SetImageOptions) Run() error {
} }
info.Refresh(obj, true) info.Refresh(obj, true)
if err := o.PrintObj(cmdutil.AsDefaultVersionedOrOriginal(info.Object, info.Mapping), o.Out); err != nil { if err := o.PrintObj(info.Object, o.Out); err != nil {
return err return err
} }
} }
......
...@@ -24,9 +24,8 @@ import ( ...@@ -24,9 +24,8 @@ import (
"strings" "strings"
"testing" "testing"
"k8s.io/kubernetes/pkg/printers"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
appsv1 "k8s.io/api/apps/v1" appsv1 "k8s.io/api/apps/v1"
appsv1beta1 "k8s.io/api/apps/v1beta1" appsv1beta1 "k8s.io/api/apps/v1beta1"
appsv1beta2 "k8s.io/api/apps/v1beta2" appsv1beta2 "k8s.io/api/apps/v1beta2"
...@@ -36,21 +35,22 @@ import ( ...@@ -36,21 +35,22 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"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"
restclient "k8s.io/client-go/rest" restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
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/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/kubectl/scheme" "k8s.io/kubernetes/pkg/kubectl/scheme"
"k8s.io/kubernetes/pkg/printers"
) )
func TestImageLocal(t *testing.T) { func TestImageLocal(t *testing.T) {
tf := cmdtesting.NewTestFactory() tf := cmdtesting.NewTestFactory()
defer tf.Cleanup() defer tf.Cleanup()
ns := legacyscheme.Codecs ns := serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Version: ""}, GroupVersion: schema.GroupVersion{Version: ""},
...@@ -173,7 +173,7 @@ func TestSetMultiResourcesImageLocal(t *testing.T) { ...@@ -173,7 +173,7 @@ func TestSetMultiResourcesImageLocal(t *testing.T) {
tf := cmdtesting.NewTestFactory() tf := cmdtesting.NewTestFactory()
defer tf.Cleanup() defer tf.Cleanup()
ns := legacyscheme.Codecs ns := serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Version: ""}, GroupVersion: schema.GroupVersion{Version: ""},
...@@ -554,7 +554,7 @@ func TestSetImageRemote(t *testing.T) { ...@@ -554,7 +554,7 @@ func TestSetImageRemote(t *testing.T) {
defer tf.Cleanup() defer tf.Cleanup()
codec := scheme.Codecs.CodecForVersions(scheme.Codecs.LegacyCodec(groupVersion), scheme.Codecs.UniversalDecoder(groupVersion), groupVersion, groupVersion) codec := scheme.Codecs.CodecForVersions(scheme.Codecs.LegacyCodec(groupVersion), scheme.Codecs.UniversalDecoder(groupVersion), groupVersion, groupVersion)
ns := legacyscheme.Codecs ns := serializer.DirectCodecFactory{CodecFactory: scheme.Codecs}
tf.Namespace = "test" tf.Namespace = "test"
tf.Client = &fake.RESTClient{ tf.Client = &fake.RESTClient{
GroupVersion: groupVersion, GroupVersion: groupVersion,
......
...@@ -173,7 +173,7 @@ func (o *SetResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, ar ...@@ -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().
......
...@@ -146,7 +146,7 @@ func (o *SetSelectorOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, arg ...@@ -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().
......
...@@ -152,7 +152,7 @@ func (o *SetServiceAccountOptions) Complete(f cmdutil.Factory, cmd *cobra.Comman ...@@ -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().
......
...@@ -138,7 +138,7 @@ func (o *SubjectOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [] ...@@ -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().
......
...@@ -172,7 +172,7 @@ func (o *TaintOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st ...@@ -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 != "" {
......
...@@ -24,11 +24,12 @@ go_library( ...@@ -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",
......
...@@ -30,11 +30,12 @@ import ( ...@@ -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 { ...@@ -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)
} }
...@@ -253,8 +255,9 @@ func NewTestFactory() *TestFactory { ...@@ -253,8 +255,9 @@ func NewTestFactory() *TestFactory {
// to avoid polluting an existing user config. // to avoid polluting an existing user config.
config, configFile := defaultFakeClientConfig() config, configFile := defaultFakeClientConfig()
return &TestFactory{ return &TestFactory{
Factory: cmdutil.NewFactory(config), Factory: cmdutil.NewFactory(config),
tempConfigFile: configFile, FakeDynamicClient: fakedynamic.NewSimpleDynamicClient(legacyscheme.Scheme),
tempConfigFile: configFile,
} }
} }
...@@ -309,7 +312,7 @@ func (f *TestFactory) ClientForMapping(mapping *meta.RESTMapping) (resource.REST ...@@ -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 { ...@@ -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) { ...@@ -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)
......
...@@ -66,7 +66,6 @@ type EditOptions struct { ...@@ -66,7 +66,6 @@ type EditOptions struct {
cmdutil.ValidateOptions cmdutil.ValidateOptions
ResourceMapper *resource.Mapper
OriginalResult *resource.Result OriginalResult *resource.Result
EditMode EditMode EditMode EditMode
......
...@@ -33,6 +33,7 @@ import ( ...@@ -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 { ...@@ -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)
......
...@@ -22,7 +22,6 @@ import ( ...@@ -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 ...@@ -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)
} }
......
...@@ -52,6 +52,7 @@ import ( ...@@ -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) { ...@@ -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 {
...@@ -249,6 +257,7 @@ func (f *ring0Factory) UpdatePodSpecForObject(obj runtime.Object, fn func(*v1.Po ...@@ -249,6 +257,7 @@ func (f *ring0Factory) UpdatePodSpecForObject(obj runtime.Object, fn func(*v1.Po
t.Spec.Template = &v1.PodTemplateSpec{} t.Spec.Template = &v1.PodTemplateSpec{}
} }
return true, fn(&t.Spec.Template.Spec) return true, fn(&t.Spec.Template.Spec)
// Deployment // Deployment
case *extensionsv1beta1.Deployment: case *extensionsv1beta1.Deployment:
return true, fn(&t.Spec.Template.Spec) return true, fn(&t.Spec.Template.Spec)
...@@ -258,6 +267,7 @@ func (f *ring0Factory) UpdatePodSpecForObject(obj runtime.Object, fn func(*v1.Po ...@@ -258,6 +267,7 @@ func (f *ring0Factory) UpdatePodSpecForObject(obj runtime.Object, fn func(*v1.Po
return true, fn(&t.Spec.Template.Spec) return true, fn(&t.Spec.Template.Spec)
case *appsv1.Deployment: case *appsv1.Deployment:
return true, fn(&t.Spec.Template.Spec) return true, fn(&t.Spec.Template.Spec)
// DaemonSet // DaemonSet
case *extensionsv1beta1.DaemonSet: case *extensionsv1beta1.DaemonSet:
return true, fn(&t.Spec.Template.Spec) return true, fn(&t.Spec.Template.Spec)
...@@ -265,6 +275,7 @@ func (f *ring0Factory) UpdatePodSpecForObject(obj runtime.Object, fn func(*v1.Po ...@@ -265,6 +275,7 @@ func (f *ring0Factory) UpdatePodSpecForObject(obj runtime.Object, fn func(*v1.Po
return true, fn(&t.Spec.Template.Spec) return true, fn(&t.Spec.Template.Spec)
case *appsv1.DaemonSet: case *appsv1.DaemonSet:
return true, fn(&t.Spec.Template.Spec) return true, fn(&t.Spec.Template.Spec)
// ReplicaSet // ReplicaSet
case *extensionsv1beta1.ReplicaSet: case *extensionsv1beta1.ReplicaSet:
return true, fn(&t.Spec.Template.Spec) return true, fn(&t.Spec.Template.Spec)
...@@ -272,6 +283,7 @@ func (f *ring0Factory) UpdatePodSpecForObject(obj runtime.Object, fn func(*v1.Po ...@@ -272,6 +283,7 @@ func (f *ring0Factory) UpdatePodSpecForObject(obj runtime.Object, fn func(*v1.Po
return true, fn(&t.Spec.Template.Spec) return true, fn(&t.Spec.Template.Spec)
case *appsv1.ReplicaSet: case *appsv1.ReplicaSet:
return true, fn(&t.Spec.Template.Spec) return true, fn(&t.Spec.Template.Spec)
// StatefulSet // StatefulSet
case *appsv1beta1.StatefulSet: case *appsv1beta1.StatefulSet:
return true, fn(&t.Spec.Template.Spec) return true, fn(&t.Spec.Template.Spec)
...@@ -279,14 +291,17 @@ func (f *ring0Factory) UpdatePodSpecForObject(obj runtime.Object, fn func(*v1.Po ...@@ -279,14 +291,17 @@ func (f *ring0Factory) UpdatePodSpecForObject(obj runtime.Object, fn func(*v1.Po
return true, fn(&t.Spec.Template.Spec) return true, fn(&t.Spec.Template.Spec)
case *appsv1.StatefulSet: case *appsv1.StatefulSet:
return true, fn(&t.Spec.Template.Spec) return true, fn(&t.Spec.Template.Spec)
// Job // Job
case *batchv1.Job: case *batchv1.Job:
return true, fn(&t.Spec.Template.Spec) return true, fn(&t.Spec.Template.Spec)
// CronJob // CronJob
case *batchv1beta1.CronJob: case *batchv1beta1.CronJob:
return true, fn(&t.Spec.JobTemplate.Spec.Template.Spec) return true, fn(&t.Spec.JobTemplate.Spec.Template.Spec)
case *batchv2alpha1.CronJob: case *batchv2alpha1.CronJob:
return true, fn(&t.Spec.JobTemplate.Spec.Template.Spec) return true, fn(&t.Spec.JobTemplate.Spec.Template.Spec)
default: default:
return false, fmt.Errorf("the object is not a pod or does not have a pod template") return false, fmt.Errorf("the object is not a pod or does not have a pod template")
} }
......
...@@ -27,7 +27,13 @@ import ( ...@@ -27,7 +27,13 @@ import (
"sync" "sync"
"time" "time"
appsv1 "k8s.io/api/apps/v1"
appsv1beta1 "k8s.io/api/apps/v1beta1"
appsv1beta2 "k8s.io/api/apps/v1beta2"
batchv1 "k8s.io/api/batch/v1"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
corev1 "k8s.io/api/core/v1"
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
"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/labels" "k8s.io/apimachinery/pkg/labels"
...@@ -38,6 +44,7 @@ import ( ...@@ -38,6 +44,7 @@ import (
"k8s.io/kubernetes/pkg/apis/apps" "k8s.io/kubernetes/pkg/apis/apps"
"k8s.io/kubernetes/pkg/apis/batch" "k8s.io/kubernetes/pkg/apis/batch"
api "k8s.io/kubernetes/pkg/apis/core" api "k8s.io/kubernetes/pkg/apis/core"
apiv1 "k8s.io/kubernetes/pkg/apis/core/v1"
"k8s.io/kubernetes/pkg/apis/extensions" "k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/controller"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
...@@ -198,6 +205,8 @@ func (f *ring1Factory) LogsForObject(object, options runtime.Object, timeout tim ...@@ -198,6 +205,8 @@ func (f *ring1Factory) LogsForObject(object, options runtime.Object, timeout tim
switch t := object.(type) { switch t := object.(type) {
case *api.Pod: case *api.Pod:
return clientset.Core().Pods(t.Namespace).GetLogs(t.Name, opts), nil return clientset.Core().Pods(t.Namespace).GetLogs(t.Name, opts), nil
case *corev1.Pod:
return clientset.Core().Pods(t.Namespace).GetLogs(t.Name, opts), nil
} }
namespace, selector, err := selectorsForObject(object) namespace, selector, err := selectorsForObject(object)
...@@ -223,10 +232,31 @@ func selectorsForObject(object runtime.Object) (namespace string, selector label ...@@ -223,10 +232,31 @@ func selectorsForObject(object runtime.Object) (namespace string, selector label
if err != nil { if err != nil {
return "", nil, fmt.Errorf("invalid label selector: %v", err) return "", nil, fmt.Errorf("invalid label selector: %v", err)
} }
case *extensionsv1beta1.ReplicaSet:
namespace = t.Namespace
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
if err != nil {
return "", nil, fmt.Errorf("invalid label selector: %v", err)
}
case *appsv1.ReplicaSet:
namespace = t.Namespace
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
if err != nil {
return "", nil, fmt.Errorf("invalid label selector: %v", err)
}
case *appsv1beta2.ReplicaSet:
namespace = t.Namespace
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
if err != nil {
return "", nil, fmt.Errorf("invalid label selector: %v", err)
}
case *api.ReplicationController: case *api.ReplicationController:
namespace = t.Namespace namespace = t.Namespace
selector = labels.SelectorFromSet(t.Spec.Selector) selector = labels.SelectorFromSet(t.Spec.Selector)
case *corev1.ReplicationController:
namespace = t.Namespace
selector = labels.SelectorFromSet(t.Spec.Selector)
case *apps.StatefulSet: case *apps.StatefulSet:
namespace = t.Namespace namespace = t.Namespace
...@@ -234,6 +264,24 @@ func selectorsForObject(object runtime.Object) (namespace string, selector label ...@@ -234,6 +264,24 @@ func selectorsForObject(object runtime.Object) (namespace string, selector label
if err != nil { if err != nil {
return "", nil, fmt.Errorf("invalid label selector: %v", err) return "", nil, fmt.Errorf("invalid label selector: %v", err)
} }
case *appsv1.StatefulSet:
namespace = t.Namespace
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
if err != nil {
return "", nil, fmt.Errorf("invalid label selector: %v", err)
}
case *appsv1beta1.StatefulSet:
namespace = t.Namespace
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
if err != nil {
return "", nil, fmt.Errorf("invalid label selector: %v", err)
}
case *appsv1beta2.StatefulSet:
namespace = t.Namespace
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
if err != nil {
return "", nil, fmt.Errorf("invalid label selector: %v", err)
}
case *extensions.DaemonSet: case *extensions.DaemonSet:
namespace = t.Namespace namespace = t.Namespace
...@@ -241,6 +289,24 @@ func selectorsForObject(object runtime.Object) (namespace string, selector label ...@@ -241,6 +289,24 @@ func selectorsForObject(object runtime.Object) (namespace string, selector label
if err != nil { if err != nil {
return "", nil, fmt.Errorf("invalid label selector: %v", err) return "", nil, fmt.Errorf("invalid label selector: %v", err)
} }
case *extensionsv1beta1.DaemonSet:
namespace = t.Namespace
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
if err != nil {
return "", nil, fmt.Errorf("invalid label selector: %v", err)
}
case *appsv1.DaemonSet:
namespace = t.Namespace
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
if err != nil {
return "", nil, fmt.Errorf("invalid label selector: %v", err)
}
case *appsv1beta2.DaemonSet:
namespace = t.Namespace
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
if err != nil {
return "", nil, fmt.Errorf("invalid label selector: %v", err)
}
case *extensions.Deployment: case *extensions.Deployment:
namespace = t.Namespace namespace = t.Namespace
...@@ -248,6 +314,30 @@ func selectorsForObject(object runtime.Object) (namespace string, selector label ...@@ -248,6 +314,30 @@ func selectorsForObject(object runtime.Object) (namespace string, selector label
if err != nil { if err != nil {
return "", nil, fmt.Errorf("invalid label selector: %v", err) return "", nil, fmt.Errorf("invalid label selector: %v", err)
} }
case *extensionsv1beta1.Deployment:
namespace = t.Namespace
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
if err != nil {
return "", nil, fmt.Errorf("invalid label selector: %v", err)
}
case *appsv1.Deployment:
namespace = t.Namespace
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
if err != nil {
return "", nil, fmt.Errorf("invalid label selector: %v", err)
}
case *appsv1beta1.Deployment:
namespace = t.Namespace
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
if err != nil {
return "", nil, fmt.Errorf("invalid label selector: %v", err)
}
case *appsv1beta2.Deployment:
namespace = t.Namespace
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
if err != nil {
return "", nil, fmt.Errorf("invalid label selector: %v", err)
}
case *batch.Job: case *batch.Job:
namespace = t.Namespace namespace = t.Namespace
...@@ -255,6 +345,12 @@ func selectorsForObject(object runtime.Object) (namespace string, selector label ...@@ -255,6 +345,12 @@ func selectorsForObject(object runtime.Object) (namespace string, selector label
if err != nil { if err != nil {
return "", nil, fmt.Errorf("invalid label selector: %v", err) return "", nil, fmt.Errorf("invalid label selector: %v", err)
} }
case *batchv1.Job:
namespace = t.Namespace
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
if err != nil {
return "", nil, fmt.Errorf("invalid label selector: %v", err)
}
case *api.Service: case *api.Service:
namespace = t.Namespace namespace = t.Namespace
...@@ -262,6 +358,12 @@ func selectorsForObject(object runtime.Object) (namespace string, selector label ...@@ -262,6 +358,12 @@ func selectorsForObject(object runtime.Object) (namespace string, selector label
return "", nil, fmt.Errorf("invalid service '%s': Service is defined without a selector", t.Name) return "", nil, fmt.Errorf("invalid service '%s': Service is defined without a selector", t.Name)
} }
selector = labels.SelectorFromSet(t.Spec.Selector) selector = labels.SelectorFromSet(t.Spec.Selector)
case *corev1.Service:
namespace = t.Namespace
if t.Spec.Selector == nil || len(t.Spec.Selector) == 0 {
return "", nil, fmt.Errorf("invalid service '%s': Service is defined without a selector", t.Name)
}
selector = labels.SelectorFromSet(t.Spec.Selector)
default: default:
return "", nil, fmt.Errorf("selector for %T not implemented", object) return "", nil, fmt.Errorf("selector for %T not implemented", object)
...@@ -325,6 +427,11 @@ func (f *ring1Factory) AttachablePodForObject(object runtime.Object, timeout tim ...@@ -325,6 +427,11 @@ func (f *ring1Factory) AttachablePodForObject(object runtime.Object, timeout tim
switch t := object.(type) { switch t := object.(type) {
case *api.Pod: case *api.Pod:
return t, nil return t, nil
case *corev1.Pod:
internalPod := &api.Pod{}
err := apiv1.Convert_v1_Pod_To_core_Pod(t, internalPod, nil)
return internalPod, err
} }
namespace, selector, err := selectorsForObject(object) namespace, selector, err := selectorsForObject(object)
......
...@@ -25,7 +25,6 @@ import ( ...@@ -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 ( ...@@ -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) { ...@@ -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) { ...@@ -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)
......
...@@ -8,6 +8,7 @@ go_library( ...@@ -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( ...@@ -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( ...@@ -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",
......
...@@ -26,10 +26,12 @@ import ( ...@@ -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 { ...@@ -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
negotiatedSerializer runtime.NegotiatedSerializer
// 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 { ...@@ -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 { ...@@ -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,45 @@ func (b *Builder) FilenameParam(enforceNamespace bool, filenameOptions *Filename ...@@ -194,39 +216,45 @@ 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)
negotiatedSerializer := runtime.NegotiatedSerializer(codecFactory)
// if you specified versions, you're specifying a desire for external types, which you don't want to round-trip through
// internal types
if len(decodingVersions) > 0 {
negotiatedSerializer = &serializer.DirectCodecFactory{CodecFactory: codecFactory}
}
b.negotiatedSerializer = negotiatedSerializer
b.mapper = &mapper{
localFn: b.isLocal,
restMapper: b.restMapper,
clientFn: b.getClient,
decoder: codecFactory.UniversalDecoder(decodingVersions...),
}
b.objectTyper = typer
return b return b
} }
...@@ -241,9 +269,6 @@ func (b *Builder) LocalParam(local bool) *Builder { ...@@ -241,9 +269,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 +277,7 @@ func (b *Builder) isLocal() bool { ...@@ -252,7 +277,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 +661,13 @@ func (b *Builder) mappingFor(resourceOrKindArg string) (*meta.RESTMapping, error ...@@ -636,13 +661,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 +677,12 @@ func (b *Builder) mappingFor(resourceOrKindArg string) (*meta.RESTMapping, error ...@@ -652,12 +677,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 +807,7 @@ func (b *Builder) visitBySelector() *Result { ...@@ -782,7 +807,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 +828,18 @@ func (b *Builder) visitBySelector() *Result { ...@@ -803,6 +828,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.negotiatedSerializer != nil {
return b.clientConfigFn.clientForGroupVersion(gv, b.negotiatedSerializer)
}
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 +869,7 @@ func (b *Builder) visitByResource() *Result { ...@@ -832,7 +869,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 +947,7 @@ func (b *Builder) visitByName() *Result { ...@@ -910,7 +947,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
......
...@@ -47,11 +47,11 @@ import ( ...@@ -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 { ...@@ -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 ...@@ -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 { ...@@ -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) { ...@@ -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))
} }
} }
} }
......
/*
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)
}
...@@ -17,38 +17,24 @@ limitations under the License. ...@@ -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 { ...@@ -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())
} }
...@@ -27,20 +27,20 @@ import ( ...@@ -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) { ...@@ -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) { ...@@ -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 ...@@ -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 [] ...@@ -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
}
...@@ -42,7 +42,7 @@ type Result struct { ...@@ -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 { ...@@ -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
} }
......
...@@ -372,12 +372,12 @@ func (v ContinueOnErrorVisitor) Visit(fn VisitorFunc) error { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment