mirror of https://github.com/k3s-io/k3s
Break kubectl from assuming details of codecs
Most of the logic related to type and kind retrieval belongs in the codec, not in the various classes. Make it explicit that the codec should handle these details. Factory now returns a universal Decoder and a JSONEncoder to assist code in kubectl that needs to specifically deal with JSON serialization (apply, merge, patch, edit, jsonpath). Add comments to indicate the serialization is explicit in those places. These methods decode to internal and encode to the preferred API version as previous, although in the future they may be changed. React to removing Codec from version interfaces and RESTMapping by passing it in to all the places that it is needed.pull/6/head
parent
181dc7c64c
commit
2fd38a7dc0
|
@ -21,6 +21,7 @@ import (
|
|||
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
type debugError interface {
|
||||
|
@ -80,7 +81,7 @@ func SetOriginalConfiguration(info *resource.Info, original []byte) error {
|
|||
// If annotate is true, it embeds the result as an anotation in the modified
|
||||
// configuration. If an object was read from the command input, it will use that
|
||||
// version of the object. Otherwise, it will use the version from the server.
|
||||
func GetModifiedConfiguration(info *resource.Info, annotate bool) ([]byte, error) {
|
||||
func GetModifiedConfiguration(info *resource.Info, annotate bool, codec runtime.Encoder) ([]byte, error) {
|
||||
// First serialize the object without the annotation to prevent recursion,
|
||||
// then add that serialization to it as the annotation and serialize it again.
|
||||
var modified []byte
|
||||
|
@ -100,6 +101,8 @@ func GetModifiedConfiguration(info *resource.Info, annotate bool) ([]byte, error
|
|||
original := annotations[LastAppliedConfigAnnotation]
|
||||
delete(annotations, LastAppliedConfigAnnotation)
|
||||
accessor.SetAnnotations(annotations)
|
||||
// TODO: this needs to be abstracted - there should be no assumption that versioned object
|
||||
// can be marshalled to JSON.
|
||||
modified, err = json.Marshal(info.VersionedObject)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -108,6 +111,8 @@ func GetModifiedConfiguration(info *resource.Info, annotate bool) ([]byte, error
|
|||
if annotate {
|
||||
annotations[LastAppliedConfigAnnotation] = string(modified)
|
||||
accessor.SetAnnotations(annotations)
|
||||
// TODO: this needs to be abstracted - there should be no assumption that versioned object
|
||||
// can be marshalled to JSON.
|
||||
modified, err = json.Marshal(info.VersionedObject)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -136,7 +141,7 @@ func GetModifiedConfiguration(info *resource.Info, annotate bool) ([]byte, error
|
|||
return nil, err
|
||||
}
|
||||
|
||||
modified, err = info.Mapping.Codec.Encode(info.Object)
|
||||
modified, err = runtime.Encode(codec, info.Object)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -147,7 +152,7 @@ func GetModifiedConfiguration(info *resource.Info, annotate bool) ([]byte, error
|
|||
return nil, err
|
||||
}
|
||||
|
||||
modified, err = info.Mapping.Codec.Encode(info.Object)
|
||||
modified, err = runtime.Encode(codec, info.Object)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -165,17 +170,17 @@ func GetModifiedConfiguration(info *resource.Info, annotate bool) ([]byte, error
|
|||
|
||||
// UpdateApplyAnnotation calls CreateApplyAnnotation if the last applied
|
||||
// configuration annotation is already present. Otherwise, it does nothing.
|
||||
func UpdateApplyAnnotation(info *resource.Info) error {
|
||||
func UpdateApplyAnnotation(info *resource.Info, codec runtime.Encoder) error {
|
||||
if original, err := GetOriginalConfiguration(info); err != nil || len(original) <= 0 {
|
||||
return err
|
||||
}
|
||||
return CreateApplyAnnotation(info)
|
||||
return CreateApplyAnnotation(info, codec)
|
||||
}
|
||||
|
||||
// CreateApplyAnnotation gets the modified configuration of the object,
|
||||
// without embedding it again, and then sets it on the object as the annotation.
|
||||
func CreateApplyAnnotation(info *resource.Info) error {
|
||||
modified, err := GetModifiedConfiguration(info, false)
|
||||
func CreateApplyAnnotation(info *resource.Info, codec runtime.Encoder) error {
|
||||
modified, err := GetModifiedConfiguration(info, false, codec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -184,9 +189,9 @@ func CreateApplyAnnotation(info *resource.Info) error {
|
|||
|
||||
// Create the annotation used by kubectl apply only when createAnnotation is true
|
||||
// Otherwise, only update the annotation when it already exists
|
||||
func CreateOrUpdateAnnotation(createAnnotation bool, info *resource.Info) error {
|
||||
func CreateOrUpdateAnnotation(createAnnotation bool, info *resource.Info, codec runtime.Encoder) error {
|
||||
if createAnnotation {
|
||||
return CreateApplyAnnotation(info)
|
||||
return CreateApplyAnnotation(info, codec)
|
||||
}
|
||||
return UpdateApplyAnnotation(info)
|
||||
return UpdateApplyAnnotation(info, codec)
|
||||
}
|
||||
|
|
|
@ -151,7 +151,7 @@ func (o *AnnotateOptions) Complete(f *cmdutil.Factory, out io.Writer, cmd *cobra
|
|||
}
|
||||
|
||||
mapper, typer := f.Object()
|
||||
o.builder = resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
|
||||
o.builder = resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
ContinueOnError().
|
||||
NamespaceParam(namespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, o.filenames...).
|
||||
|
@ -211,7 +211,7 @@ func (o AnnotateOptions) RunAnnotate() error {
|
|||
}
|
||||
|
||||
mapping := info.ResourceMapping()
|
||||
client, err := o.f.RESTClient(mapping)
|
||||
client, err := o.f.ClientForMapping(mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/strategicpatch"
|
||||
)
|
||||
|
||||
|
@ -92,7 +93,7 @@ func RunApply(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *Ap
|
|||
}
|
||||
|
||||
mapper, typer := f.Object()
|
||||
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
|
||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
Schema(schema).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
|
@ -104,6 +105,8 @@ func RunApply(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *Ap
|
|||
return err
|
||||
}
|
||||
|
||||
encoder := f.JSONEncoder()
|
||||
|
||||
count := 0
|
||||
err = r.Visit(func(info *resource.Info, err error) error {
|
||||
// In this method, info.Object contains the object retrieved from the server
|
||||
|
@ -115,7 +118,7 @@ func RunApply(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *Ap
|
|||
// Get the modified configuration of the object. Embed the result
|
||||
// as an annotation in the modified configuration, so that it will appear
|
||||
// in the patch sent to the server.
|
||||
modified, err := kubectl.GetModifiedConfiguration(info, true)
|
||||
modified, err := kubectl.GetModifiedConfiguration(info, true, encoder)
|
||||
if err != nil {
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving modified configuration from:\n%v\nfor:", info), info.Source, err)
|
||||
}
|
||||
|
@ -126,7 +129,7 @@ func RunApply(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *Ap
|
|||
}
|
||||
// Create the resource if it doesn't exist
|
||||
// First, update the annotation used by kubectl apply
|
||||
if err := kubectl.CreateApplyAnnotation(info); err != nil {
|
||||
if err := kubectl.CreateApplyAnnotation(info, encoder); err != nil {
|
||||
return cmdutil.AddSourceToErr("creating", info.Source, err)
|
||||
}
|
||||
// Then create the resource and skip the three-way merge
|
||||
|
@ -139,7 +142,7 @@ func RunApply(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *Ap
|
|||
}
|
||||
|
||||
// Serialize the current configuration of the object from the server.
|
||||
current, err := info.Mapping.Codec.Encode(info.Object)
|
||||
current, err := runtime.Encode(encoder, info.Object)
|
||||
if err != nil {
|
||||
return cmdutil.AddSourceToErr(fmt.Sprintf("serializing current configuration from:\n%v\nfor:", info), info.Source, err)
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ func RunAutoscale(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []
|
|||
}
|
||||
|
||||
mapper, typer := f.Object()
|
||||
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
|
||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
ContinueOnError().
|
||||
NamespaceParam(namespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, filenames...).
|
||||
|
@ -129,7 +129,12 @@ func RunAutoscale(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []
|
|||
return err
|
||||
}
|
||||
|
||||
resourceMapper := &resource.Mapper{ObjectTyper: typer, RESTMapper: mapper, ClientMapper: f.ClientMapperForCommand()}
|
||||
resourceMapper := &resource.Mapper{
|
||||
ObjectTyper: typer,
|
||||
RESTMapper: mapper,
|
||||
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
|
||||
Decoder: f.Decoder(true),
|
||||
}
|
||||
hpa, err := resourceMapper.InfoForObject(object)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -139,7 +144,7 @@ func RunAutoscale(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []
|
|||
return f.PrintObject(cmd, object, out)
|
||||
}
|
||||
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), hpa); err != nil {
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), hpa, f.JSONEncoder()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -45,25 +45,25 @@ func NewCmdClusterInfo(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||
return cmd
|
||||
}
|
||||
|
||||
func RunClusterInfo(factory *cmdutil.Factory, out io.Writer, cmd *cobra.Command) error {
|
||||
func RunClusterInfo(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command) error {
|
||||
if len(os.Args) > 1 && os.Args[1] == "clusterinfo" {
|
||||
printDeprecationWarning("cluster-info", "clusterinfo")
|
||||
}
|
||||
|
||||
client, err := factory.ClientConfig()
|
||||
client, err := f.ClientConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printService(out, "Kubernetes master", client.Host)
|
||||
|
||||
mapper, typer := factory.Object()
|
||||
mapper, typer := f.Object()
|
||||
cmdNamespace := cmdutil.GetFlagString(cmd, "namespace")
|
||||
if cmdNamespace == "" {
|
||||
cmdNamespace = api.NamespaceSystem
|
||||
}
|
||||
|
||||
// TODO use generalized labels once they are implemented (#341)
|
||||
b := resource.NewBuilder(mapper, typer, factory.ClientMapperForCommand()).
|
||||
b := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
SelectorParam("kubernetes.io/cluster-service=true").
|
||||
ResourceTypeOrNameArgs(false, []string{"services"}...).
|
||||
|
|
|
@ -38,6 +38,7 @@ import (
|
|||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/runtime/serializer"
|
||||
"k8s.io/kubernetes/pkg/util"
|
||||
)
|
||||
|
||||
|
@ -100,22 +101,21 @@ func versionErrIfFalse(b bool) error {
|
|||
}
|
||||
|
||||
var validVersion = testapi.Default.GroupVersion().Version
|
||||
var internalGV = unversioned.GroupVersion{Group: "apitest", Version: ""}
|
||||
var internalGV = unversioned.GroupVersion{Group: "apitest", Version: runtime.APIVersionInternal}
|
||||
var unlikelyGV = unversioned.GroupVersion{Group: "apitest", Version: "unlikelyversion"}
|
||||
var validVersionGV = unversioned.GroupVersion{Group: "apitest", Version: validVersion}
|
||||
|
||||
func newExternalScheme() (*runtime.Scheme, meta.RESTMapper, runtime.Codec) {
|
||||
scheme := runtime.NewScheme()
|
||||
scheme.AddInternalGroupVersion(internalGV)
|
||||
scheme.AddKnownTypeWithName(internalGV.WithKind("Type"), &internalType{})
|
||||
scheme.AddKnownTypeWithName(unlikelyGV.WithKind("Type"), &externalType{})
|
||||
//This tests that kubectl will not confuse the external scheme with the internal scheme, even when they accidentally have versions of the same name.
|
||||
scheme.AddKnownTypeWithName(validVersionGV.WithKind("Type"), &ExternalType2{})
|
||||
|
||||
codec := runtime.CodecFor(scheme, unlikelyGV)
|
||||
codecs := serializer.NewCodecFactory(scheme)
|
||||
codec := codecs.LegacyCodec(unlikelyGV)
|
||||
mapper := meta.NewDefaultRESTMapper([]unversioned.GroupVersion{unlikelyGV, validVersionGV}, func(version unversioned.GroupVersion) (*meta.VersionInterfaces, error) {
|
||||
return &meta.VersionInterfaces{
|
||||
Codec: runtime.CodecFor(scheme, version),
|
||||
ObjectConvertor: scheme,
|
||||
MetadataAccessor: meta.NewAccessor(),
|
||||
}, versionErrIfFalse(version == validVersionGV || version == unlikelyGV)
|
||||
|
@ -183,9 +183,15 @@ func NewTestFactory() (*cmdutil.Factory, *testFactory, runtime.Codec) {
|
|||
Object: func() (meta.RESTMapper, runtime.ObjectTyper) {
|
||||
return t.Mapper, t.Typer
|
||||
},
|
||||
RESTClient: func(*meta.RESTMapping) (resource.RESTClient, error) {
|
||||
ClientForMapping: func(*meta.RESTMapping) (resource.RESTClient, error) {
|
||||
return t.Client, t.Err
|
||||
},
|
||||
Decoder: func(bool) runtime.Decoder {
|
||||
return codec
|
||||
},
|
||||
JSONEncoder: func() runtime.Encoder {
|
||||
return codec
|
||||
},
|
||||
Describer: func(*meta.RESTMapping) (kubectl.Describer, error) {
|
||||
return t.Describer, t.Err
|
||||
},
|
||||
|
@ -209,7 +215,7 @@ func NewMixedFactory(apiClient resource.RESTClient) (*cmdutil.Factory, *testFact
|
|||
f.Object = func() (meta.RESTMapper, runtime.ObjectTyper) {
|
||||
return meta.MultiRESTMapper{t.Mapper, testapi.Default.RESTMapper()}, runtime.MultiObjectTyper{t.Typer, api.Scheme}
|
||||
}
|
||||
f.RESTClient = func(m *meta.RESTMapping) (resource.RESTClient, error) {
|
||||
f.ClientForMapping = func(m *meta.RESTMapping) (resource.RESTClient, error) {
|
||||
if m.ObjectConvertor == api.Scheme {
|
||||
return apiClient, t.Err
|
||||
}
|
||||
|
@ -235,9 +241,15 @@ func NewAPIFactory() (*cmdutil.Factory, *testFactory, runtime.Codec) {
|
|||
c.ExtensionsClient.Client = fakeClient.Client
|
||||
return c, t.Err
|
||||
},
|
||||
RESTClient: func(*meta.RESTMapping) (resource.RESTClient, error) {
|
||||
ClientForMapping: func(*meta.RESTMapping) (resource.RESTClient, error) {
|
||||
return t.Client, t.Err
|
||||
},
|
||||
Decoder: func(bool) runtime.Decoder {
|
||||
return testapi.Default.Codec()
|
||||
},
|
||||
JSONEncoder: func() runtime.Encoder {
|
||||
return testapi.Default.Codec()
|
||||
},
|
||||
Describer: func(*meta.RESTMapping) (kubectl.Describer, error) {
|
||||
return t.Describer, t.Err
|
||||
},
|
||||
|
@ -303,7 +315,7 @@ func stringBody(body string) io.ReadCloser {
|
|||
// mapping := &meta.RESTMapping{
|
||||
// APIVersion: version,
|
||||
// }
|
||||
// c, err := f.RESTClient(mapping)
|
||||
// c, err := f.ClientForMapping(mapping)
|
||||
// if err != nil {
|
||||
// t.Errorf("unexpected error: %v", err)
|
||||
// }
|
||||
|
|
|
@ -26,6 +26,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
@ -87,6 +88,7 @@ type ConvertOptions struct {
|
|||
filenames []string
|
||||
local bool
|
||||
|
||||
encoder runtime.Encoder
|
||||
out io.Writer
|
||||
printer kubectl.ResourcePrinter
|
||||
|
||||
|
@ -105,11 +107,12 @@ func (o *ConvertOptions) Complete(f *cmdutil.Factory, out io.Writer, cmd *cobra.
|
|||
|
||||
// build the builder
|
||||
mapper, typer := f.Object()
|
||||
clientMapper := resource.ClientMapperFunc(f.ClientForMapping)
|
||||
if o.local {
|
||||
fmt.Fprintln(out, "running in local mode...")
|
||||
o.builder = resource.NewBuilder(mapper, typer, f.NilClientMapperForCommand())
|
||||
o.builder = resource.NewBuilder(mapper, typer, resource.DisabledClientForMapping{clientMapper}, f.Decoder(true))
|
||||
} else {
|
||||
o.builder = resource.NewBuilder(mapper, typer, f.ClientMapperForCommand())
|
||||
o.builder = resource.NewBuilder(mapper, typer, clientMapper, f.Decoder(true))
|
||||
schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate"), cmdutil.GetFlagString(cmd, "schema-cache-dir"))
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -136,6 +139,7 @@ func (o *ConvertOptions) Complete(f *cmdutil.Factory, out io.Writer, cmd *cobra.
|
|||
outputFormat = "template"
|
||||
}
|
||||
}
|
||||
o.encoder = f.JSONEncoder()
|
||||
o.printer, _, err = kubectl.GetPrinter(outputFormat, templateFile)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -151,7 +155,7 @@ func (o *ConvertOptions) RunConvert() error {
|
|||
return err
|
||||
}
|
||||
|
||||
objects, err := resource.AsVersionedObject(infos, false, o.outputVersion.String())
|
||||
objects, err := resource.AsVersionedObject(infos, false, o.outputVersion.String(), o.encoder)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -99,7 +99,7 @@ func RunCreate(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *C
|
|||
}
|
||||
|
||||
mapper, typer := f.Object()
|
||||
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
|
||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
Schema(schema).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
|
@ -116,7 +116,7 @@ func RunCreate(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *C
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info); err != nil {
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, f.JSONEncoder()); err != nil {
|
||||
return cmdutil.AddSourceToErr("creating", info.Source, err)
|
||||
}
|
||||
|
||||
|
@ -218,16 +218,20 @@ func RunCreateSubcommand(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer,
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client, err := f.RESTClient(mapping)
|
||||
client, err := f.ClientForMapping(mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resourceMapper := &resource.Mapper{ObjectTyper: typer, RESTMapper: mapper, ClientMapper: f.ClientMapperForCommand()}
|
||||
resourceMapper := &resource.Mapper{
|
||||
ObjectTyper: typer,
|
||||
RESTMapper: mapper,
|
||||
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
|
||||
}
|
||||
info, err := resourceMapper.InfoForObject(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := kubectl.UpdateApplyAnnotation(info); err != nil {
|
||||
if err := kubectl.UpdateApplyAnnotation(info, f.JSONEncoder()); err != nil {
|
||||
return err
|
||||
}
|
||||
if !options.DryRun {
|
||||
|
|
|
@ -108,7 +108,7 @@ func RunDelete(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str
|
|||
}
|
||||
deleteAll := cmdutil.GetFlagBool(cmd, "all")
|
||||
mapper, typer := f.Object()
|
||||
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
|
||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, options.Filenames...).
|
||||
|
|
|
@ -106,7 +106,7 @@ func RunDescribe(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []s
|
|||
}
|
||||
|
||||
mapper, typer := f.Object()
|
||||
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
|
||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, options.Filenames...).
|
||||
|
@ -147,7 +147,7 @@ func RunDescribe(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []s
|
|||
}
|
||||
|
||||
func DescribeMatchingResources(mapper meta.RESTMapper, typer runtime.ObjectTyper, f *cmdutil.Factory, namespace, rsrc, prefix string, out io.Writer, originalError error) error {
|
||||
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
|
||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
NamespaceParam(namespace).DefaultNamespace().
|
||||
ResourceTypeOrNameArgs(true, rsrc).
|
||||
SingleResourceType().
|
||||
|
|
|
@ -209,8 +209,7 @@ func (o *DrainOptions) getPodsForDeletion() ([]api.Pod, error) {
|
|||
if found {
|
||||
// Now verify that the specified creator actually exists.
|
||||
var sr api.SerializedReference
|
||||
err := api.Scheme.DecodeInto([]byte(creatorRef), &sr)
|
||||
if err != nil {
|
||||
if err := runtime.DecodeInto(o.factory.Decoder(true), []byte(creatorRef), &sr); err != nil {
|
||||
return pods, err
|
||||
}
|
||||
if sr.Reference.Kind == "ReplicationController" {
|
||||
|
|
|
@ -23,7 +23,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
gruntime "runtime"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
|
@ -34,6 +34,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/editor"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/jsonmerge"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/util"
|
||||
"k8s.io/kubernetes/pkg/util/strategicpatch"
|
||||
"k8s.io/kubernetes/pkg/util/yaml"
|
||||
|
@ -94,7 +95,7 @@ func NewCmdEdit(f *cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||
kubectl.AddJsonFilenameFlag(cmd, &filenames, usage)
|
||||
cmd.Flags().StringP("output", "o", "yaml", "Output format. One of: yaml|json.")
|
||||
cmd.Flags().String("output-version", "", "Output the formatted object with the given version (default api-version).")
|
||||
cmd.Flags().Bool("windows-line-endings", runtime.GOOS == "windows", "Use Windows line-endings (default Unix line-endings)")
|
||||
cmd.Flags().Bool("windows-line-endings", gruntime.GOOS == "windows", "Use Windows line-endings (default Unix line-endings)")
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
@ -119,13 +120,14 @@ func RunEdit(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
|
|||
}
|
||||
|
||||
mapper, typer := f.Object()
|
||||
rmap := &resource.Mapper{
|
||||
resourceMapper := &resource.Mapper{
|
||||
ObjectTyper: typer,
|
||||
RESTMapper: mapper,
|
||||
ClientMapper: f.ClientMapperForCommand(),
|
||||
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
|
||||
Decoder: f.Decoder(true),
|
||||
}
|
||||
|
||||
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
|
||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, filenames...).
|
||||
ResourceTypeOrNameArgs(true, args...).
|
||||
|
@ -147,6 +149,8 @@ func RunEdit(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
|
|||
return err
|
||||
}
|
||||
|
||||
encoder := f.JSONEncoder()
|
||||
|
||||
windowsLineEndings := cmdutil.GetFlagBool(cmd, "windows-line-endings")
|
||||
edit := editor.NewDefaultEditor(f.EditorEnvs())
|
||||
defaultVersion, err := cmdutil.OutputVersion(cmd, clientConfig.GroupVersion)
|
||||
|
@ -155,7 +159,7 @@ func RunEdit(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
|
|||
}
|
||||
results := editResults{}
|
||||
for {
|
||||
objs, err := resource.AsVersionedObjects(infos, defaultVersion.String())
|
||||
objs, err := resource.AsVersionedObjects(infos, defaultVersion.String(), encoder)
|
||||
if err != nil {
|
||||
return preservedFile(err, results.file, out)
|
||||
}
|
||||
|
@ -219,21 +223,21 @@ func RunEdit(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
|
|||
}
|
||||
|
||||
// parse the edited file
|
||||
updates, err := rmap.InfoForData(edited, "edited-file")
|
||||
updates, err := resourceMapper.InfoForData(edited, "edited-file")
|
||||
if err != nil {
|
||||
return fmt.Errorf("The edited file had a syntax error: %v", err)
|
||||
}
|
||||
|
||||
// put configuration annotation in "updates"
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), updates); err != nil {
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), updates, encoder); err != nil {
|
||||
return preservedFile(err, file, out)
|
||||
}
|
||||
// encode updates back to "edited" since we'll only generate patch from "edited"
|
||||
if edited, err = updates.Mapping.Codec.Encode(updates.Object); err != nil {
|
||||
if edited, err = runtime.Encode(encoder, updates.Object); err != nil {
|
||||
return preservedFile(err, file, out)
|
||||
}
|
||||
|
||||
visitor := resource.NewFlattenListVisitor(updates, rmap)
|
||||
visitor := resource.NewFlattenListVisitor(updates, resourceMapper)
|
||||
|
||||
// need to make sure the original namespace wasn't changed while editing
|
||||
if err = visitor.Visit(resource.RequireNamespace(cmdNamespace)); err != nil {
|
||||
|
|
|
@ -26,6 +26,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/validation"
|
||||
)
|
||||
|
||||
|
@ -104,7 +105,7 @@ func RunExpose(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str
|
|||
}
|
||||
|
||||
mapper, typer := f.Object()
|
||||
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
|
||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
ContinueOnError().
|
||||
NamespaceParam(namespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, options.Filenames...).
|
||||
|
@ -192,13 +193,19 @@ func RunExpose(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str
|
|||
}
|
||||
|
||||
if inline := cmdutil.GetFlagString(cmd, "overrides"); len(inline) > 0 {
|
||||
object, err = cmdutil.Merge(object, inline, mapping.GroupVersionKind.Kind)
|
||||
codec := runtime.NewCodec(f.JSONEncoder(), f.Decoder(true))
|
||||
object, err = cmdutil.Merge(codec, object, inline, mapping.GroupVersionKind.Kind)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
resourceMapper := &resource.Mapper{ObjectTyper: typer, RESTMapper: mapper, ClientMapper: f.ClientMapperForCommand()}
|
||||
resourceMapper := &resource.Mapper{
|
||||
ObjectTyper: typer,
|
||||
RESTMapper: mapper,
|
||||
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
|
||||
Decoder: f.Decoder(true),
|
||||
}
|
||||
info, err = resourceMapper.InfoForObject(object)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -207,7 +214,7 @@ func RunExpose(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str
|
|||
if cmdutil.GetFlagBool(cmd, "dry-run") {
|
||||
return f.PrintObject(cmd, object, out)
|
||||
}
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info); err != nil {
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, f.JSONEncoder()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -137,7 +137,7 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string
|
|||
// handle watch separately since we cannot watch multiple resource types
|
||||
isWatch, isWatchOnly := cmdutil.GetFlagBool(cmd, "watch"), cmdutil.GetFlagBool(cmd, "watch-only")
|
||||
if isWatch || isWatchOnly {
|
||||
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
|
||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
|
||||
FilenameParam(enforceNamespace, options.Filenames...).
|
||||
SelectorParam(selector).
|
||||
|
@ -192,7 +192,7 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string
|
|||
return nil
|
||||
}
|
||||
|
||||
b := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
|
||||
b := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
|
||||
FilenameParam(enforceNamespace, options.Filenames...).
|
||||
SelectorParam(selector).
|
||||
|
@ -224,7 +224,7 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
obj, err := resource.AsVersionedObject(infos, !singular, version.String())
|
||||
obj, err := resource.AsVersionedObject(infos, !singular, version.String(), f.JSONEncoder())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -244,7 +244,8 @@ func RunGet(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string
|
|||
sorting, err := cmd.Flags().GetString("sort-by")
|
||||
var sorter *kubectl.RuntimeSort
|
||||
if err == nil && len(sorting) > 0 {
|
||||
if sorter, err = kubectl.SortObjects(objs, sorting); err != nil {
|
||||
// TODO: questionable
|
||||
if sorter, err = kubectl.SortObjects(f.Decoder(true), objs, sorting); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -177,7 +177,7 @@ func TestGetUnknownSchemaObjectListGeneric(t *testing.T) {
|
|||
},
|
||||
}
|
||||
for k, test := range testCases {
|
||||
apiCodec := runtime.CodecFor(api.Scheme, *testapi.Default.GroupVersion())
|
||||
apiCodec := testapi.Default.Codec()
|
||||
regularClient := &fake.RESTClient{
|
||||
Codec: apiCodec,
|
||||
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
|
||||
|
@ -482,7 +482,7 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if errs := runtime.DecodeList(list, api.Scheme); len(errs) > 0 {
|
||||
if errs := runtime.DecodeList(list, codec); len(errs) > 0 {
|
||||
t.Fatalf("unexpected error: %v", errs)
|
||||
}
|
||||
if err := meta.SetList(out, list); err != nil {
|
||||
|
|
|
@ -201,7 +201,7 @@ func RunLabel(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
|
|||
return cmdutil.UsageError(cmd, err.Error())
|
||||
}
|
||||
mapper, typer := f.Object()
|
||||
b := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
|
||||
b := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, options.Filenames...).
|
||||
|
@ -264,7 +264,7 @@ func RunLabel(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
|
|||
}
|
||||
|
||||
mapping := info.ResourceMapping()
|
||||
client, err := f.RESTClient(mapping)
|
||||
client, err := f.ClientForMapping(mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ type LogsOptions struct {
|
|||
Mapper meta.RESTMapper
|
||||
Typer runtime.ObjectTyper
|
||||
ClientMapper resource.ClientMapper
|
||||
Decoder runtime.Decoder
|
||||
|
||||
LogsForObject func(object, options runtime.Object) (*client.Request, error)
|
||||
|
||||
|
@ -151,7 +152,8 @@ func (o *LogsOptions) Complete(f *cmdutil.Factory, out io.Writer, cmd *cobra.Com
|
|||
o.Options = logOptions
|
||||
|
||||
o.Mapper, o.Typer = f.Object()
|
||||
o.ClientMapper = f.ClientMapperForCommand()
|
||||
o.Decoder = f.Decoder(true)
|
||||
o.ClientMapper = resource.ClientMapperFunc(f.ClientForMapping)
|
||||
o.LogsForObject = f.LogsForObject
|
||||
|
||||
o.Out = out
|
||||
|
@ -176,7 +178,7 @@ func (o LogsOptions) Validate() error {
|
|||
|
||||
// RunLogs retrieves a pod log
|
||||
func (o LogsOptions) RunLogs() (int64, error) {
|
||||
infos, err := resource.NewBuilder(o.Mapper, o.Typer, o.ClientMapper).
|
||||
infos, err := resource.NewBuilder(o.Mapper, o.Typer, o.ClientMapper, o.Decoder).
|
||||
NamespaceParam(o.Namespace).DefaultNamespace().
|
||||
ResourceNames("pods", o.ResourceArg).
|
||||
SingleResourceType().
|
||||
|
|
|
@ -92,7 +92,7 @@ func RunPatch(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
|
|||
}
|
||||
|
||||
mapper, typer := f.Object()
|
||||
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
|
||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, options.Filenames...).
|
||||
|
@ -114,7 +114,7 @@ func RunPatch(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
|
|||
info := infos[0]
|
||||
name, namespace := info.Name, info.Namespace
|
||||
mapping := info.ResourceMapping()
|
||||
client, err := f.RESTClient(mapping)
|
||||
client, err := f.ClientForMapping(mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ func RunReplace(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []st
|
|||
}
|
||||
|
||||
mapper, typer := f.Object()
|
||||
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
|
||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
Schema(schema).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
|
@ -129,7 +129,7 @@ func RunReplace(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []st
|
|||
return err
|
||||
}
|
||||
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info); err != nil {
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, f.JSONEncoder()); err != nil {
|
||||
return cmdutil.AddSourceToErr("replacing", info.Source, err)
|
||||
}
|
||||
|
||||
|
@ -174,7 +174,7 @@ func forceReplace(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []
|
|||
}
|
||||
|
||||
mapper, typer := f.Object()
|
||||
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
|
||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, options.Filenames...).
|
||||
|
@ -198,7 +198,7 @@ func forceReplace(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []
|
|||
return err
|
||||
}
|
||||
|
||||
r = resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
|
||||
r = resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
Schema(schema).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
|
@ -216,7 +216,7 @@ func forceReplace(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []
|
|||
return err
|
||||
}
|
||||
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info); err != nil {
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, f.JSONEncoder()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ import (
|
|||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
|
@ -198,7 +197,7 @@ func RunRollingUpdate(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, arg
|
|||
return err
|
||||
}
|
||||
|
||||
request := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
|
||||
request := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
Schema(schema).
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, filename).
|
||||
|
@ -385,12 +384,9 @@ func isReplicasDefaulted(info *resource.Info) bool {
|
|||
// was unable to recover versioned info
|
||||
return false
|
||||
}
|
||||
|
||||
switch info.Mapping.GroupVersionKind.GroupVersion() {
|
||||
case unversioned.GroupVersion{Version: "v1"}:
|
||||
if rc, ok := info.VersionedObject.(*v1.ReplicationController); ok {
|
||||
return rc.Spec.Replicas == nil
|
||||
}
|
||||
switch t := info.VersionedObject.(type) {
|
||||
case *v1.ReplicationController:
|
||||
return t.Spec.Replicas == nil
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -236,7 +236,7 @@ func Run(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cob
|
|||
return err
|
||||
}
|
||||
_, typer := f.Object()
|
||||
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
|
||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
ContinueOnError().
|
||||
NamespaceParam(namespace).DefaultNamespace().
|
||||
ResourceNames(mapping.Resource, name).
|
||||
|
@ -409,7 +409,8 @@ func createGeneratedObject(f *cmdutil.Factory, cmd *cobra.Command, generator kub
|
|||
}
|
||||
|
||||
if len(overrides) > 0 {
|
||||
obj, err = cmdutil.Merge(obj, overrides, groupVersionKind.Kind)
|
||||
codec := runtime.NewCodec(f.JSONEncoder(), f.Decoder(true))
|
||||
obj, err = cmdutil.Merge(codec, obj, overrides, groupVersionKind.Kind)
|
||||
if err != nil {
|
||||
return nil, "", nil, nil, err
|
||||
}
|
||||
|
@ -419,20 +420,25 @@ func createGeneratedObject(f *cmdutil.Factory, cmd *cobra.Command, generator kub
|
|||
if err != nil {
|
||||
return nil, "", nil, nil, err
|
||||
}
|
||||
client, err := f.RESTClient(mapping)
|
||||
client, err := f.ClientForMapping(mapping)
|
||||
if err != nil {
|
||||
return nil, "", nil, nil, err
|
||||
}
|
||||
|
||||
// TODO: extract this flag to a central location, when such a location exists.
|
||||
if !cmdutil.GetFlagBool(cmd, "dry-run") {
|
||||
resourceMapper := &resource.Mapper{ObjectTyper: typer, RESTMapper: mapper, ClientMapper: f.ClientMapperForCommand()}
|
||||
resourceMapper := &resource.Mapper{
|
||||
ObjectTyper: typer,
|
||||
RESTMapper: mapper,
|
||||
ClientMapper: resource.ClientMapperFunc(f.ClientForMapping),
|
||||
Decoder: f.Decoder(true),
|
||||
}
|
||||
info, err := resourceMapper.InfoForObject(obj)
|
||||
if err != nil {
|
||||
return nil, "", nil, nil, err
|
||||
}
|
||||
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info); err != nil {
|
||||
if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, f.JSONEncoder()); err != nil {
|
||||
return nil, "", nil, nil, err
|
||||
}
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ func RunScale(f *cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
|
|||
}
|
||||
|
||||
mapper, typer := f.Object()
|
||||
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
|
||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, options.Filenames...).
|
||||
|
|
|
@ -85,7 +85,7 @@ func RunStop(f *cmdutil.Factory, cmd *cobra.Command, args []string, out io.Write
|
|||
}
|
||||
|
||||
mapper, typer := f.Object()
|
||||
r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()).
|
||||
r := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true)).
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
ResourceTypeOrNameArgs(false, args...).
|
||||
|
|
|
@ -45,6 +45,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/labels"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/runtime/serializer/json"
|
||||
"k8s.io/kubernetes/pkg/util"
|
||||
)
|
||||
|
||||
|
@ -63,13 +64,19 @@ type Factory struct {
|
|||
|
||||
// Returns interfaces for dealing with arbitrary runtime.Objects.
|
||||
Object func() (meta.RESTMapper, runtime.ObjectTyper)
|
||||
// Returns interfaces for decoding objects - if toInternal is set, decoded objects will be converted
|
||||
// into their internal form (if possible). Eventually the internal form will be removed as an option,
|
||||
// and only versioned objects will be returned.
|
||||
Decoder func(toInternal bool) runtime.Decoder
|
||||
// Returns an encoder capable of encoding a provided object into JSON in the default desired version.
|
||||
JSONEncoder func() runtime.Encoder
|
||||
// Returns a client for accessing Kubernetes resources or an error.
|
||||
Client func() (*client.Client, error)
|
||||
// Returns a client.Config for accessing the Kubernetes server.
|
||||
ClientConfig func() (*client.Config, error)
|
||||
// Returns a RESTClient for working with the specified RESTMapping or an error. This is intended
|
||||
// for working with arbitrary resources and is not guaranteed to point to a Kubernetes APIServer.
|
||||
RESTClient func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||
ClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||
// Returns a Describer for displaying the specified RESTMapping type or an error.
|
||||
Describer func(mapping *meta.RESTMapping) (kubectl.Describer, error)
|
||||
// Returns a Printer for formatting objects of the given type or an error.
|
||||
|
@ -185,7 +192,7 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
|
|||
ClientConfig: func() (*client.Config, error) {
|
||||
return clients.ClientConfigForVersion(nil)
|
||||
},
|
||||
RESTClient: func(mapping *meta.RESTMapping) (resource.RESTClient, error) {
|
||||
ClientForMapping: func(mapping *meta.RESTMapping) (resource.RESTClient, error) {
|
||||
mappingVersion := mapping.GroupVersionKind.GroupVersion()
|
||||
client, err := clients.ClientForVersion(&mappingVersion)
|
||||
if err != nil {
|
||||
|
@ -210,6 +217,15 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
|
|||
}
|
||||
return nil, fmt.Errorf("no description has been implemented for %q", mapping.GroupVersionKind.Kind)
|
||||
},
|
||||
Decoder: func(toInternal bool) runtime.Decoder {
|
||||
if toInternal {
|
||||
return api.Codecs.UniversalDecoder()
|
||||
}
|
||||
return api.Codecs.UniversalDeserializer()
|
||||
},
|
||||
JSONEncoder: func() runtime.Encoder {
|
||||
return api.Codecs.LegacyCodec(registered.EnabledVersions()...)
|
||||
},
|
||||
Printer: func(mapping *meta.RESTMapping, noHeaders, withNamespace bool, wide bool, showAll bool, absoluteTimestamps bool, columnLabels []string) (kubectl.ResourcePrinter, error) {
|
||||
return kubectl.NewHumanReadablePrinter(noHeaders, withNamespace, wide, showAll, absoluteTimestamps, columnLabels), nil
|
||||
},
|
||||
|
@ -531,7 +547,7 @@ func getSchemaAndValidate(c schemaClient, data []byte, prefix, groupVersion, cac
|
|||
}
|
||||
|
||||
func (c *clientSwaggerSchema) ValidateBytes(data []byte) error {
|
||||
gvk, err := runtime.UnstructuredJSONScheme.DataKind(data)
|
||||
gvk, err := json.DefaultMetaFactory.Interpret(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -663,24 +679,9 @@ func (f *Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMappin
|
|||
return printer, nil
|
||||
}
|
||||
|
||||
// ClientMapperForCommand returns a ClientMapper for the factory.
|
||||
func (f *Factory) ClientMapperForCommand() resource.ClientMapper {
|
||||
return resource.ClientMapperFunc(func(mapping *meta.RESTMapping) (resource.RESTClient, error) {
|
||||
return f.RESTClient(mapping)
|
||||
})
|
||||
}
|
||||
|
||||
// NilClientMapperForCommand returns a ClientMapper which always returns nil.
|
||||
// When command is running locally and client isn't needed, this mapper can be parsed to NewBuilder.
|
||||
func (f *Factory) NilClientMapperForCommand() resource.ClientMapper {
|
||||
return resource.ClientMapperFunc(func(mapping *meta.RESTMapping) (resource.RESTClient, error) {
|
||||
return nil, nil
|
||||
})
|
||||
}
|
||||
|
||||
// One stop shopping for a Builder
|
||||
func (f *Factory) NewBuilder() *resource.Builder {
|
||||
mapper, typer := f.Object()
|
||||
|
||||
return resource.NewBuilder(mapper, typer, f.ClientMapperForCommand())
|
||||
return resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), f.Decoder(true))
|
||||
}
|
||||
|
|
|
@ -245,7 +245,7 @@ func TestValidateCachesSchema(t *testing.T) {
|
|||
os.RemoveAll(dir)
|
||||
|
||||
obj := &api.Pod{}
|
||||
data, err := testapi.Default.Codec().Encode(obj)
|
||||
data, err := runtime.Encode(testapi.Default.Codec(), obj)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
t.FailNow()
|
||||
|
|
|
@ -18,7 +18,6 @@ package util
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
@ -28,10 +27,8 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/errors"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
|
@ -371,38 +368,11 @@ func ReadConfigDataFromLocation(location string) ([]byte, error) {
|
|||
}
|
||||
}
|
||||
|
||||
func Merge(dst runtime.Object, fragment, kind string) (runtime.Object, error) {
|
||||
// Ok, this is a little hairy, we'd rather not force the user to specify a kind for their JSON
|
||||
// So we pull it into a map, add the Kind field, and then reserialize.
|
||||
// We also pull the apiVersion for proper parsing
|
||||
var intermediate interface{}
|
||||
if err := json.Unmarshal([]byte(fragment), &intermediate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dataMap, ok := intermediate.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Expected a map, found something else: %s", fragment)
|
||||
}
|
||||
version, found := dataMap["apiVersion"]
|
||||
if !found {
|
||||
return nil, fmt.Errorf("Inline JSON requires an apiVersion field")
|
||||
}
|
||||
versionString, ok := version.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("apiVersion must be a string")
|
||||
}
|
||||
groupVersion, err := unversioned.ParseGroupVersion(versionString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
i, err := registered.GroupOrDie(api.GroupName).InterfacesFor(groupVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Merge requires JSON serialization
|
||||
// TODO: merge assumes JSON serialization, and does not properly abstract API retrieval
|
||||
func Merge(codec runtime.Codec, dst runtime.Object, fragment, kind string) (runtime.Object, error) {
|
||||
// encode dst into versioned json and apply fragment directly too it
|
||||
target, err := i.Codec.Encode(dst)
|
||||
target, err := runtime.Encode(codec, dst)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -410,7 +380,7 @@ func Merge(dst runtime.Object, fragment, kind string) (runtime.Object, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out, err := i.Codec.Decode(patched)
|
||||
out, err := runtime.Decode(codec, patched)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -443,7 +413,7 @@ func DumpReaderToFile(reader io.Reader, filename string) error {
|
|||
}
|
||||
|
||||
// UpdateObject updates resource object with updateFn
|
||||
func UpdateObject(info *resource.Info, updateFn func(runtime.Object) error) (runtime.Object, error) {
|
||||
func UpdateObject(info *resource.Info, codec runtime.Codec, updateFn func(runtime.Object) error) (runtime.Object, error) {
|
||||
helper := resource.NewHelper(info.Client, info.Mapping)
|
||||
|
||||
if err := updateFn(info.Object); err != nil {
|
||||
|
@ -451,7 +421,7 @@ func UpdateObject(info *resource.Info, updateFn func(runtime.Object) error) (run
|
|||
}
|
||||
|
||||
// Update the annotation used by kubectl apply
|
||||
if err := kubectl.UpdateApplyAnnotation(info); err != nil {
|
||||
if err := kubectl.UpdateApplyAnnotation(info, codec); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
|
@ -183,7 +183,7 @@ func TestMerge(t *testing.T) {
|
|||
}
|
||||
|
||||
for i, test := range tests {
|
||||
out, err := Merge(test.obj, test.fragment, test.kind)
|
||||
out, err := Merge(testapi.Default.Codec(), test.obj, test.fragment, test.kind)
|
||||
if !test.expectErr {
|
||||
if err != nil {
|
||||
t.Errorf("testcase[%d], unexpected error: %v", i, err)
|
||||
|
|
|
@ -26,7 +26,6 @@ import (
|
|||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/jsonpath"
|
||||
|
@ -152,6 +151,7 @@ type Column struct {
|
|||
// of data from templates specified in the `Columns` array
|
||||
type CustomColumnsPrinter struct {
|
||||
Columns []Column
|
||||
Decoder runtime.Decoder
|
||||
}
|
||||
|
||||
func (s *CustomColumnsPrinter) PrintObj(obj runtime.Object, out io.Writer) error {
|
||||
|
@ -192,7 +192,7 @@ func (s *CustomColumnsPrinter) printOneObject(obj runtime.Object, parsers []*jso
|
|||
switch u := obj.(type) {
|
||||
case *runtime.Unknown:
|
||||
var err error
|
||||
if obj, err = api.Codec.Decode(u.RawJSON); err != nil {
|
||||
if obj, _, err = s.Decoder.Decode(u.RawJSON, nil, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,9 +80,9 @@ type resourceTuple struct {
|
|||
}
|
||||
|
||||
// NewBuilder creates a builder that operates on generic objects.
|
||||
func NewBuilder(mapper meta.RESTMapper, typer runtime.ObjectTyper, clientMapper ClientMapper) *Builder {
|
||||
func NewBuilder(mapper meta.RESTMapper, typer runtime.ObjectTyper, clientMapper ClientMapper, decoder runtime.Decoder) *Builder {
|
||||
return &Builder{
|
||||
mapper: &Mapper{typer, mapper, clientMapper},
|
||||
mapper: &Mapper{typer, mapper, clientMapper, decoder},
|
||||
requireObject: true,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/client/unversioned/fake"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
utilerrors "k8s.io/kubernetes/pkg/util/errors"
|
||||
|
@ -177,9 +178,9 @@ func (v *testVisitor) Objects() []runtime.Object {
|
|||
return objects
|
||||
}
|
||||
|
||||
func TestPathBuilder(t *testing.T) {
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient()).
|
||||
FilenameParam(false, "../../../examples/guestbook/redis-master-controller.yaml")
|
||||
func TestPathBuilderAndVersionedObjectNotDefaulted(t *testing.T) {
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
|
||||
FilenameParam(false, "../../../docs/user-guide/update-demo/kitten-rc.yaml")
|
||||
|
||||
test := &testVisitor{}
|
||||
singular := false
|
||||
|
@ -190,9 +191,14 @@ func TestPathBuilder(t *testing.T) {
|
|||
}
|
||||
|
||||
info := test.Infos[0]
|
||||
if info.Name != "redis-master" || info.Namespace != "" || info.Object == nil {
|
||||
if info.Name != "update-demo-kitten" || info.Namespace != "" || info.Object == nil {
|
||||
t.Errorf("unexpected info: %#v", info)
|
||||
}
|
||||
version, ok := info.VersionedObject.(*v1.ReplicationController)
|
||||
// versioned object does not have defaulting applied
|
||||
if info.VersionedObject == nil || !ok || version.Spec.Replicas != nil {
|
||||
t.Errorf("unexpected versioned object: %#v", info.VersionedObject)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodeBuilder(t *testing.T) {
|
||||
|
@ -212,7 +218,7 @@ func TestNodeBuilder(t *testing.T) {
|
|||
w.Write([]byte(runtime.EncodeOrDie(testapi.Default.Codec(), node)))
|
||||
}()
|
||||
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient()).
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
|
||||
NamespaceParam("test").Stream(r, "STDIN")
|
||||
|
||||
test := &testVisitor{}
|
||||
|
@ -228,7 +234,7 @@ func TestNodeBuilder(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPathBuilderWithMultiple(t *testing.T) {
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient()).
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
|
||||
FilenameParam(false, "../../../examples/guestbook/redis-master-controller.yaml").
|
||||
FilenameParam(false, "../../../examples/pod").
|
||||
NamespaceParam("test").DefaultNamespace()
|
||||
|
@ -252,7 +258,7 @@ func TestPathBuilderWithMultiple(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestDirectoryBuilder(t *testing.T) {
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient()).
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
|
||||
FilenameParam(false, "../../../examples/guestbook").
|
||||
NamespaceParam("test").DefaultNamespace()
|
||||
|
||||
|
@ -283,7 +289,7 @@ func TestNamespaceOverride(t *testing.T) {
|
|||
// TODO: Uncomment when fix #19254
|
||||
// defer s.Close()
|
||||
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient()).
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
|
||||
FilenameParam(false, s.URL).
|
||||
NamespaceParam("test")
|
||||
|
||||
|
@ -294,7 +300,7 @@ func TestNamespaceOverride(t *testing.T) {
|
|||
t.Fatalf("unexpected response: %v %#v", err, test.Infos)
|
||||
}
|
||||
|
||||
b = NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient()).
|
||||
b = NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
|
||||
FilenameParam(true, s.URL).
|
||||
NamespaceParam("test")
|
||||
|
||||
|
@ -314,7 +320,7 @@ func TestURLBuilder(t *testing.T) {
|
|||
// TODO: Uncomment when fix #19254
|
||||
// defer s.Close()
|
||||
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient()).
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
|
||||
FilenameParam(false, s.URL).
|
||||
NamespaceParam("test")
|
||||
|
||||
|
@ -339,7 +345,7 @@ func TestURLBuilderRequireNamespace(t *testing.T) {
|
|||
// TODO: Uncomment when fix #19254
|
||||
// defer s.Close()
|
||||
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient()).
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
|
||||
FilenameParam(false, s.URL).
|
||||
NamespaceParam("test").RequireNamespace()
|
||||
|
||||
|
@ -356,7 +362,7 @@ func TestResourceByName(t *testing.T) {
|
|||
pods, _ := testData()
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
|
||||
"/namespaces/test/pods/foo": runtime.EncodeOrDie(testapi.Default.Codec(), &pods.Items[0]),
|
||||
})).
|
||||
}), testapi.Default.Codec()).
|
||||
NamespaceParam("test")
|
||||
|
||||
test := &testVisitor{}
|
||||
|
@ -392,7 +398,7 @@ func TestMultipleResourceByTheSameName(t *testing.T) {
|
|||
"/namespaces/test/pods/baz": runtime.EncodeOrDie(testapi.Default.Codec(), &pods.Items[1]),
|
||||
"/namespaces/test/services/foo": runtime.EncodeOrDie(testapi.Default.Codec(), &svcs.Items[0]),
|
||||
"/namespaces/test/services/baz": runtime.EncodeOrDie(testapi.Default.Codec(), &svcs.Items[0]),
|
||||
})).
|
||||
}), testapi.Default.Codec()).
|
||||
NamespaceParam("test")
|
||||
|
||||
test := &testVisitor{}
|
||||
|
@ -422,7 +428,7 @@ func TestResourceNames(t *testing.T) {
|
|||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
|
||||
"/namespaces/test/pods/foo": runtime.EncodeOrDie(testapi.Default.Codec(), &pods.Items[0]),
|
||||
"/namespaces/test/services/baz": runtime.EncodeOrDie(testapi.Default.Codec(), &svc.Items[0]),
|
||||
})).
|
||||
}), testapi.Default.Codec()).
|
||||
NamespaceParam("test")
|
||||
|
||||
test := &testVisitor{}
|
||||
|
@ -446,7 +452,7 @@ func TestResourceNames(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestResourceByNameWithoutRequireObject(t *testing.T) {
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{})).
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{}), testapi.Default.Codec()).
|
||||
NamespaceParam("test")
|
||||
|
||||
test := &testVisitor{}
|
||||
|
@ -482,7 +488,7 @@ func TestResourceByNameAndEmptySelector(t *testing.T) {
|
|||
pods, _ := testData()
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
|
||||
"/namespaces/test/pods/foo": runtime.EncodeOrDie(testapi.Default.Codec(), &pods.Items[0]),
|
||||
})).
|
||||
}), testapi.Default.Codec()).
|
||||
NamespaceParam("test").
|
||||
SelectorParam("").
|
||||
ResourceTypeOrNameArgs(true, "pods", "foo")
|
||||
|
@ -511,7 +517,7 @@ func TestSelector(t *testing.T) {
|
|||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
|
||||
"/namespaces/test/pods?" + labelKey + "=a%3Db": runtime.EncodeOrDie(testapi.Default.Codec(), pods),
|
||||
"/namespaces/test/services?" + labelKey + "=a%3Db": runtime.EncodeOrDie(testapi.Default.Codec(), svc),
|
||||
})).
|
||||
}), testapi.Default.Codec()).
|
||||
SelectorParam("a=b").
|
||||
NamespaceParam("test").
|
||||
Flatten()
|
||||
|
@ -539,7 +545,7 @@ func TestSelector(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSelectorRequiresKnownTypes(t *testing.T) {
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient()).
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
|
||||
SelectorParam("a=b").
|
||||
NamespaceParam("test").
|
||||
ResourceTypes("unknown")
|
||||
|
@ -550,7 +556,7 @@ func TestSelectorRequiresKnownTypes(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSingleResourceType(t *testing.T) {
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient()).
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
|
||||
SelectorParam("a=b").
|
||||
SingleResourceType().
|
||||
ResourceTypeOrNameArgs(true, "pods,services")
|
||||
|
@ -620,7 +626,7 @@ func TestResourceTuple(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith(k, t, expectedRequests)).
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith(k, t, expectedRequests), testapi.Default.Codec()).
|
||||
NamespaceParam("test").DefaultNamespace().
|
||||
ResourceTypeOrNameArgs(true, testCase.args...).RequireObject(requireObject)
|
||||
|
||||
|
@ -651,7 +657,7 @@ func TestResourceTuple(t *testing.T) {
|
|||
|
||||
func TestStream(t *testing.T) {
|
||||
r, pods, rc := streamTestData()
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient()).
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
|
||||
NamespaceParam("test").Stream(r, "STDIN").Flatten()
|
||||
|
||||
test := &testVisitor{}
|
||||
|
@ -668,7 +674,7 @@ func TestStream(t *testing.T) {
|
|||
|
||||
func TestYAMLStream(t *testing.T) {
|
||||
r, pods, rc := streamYAMLTestData()
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient()).
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
|
||||
NamespaceParam("test").Stream(r, "STDIN").Flatten()
|
||||
|
||||
test := &testVisitor{}
|
||||
|
@ -685,7 +691,7 @@ func TestYAMLStream(t *testing.T) {
|
|||
|
||||
func TestMultipleObject(t *testing.T) {
|
||||
r, pods, svc := streamTestData()
|
||||
obj, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient()).
|
||||
obj, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
|
||||
NamespaceParam("test").Stream(r, "STDIN").Flatten().
|
||||
Do().Object()
|
||||
|
||||
|
@ -707,7 +713,7 @@ func TestMultipleObject(t *testing.T) {
|
|||
|
||||
func TestContinueOnErrorVisitor(t *testing.T) {
|
||||
r, _, _ := streamTestData()
|
||||
req := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient()).
|
||||
req := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
|
||||
ContinueOnError().
|
||||
NamespaceParam("test").Stream(r, "STDIN").Flatten().
|
||||
Do()
|
||||
|
@ -736,7 +742,7 @@ func TestContinueOnErrorVisitor(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSingularObject(t *testing.T) {
|
||||
obj, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient()).
|
||||
obj, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
|
||||
NamespaceParam("test").DefaultNamespace().
|
||||
FilenameParam(false, "../../../examples/guestbook/redis-master-controller.yaml").
|
||||
Flatten().
|
||||
|
@ -756,7 +762,7 @@ func TestSingularObject(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestSingularObjectNoExtension(t *testing.T) {
|
||||
obj, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient()).
|
||||
obj, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
|
||||
NamespaceParam("test").DefaultNamespace().
|
||||
FilenameParam(false, "../../../examples/pod").
|
||||
Flatten().
|
||||
|
@ -778,7 +784,7 @@ func TestSingularObjectNoExtension(t *testing.T) {
|
|||
func TestSingularRootScopedObject(t *testing.T) {
|
||||
node := &api.Node{ObjectMeta: api.ObjectMeta{Name: "test"}, Spec: api.NodeSpec{ExternalID: "test"}}
|
||||
r := streamTestObject(node)
|
||||
infos, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient()).
|
||||
infos, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
|
||||
NamespaceParam("test").DefaultNamespace().
|
||||
Stream(r, "STDIN").
|
||||
Flatten().
|
||||
|
@ -805,7 +811,7 @@ func TestListObject(t *testing.T) {
|
|||
labelKey := unversioned.LabelSelectorQueryParam(testapi.Default.GroupVersion().String())
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
|
||||
"/namespaces/test/pods?" + labelKey + "=a%3Db": runtime.EncodeOrDie(testapi.Default.Codec(), pods),
|
||||
})).
|
||||
}), testapi.Default.Codec()).
|
||||
SelectorParam("a=b").
|
||||
NamespaceParam("test").
|
||||
ResourceTypeOrNameArgs(true, "pods").
|
||||
|
@ -839,7 +845,7 @@ func TestListObjectWithDifferentVersions(t *testing.T) {
|
|||
obj, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClientWith("", t, map[string]string{
|
||||
"/namespaces/test/pods?" + labelKey + "=a%3Db": runtime.EncodeOrDie(testapi.Default.Codec(), pods),
|
||||
"/namespaces/test/services?" + labelKey + "=a%3Db": runtime.EncodeOrDie(testapi.Default.Codec(), svc),
|
||||
})).
|
||||
}), testapi.Default.Codec()).
|
||||
SelectorParam("a=b").
|
||||
NamespaceParam("test").
|
||||
ResourceTypeOrNameArgs(true, "pods,services").
|
||||
|
@ -867,7 +873,7 @@ func TestWatch(t *testing.T) {
|
|||
Type: watch.Added,
|
||||
Object: &svc.Items[0],
|
||||
}),
|
||||
})).
|
||||
}), testapi.Default.Codec()).
|
||||
NamespaceParam("test").DefaultNamespace().
|
||||
FilenameParam(false, "../../../examples/guestbook/redis-master-service.yaml").Flatten().
|
||||
Do().Watch("12")
|
||||
|
@ -894,7 +900,7 @@ func TestWatch(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestWatchMultipleError(t *testing.T) {
|
||||
_, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient()).
|
||||
_, err := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
|
||||
NamespaceParam("test").DefaultNamespace().
|
||||
FilenameParam(false, "../../../examples/guestbook/redis-master-controller.yaml").Flatten().
|
||||
FilenameParam(false, "../../../examples/guestbook/redis-master-controller.yaml").Flatten().
|
||||
|
@ -921,7 +927,7 @@ func TestLatest(t *testing.T) {
|
|||
"/namespaces/test/pods/foo": runtime.EncodeOrDie(testapi.Default.Codec(), newPod),
|
||||
"/namespaces/test/pods/bar": runtime.EncodeOrDie(testapi.Default.Codec(), newPod2),
|
||||
"/namespaces/test/services/baz": runtime.EncodeOrDie(testapi.Default.Codec(), newSvc),
|
||||
})).
|
||||
}), testapi.Default.Codec()).
|
||||
NamespaceParam("other").Stream(r, "STDIN").Flatten().Latest()
|
||||
|
||||
test := &testVisitor{}
|
||||
|
@ -953,7 +959,7 @@ func TestReceiveMultipleErrors(t *testing.T) {
|
|||
w2.Write([]byte(runtime.EncodeOrDie(testapi.Default.Codec(), &svc.Items[0])))
|
||||
}()
|
||||
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient()).
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec()).
|
||||
Stream(r, "1").Stream(r2, "2").
|
||||
ContinueOnError()
|
||||
|
||||
|
@ -997,7 +1003,7 @@ func TestReplaceAliases(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient())
|
||||
b := NewBuilder(testapi.Default.RESTMapper(), api.Scheme, fakeClient(), testapi.Default.Codec())
|
||||
|
||||
for _, test := range tests {
|
||||
replaced := b.replaceAliases(test.arg)
|
||||
|
|
|
@ -33,8 +33,6 @@ type Helper struct {
|
|||
Resource string
|
||||
// A RESTClient capable of mutating this resource.
|
||||
RESTClient RESTClient
|
||||
// A codec for decoding and encoding objects of this resource type.
|
||||
Codec runtime.Codec
|
||||
// An interface for reading or writing the resource version of this
|
||||
// type.
|
||||
Versioner runtime.ResourceVersioner
|
||||
|
@ -45,9 +43,8 @@ type Helper struct {
|
|||
// NewHelper creates a Helper from a ResourceMapping
|
||||
func NewHelper(client RESTClient, mapping *meta.RESTMapping) *Helper {
|
||||
return &Helper{
|
||||
RESTClient: client,
|
||||
Resource: mapping.Resource,
|
||||
Codec: mapping.Codec,
|
||||
RESTClient: client,
|
||||
Versioner: mapping.MetadataAccessor,
|
||||
NamespaceScoped: mapping.Scope.Name() == meta.RESTScopeNameNamespace,
|
||||
}
|
||||
|
|
|
@ -189,7 +189,6 @@ func TestHelperCreate(t *testing.T) {
|
|||
}
|
||||
modifier := &Helper{
|
||||
RESTClient: client,
|
||||
Codec: testapi.Default.Codec(),
|
||||
Versioner: testapi.Default.MetadataAccessor(),
|
||||
NamespaceScoped: true,
|
||||
}
|
||||
|
@ -441,7 +440,6 @@ func TestHelperReplace(t *testing.T) {
|
|||
}
|
||||
modifier := &Helper{
|
||||
RESTClient: client,
|
||||
Codec: testapi.Default.Codec(),
|
||||
Versioner: testapi.Default.MetadataAccessor(),
|
||||
NamespaceScoped: true,
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ type RESTClient interface {
|
|||
Put() *client.Request
|
||||
}
|
||||
|
||||
// ClientMapper retrieves a client object for a given mapping
|
||||
// ClientMapper abstracts retrieving a Client for mapped objects.
|
||||
type ClientMapper interface {
|
||||
ClientForMapping(mapping *meta.RESTMapping) (RESTClient, error)
|
||||
}
|
||||
|
|
|
@ -20,69 +20,63 @@ import (
|
|||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
"k8s.io/kubernetes/pkg/util/yaml"
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// Mapper is a convenience struct for holding references to the three interfaces
|
||||
// needed to create Info for arbitrary objects.
|
||||
type Mapper struct {
|
||||
runtime.ObjectTyper
|
||||
meta.RESTMapper
|
||||
ClientMapper
|
||||
runtime.Decoder
|
||||
}
|
||||
|
||||
// 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
|
||||
// set into Info if the mapping's MetadataAccessor can retrieve them.
|
||||
func (m *Mapper) InfoForData(data []byte, source string) (*Info, error) {
|
||||
json, err := yaml.ToJSON(data)
|
||||
versions := &runtime.VersionedObjects{}
|
||||
_, gvk, err := m.Decode(data, nil, versions)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse %q: %v", source, err)
|
||||
}
|
||||
data = json
|
||||
gvk, err := runtime.UnstructuredJSONScheme.DataKind(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to get type info from %q: %v", source, err)
|
||||
}
|
||||
if ok := registered.IsEnabledVersion(gvk.GroupVersion()); !ok {
|
||||
return nil, fmt.Errorf("API version %q in %q isn't supported, only supports API versions %q", gvk.GroupVersion().String(), source, registered.EnabledVersions())
|
||||
}
|
||||
if gvk.Kind == "" {
|
||||
return nil, fmt.Errorf("kind not set in %q", source)
|
||||
return nil, fmt.Errorf("unable to decode %q: %v", source, err)
|
||||
}
|
||||
mapping, err := m.RESTMapping(gvk.GroupKind(), gvk.Version)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to recognize %q: %v", source, err)
|
||||
}
|
||||
obj, err := mapping.Codec.Decode(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to load %q: %v", source, err)
|
||||
}
|
||||
|
||||
client, err := m.ClientForMapping(mapping)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to connect to a server to handle %q: %v", mapping.Resource, err)
|
||||
}
|
||||
|
||||
// TODO: decoding the version object is convenient, but questionable. This is used by apply
|
||||
// and rolling-update today, but both of those cases should probably be requesting the raw
|
||||
// object and performing their own decoding.
|
||||
obj, versioned := versions.Last(), versions.First()
|
||||
name, _ := mapping.MetadataAccessor.Name(obj)
|
||||
namespace, _ := mapping.MetadataAccessor.Namespace(obj)
|
||||
resourceVersion, _ := mapping.MetadataAccessor.ResourceVersion(obj)
|
||||
|
||||
var versionedObject interface{}
|
||||
|
||||
if vo, _, err := api.Scheme.Raw().DecodeToVersionedObject(data); err == nil {
|
||||
versionedObject = vo
|
||||
}
|
||||
return &Info{
|
||||
Mapping: mapping,
|
||||
Client: client,
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
Source: source,
|
||||
VersionedObject: versionedObject,
|
||||
VersionedObject: versioned,
|
||||
Object: obj,
|
||||
ResourceVersion: resourceVersion,
|
||||
}, nil
|
||||
|
|
|
@ -210,8 +210,8 @@ func (r *Result) Watch(resourceVersion string) (watch.Interface, error) {
|
|||
// the objects as children, or if only a single Object is present, as that object. The provided
|
||||
// version will be preferred as the conversion target, but the Object's mapping version will be
|
||||
// used if that version is not present.
|
||||
func AsVersionedObject(infos []*Info, forceList bool, version string) (runtime.Object, error) {
|
||||
objects, err := AsVersionedObjects(infos, version)
|
||||
func AsVersionedObject(infos []*Info, forceList bool, version string, encoder runtime.Encoder) (runtime.Object, error) {
|
||||
objects, err := AsVersionedObjects(infos, version, encoder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -233,19 +233,21 @@ func AsVersionedObject(infos []*Info, forceList bool, version string) (runtime.O
|
|||
// AsVersionedObjects converts a list of infos into versioned objects. The provided
|
||||
// version will be preferred as the conversion target, but the Object's mapping version will be
|
||||
// used if that version is not present.
|
||||
func AsVersionedObjects(infos []*Info, version string) ([]runtime.Object, error) {
|
||||
func AsVersionedObjects(infos []*Info, version string, encoder runtime.Encoder) ([]runtime.Object, error) {
|
||||
objects := []runtime.Object{}
|
||||
for _, info := range infos {
|
||||
if info.Object == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: use info.VersionedObject as the value?
|
||||
|
||||
// objects that are not part of api.Scheme must be converted to JSON
|
||||
// TODO: convert to map[string]interface{}, attach to runtime.Unknown?
|
||||
if len(version) > 0 {
|
||||
if _, err := api.Scheme.ObjectKind(info.Object); runtime.IsNotRegisteredError(err) {
|
||||
// TODO: ideally this would encode to version, but we don't expose multiple codecs here.
|
||||
data, err := info.Mapping.Codec.Encode(info.Object)
|
||||
data, err := runtime.Encode(encoder, info.Object)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -345,7 +345,7 @@ func (v FlattenListVisitor) Visit(fn VisitorFunc) error {
|
|||
if errs := runtime.DecodeList(items, struct {
|
||||
runtime.ObjectTyper
|
||||
runtime.Decoder
|
||||
}{v.Mapper, info.Mapping.Codec}); len(errs) > 0 {
|
||||
}{v.Mapper, v.Mapper.Decoder}); len(errs) > 0 {
|
||||
return utilerrors.NewAggregate(errs)
|
||||
}
|
||||
for i := range items {
|
||||
|
|
|
@ -33,7 +33,6 @@ import (
|
|||
"github.com/ghodss/yaml"
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/latest"
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/apis/extensions"
|
||||
|
@ -68,7 +67,7 @@ func GetPrinter(format, formatArgument string) (ResourcePrinter, bool, error) {
|
|||
case "name":
|
||||
printer = &NamePrinter{
|
||||
Typer: runtime.ObjectTyperToTyper(api.Scheme),
|
||||
Decoder: latest.Codecs.UniversalDecoder(),
|
||||
Decoder: api.Codecs.UniversalDecoder(),
|
||||
}
|
||||
case "template", "go-template":
|
||||
if len(formatArgument) == 0 {
|
||||
|
|
|
@ -27,7 +27,6 @@ import (
|
|||
"time"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/latest"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/api/v1"
|
||||
|
@ -466,7 +465,7 @@ func TestPrinters(t *testing.T) {
|
|||
"jsonpath": jsonpathPrinter,
|
||||
"name": &NamePrinter{
|
||||
Typer: runtime.ObjectTyperToTyper(api.Scheme),
|
||||
Decoder: latest.Codecs.UniversalDecoder(),
|
||||
Decoder: api.Codecs.UniversalDecoder(),
|
||||
},
|
||||
}
|
||||
objects := map[string]runtime.Object{
|
||||
|
|
|
@ -20,13 +20,13 @@ import (
|
|||
"reflect"
|
||||
"testing"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/latest"
|
||||
internal "k8s.io/kubernetes/pkg/api"
|
||||
api "k8s.io/kubernetes/pkg/api/v1"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
func encodeOrDie(obj runtime.Object) []byte {
|
||||
data, err := runtime.Encode(latest.Codecs.LegacyCodec(api.SchemeGroupVersion), obj)
|
||||
data, err := runtime.Encode(internal.Codecs.LegacyCodec(api.SchemeGroupVersion), obj)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
@ -224,7 +224,7 @@ func TestSortingPrinter(t *testing.T) {
|
|||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
sort := &SortingPrinter{SortField: test.field, Decoder: latest.Codecs.UniversalDecoder()}
|
||||
sort := &SortingPrinter{SortField: test.field, Decoder: internal.Codecs.UniversalDecoder()}
|
||||
if err := sort.sortObj(test.obj); err != nil {
|
||||
t.Errorf("unexpected error: %v (%s)", err, test.name)
|
||||
continue
|
||||
|
|
|
@ -25,7 +25,6 @@ import (
|
|||
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
"k8s.io/kubernetes/pkg/api/registered"
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
apiutil "k8s.io/kubernetes/pkg/api/util"
|
||||
"k8s.io/kubernetes/pkg/apimachinery/registered"
|
||||
|
|
Loading…
Reference in New Issue