Remove use of VersionedObject and simplify builder in generic methods

Reduce all uses of Unstructured to the simpler form, and avoid asking
for mapper or typer unless it is required. Use Typed() for places that
previously used VersionedObject, and remove paths for versioned objects
from code that is now using unstructured.
pull/6/head
Clayton Coleman 2017-11-13 23:01:51 -05:00
parent 64f56764d5
commit 5038eb2a3f
No known key found for this signature in database
GPG Key ID: 3D16906B4F1C5CB3
30 changed files with 263 additions and 393 deletions

View File

@ -72,59 +72,33 @@ func GetModifiedConfiguration(info *resource.Info, annotate bool, codec runtime.
// 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
if info.VersionedObject != nil {
// If an object was read from input, use that version.
accessor, err := meta.Accessor(info.VersionedObject)
if err != nil {
return nil, err
}
// Get the current annotations from the object.
annots := accessor.GetAnnotations()
if annots == nil {
annots = map[string]string{}
}
// Otherwise, use the server side version of the object.
accessor := info.Mapping.MetadataAccessor
// Get the current annotations from the object.
annots, err := accessor.Annotations(info.Object)
if err != nil {
return nil, err
}
original := annots[api.LastAppliedConfigAnnotation]
delete(annots, api.LastAppliedConfigAnnotation)
accessor.SetAnnotations(annots)
// TODO: this needs to be abstracted - there should be no assumption that versioned object
// can be marshalled to JSON.
modified, err = runtime.Encode(codec, info.VersionedObject)
if err != nil {
return nil, err
}
if annots == nil {
annots = map[string]string{}
}
if annotate {
annots[api.LastAppliedConfigAnnotation] = string(modified)
accessor.SetAnnotations(annots)
// TODO: this needs to be abstracted - there should be no assumption that versioned object
// can be marshalled to JSON.
modified, err = runtime.Encode(codec, info.VersionedObject)
if err != nil {
return nil, err
}
}
original := annots[api.LastAppliedConfigAnnotation]
delete(annots, api.LastAppliedConfigAnnotation)
if err := accessor.SetAnnotations(info.Object, annots); err != nil {
return nil, err
}
// Restore the object to its original condition.
annots[api.LastAppliedConfigAnnotation] = original
accessor.SetAnnotations(annots)
} else {
// Otherwise, use the server side version of the object.
accessor := info.Mapping.MetadataAccessor
// Get the current annotations from the object.
annots, err := accessor.Annotations(info.Object)
if err != nil {
return nil, err
}
modified, err = runtime.Encode(codec, info.Object)
if err != nil {
return nil, err
}
if annots == nil {
annots = map[string]string{}
}
original := annots[api.LastAppliedConfigAnnotation]
delete(annots, api.LastAppliedConfigAnnotation)
if err := accessor.SetAnnotations(info.Object, annots); err != nil {
if annotate {
annots[api.LastAppliedConfigAnnotation] = string(modified)
if err := info.Mapping.MetadataAccessor.SetAnnotations(info.Object, annots); err != nil {
return nil, err
}
@ -132,24 +106,12 @@ func GetModifiedConfiguration(info *resource.Info, annotate bool, codec runtime.
if err != nil {
return nil, err
}
}
if annotate {
annots[api.LastAppliedConfigAnnotation] = string(modified)
if err := info.Mapping.MetadataAccessor.SetAnnotations(info.Object, annots); err != nil {
return nil, err
}
modified, err = runtime.Encode(codec, info.Object)
if err != nil {
return nil, err
}
}
// Restore the object to its original condition.
annots[api.LastAppliedConfigAnnotation] = original
if err := info.Mapping.MetadataAccessor.SetAnnotations(info.Object, annots); err != nil {
return nil, err
}
// Restore the object to its original condition.
annots[api.LastAppliedConfigAnnotation] = original
if err := info.Mapping.MetadataAccessor.SetAnnotations(info.Object, annots); err != nil {
return nil, err
}
return modified, nil

View File

@ -189,28 +189,22 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro
changeCause := f.Command(cmd, false)
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
b := f.NewBuilder().
ContinueOnError().
b := f.NewBuilder()
if o.local {
b = b.Local()
} else {
b = b.Unstructured()
}
b = b.ContinueOnError().
NamespaceParam(namespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).
IncludeUninitialized(includeUninitialized).
Flatten()
if !o.local {
// call this method here, as it requires an api call
// and will cause the command to fail when there is
// no connection to a server
mapper, typer, err := f.UnstructuredObject()
if err != nil {
return err
}
b = b.LabelSelectorParam(o.selector).
Unstructured(f.UnstructuredClientForMapping, mapper, typer).
ResourceTypeOrNameArgs(o.all, o.resources...).
Latest()
} else {
b = b.Local(f.ClientForMapping)
}
r := b.Do()
@ -287,15 +281,7 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro
}
}
var mapper meta.RESTMapper
if o.local {
mapper, _ = f.Object()
} else {
mapper, _, err = f.UnstructuredObject()
if err != nil {
return err
}
}
mapper := r.Mapper().RESTMapper
if len(o.outputFormat) > 0 {
return f.PrintObject(cmd, o.local, mapper, outputObj, o.out)
}

View File

@ -198,12 +198,12 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, opti
return err
}
mapper, typer, err := f.UnstructuredObject()
if err != nil {
return err
}
if options.Prune {
mapper, _, err := f.UnstructuredObject()
if err != nil {
return err
}
options.PruneResources, err = parsePruneResources(mapper, cmdutil.GetFlagStringArray(cmd, "prune-whitelist"))
if err != nil {
return err
@ -214,7 +214,7 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, opti
// unless explicitly set --include-uninitialized=false
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, options.Prune)
r := f.NewBuilder().
Unstructured(f.UnstructuredClientForMapping, mapper, typer).
Unstructured().
Schema(schema).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
@ -223,8 +223,7 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, opti
IncludeUninitialized(includeUninitialized).
Flatten().
Do()
err = r.Err()
if err != nil {
if err := r.Err(); err != nil {
return err
}
@ -234,14 +233,13 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, opti
encoder := f.JSONEncoder()
decoder := f.Decoder(false)
mapper := r.Mapper().RESTMapper
visitedUids := sets.NewString()
visitedNamespaces := sets.NewString()
count := 0
err = r.Visit(func(info *resource.Info, err error) error {
// In this method, info.Object contains the object retrieved from the server
// and info.VersionedObject contains the object decoded from the input source.
if err != nil {
return err
}
@ -252,10 +250,7 @@ func RunApply(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, opti
// Add change-cause annotation to resource info if it should be recorded
if cmdutil.ShouldRecord(cmd, info) {
recordInObj := info.VersionedObject
if info.VersionedObject == nil {
recordInObj = info.Object
}
recordInObj := info.Object
if err := cmdutil.RecordChangeCause(recordInObj, f.Command(cmd, false)); err != nil {
glog.V(4).Infof("error recording current command: %v", err)
}

View File

@ -122,29 +122,19 @@ func (o *SetLastAppliedOptions) Complete(f cmdutil.Factory, cmd *cobra.Command)
}
func (o *SetLastAppliedOptions) Validate(f cmdutil.Factory, cmd *cobra.Command) error {
mapper, typer, err := f.UnstructuredObject()
if err != nil {
return err
}
r := f.NewBuilder().
Unstructured(f.UnstructuredClientForMapping, mapper, typer).
Unstructured().
NamespaceParam(o.Namespace).DefaultNamespace().
FilenameParam(o.EnforceNamespace, &o.FilenameOptions).
Latest().
Flatten().
Do()
err = r.Err()
if err != nil {
return err
}
err = r.Visit(func(info *resource.Info, err error) error {
err := r.Visit(func(info *resource.Info, err error) error {
if err != nil {
return err
}
patchBuf, diffBuf, patchType, err := editor.GetApplyPatch(info.VersionedObject, o.Codec)
patchBuf, diffBuf, patchType, err := editor.GetApplyPatch(info.Object, o.Codec)
if err != nil {
return err
}
@ -157,16 +147,16 @@ func (o *SetLastAppliedOptions) Validate(f cmdutil.Factory, cmd *cobra.Command)
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%v\nfrom server for:", info), info.Source, err)
}
}
oringalBuf, err := kubectl.GetOriginalConfiguration(info.Mapping, info.Object)
originalBuf, err := kubectl.GetOriginalConfiguration(info.Mapping, info.Object)
if err != nil {
return cmdutil.AddSourceToErr(fmt.Sprintf("retrieving current configuration of:\n%v\nfrom server for:", info), info.Source, err)
}
if oringalBuf == nil && !o.CreateAnnotation {
if originalBuf == nil && !o.CreateAnnotation {
return cmdutil.UsageErrorf(cmd, "no last-applied-configuration annotation found on resource: %s, to create the annotation, run the command with --create-annotation", info.Name)
}
//only add to PatchBufferList when changed
if !bytes.Equal(cmdutil.StripComments(oringalBuf), cmdutil.StripComments(diffBuf)) {
if !bytes.Equal(cmdutil.StripComments(originalBuf), cmdutil.StripComments(diffBuf)) {
p := PatchBuffer{Patch: patchBuf, PatchType: patchType}
o.PatchBufferList = append(o.PatchBufferList, p)
o.InfoList = append(o.InfoList, info)
@ -234,7 +224,7 @@ func (o *SetLastAppliedOptions) getPatch(info *resource.Info) ([]byte, []byte, e
objMap := map[string]map[string]map[string]string{}
metadataMap := map[string]map[string]string{}
annotationsMap := map[string]string{}
localFile, err := runtime.Encode(o.Codec, info.VersionedObject)
localFile, err := runtime.Encode(o.Codec, info.Object)
if err != nil {
return nil, localFile, err
}

View File

@ -1014,51 +1014,53 @@ func TestRunApplySetLastApplied(t *testing.T) {
},
}
for _, test := range tests {
f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Version: "v1"},
NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == pathRC && m == "GET":
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
case p == noAnnotationPath && m == "GET":
bodyRC := ioutil.NopCloser(bytes.NewReader(noAnnotationRC))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
case p == noExistPath && m == "GET":
return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: objBody(codec, &api.Pod{})}, nil
case p == pathRC && m == "PATCH":
checkPatchString(t, req)
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
case p == "/api/v1/namespaces/test" && m == "GET":
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &api.Namespace{})}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
}
}),
}
tf.Namespace = "test"
tf.ClientConfig = defaultClientConfig()
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
t.Run(test.name, func(t *testing.T) {
f, tf, codec, _ := cmdtesting.NewAPIFactory()
tf.Printer = &testPrinter{}
tf.UnstructuredClient = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Version: "v1"},
NegotiatedSerializer: unstructuredSerializer,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
switch p, m := req.URL.Path, req.Method; {
case p == pathRC && m == "GET":
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
case p == noAnnotationPath && m == "GET":
bodyRC := ioutil.NopCloser(bytes.NewReader(noAnnotationRC))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
case p == noExistPath && m == "GET":
return &http.Response{StatusCode: 404, Header: defaultHeader(), Body: objBody(codec, &api.Pod{})}, nil
case p == pathRC && m == "PATCH":
checkPatchString(t, req)
bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
case p == "/api/v1/namespaces/test" && m == "GET":
return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &api.Namespace{})}, nil
default:
t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
return nil, nil
}
}),
}
tf.Namespace = "test"
tf.ClientConfig = defaultClientConfig()
buf, errBuf := bytes.NewBuffer([]byte{}), bytes.NewBuffer([]byte{})
cmdutil.BehaviorOnFatal(func(str string, code int) {
if str != test.expectedErr {
t.Errorf("%s: unexpected error: %s\nexpected: %s", test.name, str, test.expectedErr)
cmdutil.BehaviorOnFatal(func(str string, code int) {
if str != test.expectedErr {
t.Errorf("%s: unexpected error: %s\nexpected: %s", test.name, str, test.expectedErr)
}
})
cmd := NewCmdApplySetLastApplied(f, buf, errBuf)
cmd.Flags().Set("filename", test.filePath)
cmd.Flags().Set("output", test.output)
cmd.Run(cmd, []string{})
if buf.String() != test.expectedOut {
t.Fatalf("%s: unexpected output: %s\nexpected: %s", test.name, buf.String(), test.expectedOut)
}
})
cmd := NewCmdApplySetLastApplied(f, buf, errBuf)
cmd.Flags().Set("filename", test.filePath)
cmd.Flags().Set("output", test.output)
cmd.Run(cmd, []string{})
if buf.String() != test.expectedOut {
t.Fatalf("%s: unexpected output: %s\nexpected: %s", test.name, buf.String(), test.expectedOut)
}
}
cmdutil.BehaviorOnFatal(func(str string, code int) {})
}

View File

@ -87,13 +87,8 @@ func (o *ViewLastAppliedOptions) Complete(f cmdutil.Factory, args []string) erro
return err
}
mapper, typer, err := f.UnstructuredObject()
if err != nil {
return err
}
r := f.NewBuilder().
Unstructured(f.UnstructuredClientForMapping, mapper, typer).
Unstructured().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).
ResourceTypeOrNameArgs(enforceNamespace, args...).

View File

@ -136,7 +136,7 @@ func (o *ConvertOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.C
}
o.builder = o.builder.Schema(schema)
} else {
o.builder = o.builder.Local(f.ClientForMapping)
o.builder = o.builder.Local()
}
cmdNamespace, _, err := f.DefaultNamespace()

View File

@ -184,13 +184,8 @@ func RunCreate(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, opt
return err
}
mapper, typer, err := f.UnstructuredObject()
if err != nil {
return err
}
r := f.NewBuilder().
Unstructured(f.UnstructuredClientForMapping, mapper, typer).
Unstructured().
Schema(schema).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
@ -205,6 +200,7 @@ func RunCreate(f cmdutil.Factory, cmd *cobra.Command, out, errOut io.Writer, opt
dryRun := cmdutil.GetFlagBool(cmd, "dry-run")
output := cmdutil.GetFlagString(cmd, "output")
mapper := r.Mapper().RESTMapper
count := 0
err = r.Visit(func(info *resource.Info, err error) error {

View File

@ -169,16 +169,9 @@ func (o *DeleteOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, args
return err
}
// Set up client based support.
mapper, typer, err := f.UnstructuredObject()
if err != nil {
return err
}
o.Mapper = mapper
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
r := f.NewBuilder().
Unstructured(f.UnstructuredClientForMapping, mapper, typer).
Unstructured().
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).
@ -193,6 +186,7 @@ func (o *DeleteOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, args
return err
}
o.Result = r
o.Mapper = r.Mapper().RESTMapper
o.f = f
// Set up writer

View File

@ -24,7 +24,6 @@ import (
"github.com/spf13/cobra"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/kubernetes/pkg/kubectl"
@ -116,16 +115,11 @@ func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, a
return cmdutil.UsageErrorf(cmd, "Required resource not specified.")
}
mapper, typer, err := f.UnstructuredObject()
if err != nil {
return err
}
// include the uninitialized objects by default
// unless user explicitly set --include-uninitialized=false
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, true)
r := f.NewBuilder().
Unstructured(f.UnstructuredClientForMapping, mapper, typer).
Unstructured().
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().AllNamespaces(allNamespaces).
FilenameParam(enforceNamespace, options).
@ -182,11 +176,7 @@ func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, a
}
func DescribeMatchingResources(f cmdutil.Factory, namespace, rsrc, prefix string, describerSettings *printers.DescriberSettings, out io.Writer, originalError error) error {
mapper, typer, err := f.UnstructuredObject()
if err != nil {
return err
}
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
r := f.NewBuilder().Unstructured().
NamespaceParam(namespace).DefaultNamespace().
ResourceTypeOrNameArgs(true, rsrc).
SingleResourceType().

View File

@ -280,7 +280,7 @@ func (obj InfoObject) toMap(data []byte) (map[string]interface{}, error) {
}
func (obj InfoObject) Local() (map[string]interface{}, error) {
data, err := runtime.Encode(obj.Encoder, obj.Info.VersionedObject)
data, err := runtime.Encode(obj.Encoder, obj.Info.Object)
if err != nil {
return nil, err
}
@ -408,24 +408,18 @@ func RunDiff(f cmdutil.Factory, diff *DiffProgram, options *DiffOptions, from, t
printer := Printer{}
mapper, typer, err := f.UnstructuredObject()
if err != nil {
return err
}
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
if err != nil {
return err
}
r := f.NewBuilder().
Unstructured(f.UnstructuredClientForMapping, mapper, typer).
Unstructured().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &options.FilenameOptions).
Flatten().
Do()
err = r.Err()
if err != nil {
if err := r.Err(); err != nil {
return err
}

View File

@ -191,7 +191,13 @@ func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
changeCause := f.Command(cmd, false)
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
b := f.NewBuilder().
b := f.NewBuilder()
if o.local {
b = b.Local()
} else {
b = b.Unstructured()
}
b = b.
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).
@ -199,20 +205,9 @@ func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
Flatten()
if !o.local {
// call this method here, as it requires an api call
// and will cause the command to fail when there is
// no connection to a server
mapper, typer, err := f.UnstructuredObject()
if err != nil {
return err
}
b = b.LabelSelectorParam(o.selector).
Unstructured(f.UnstructuredClientForMapping, mapper, typer).
ResourceTypeOrNameArgs(o.all, o.resources...).
Latest()
} else {
b = b.Local(f.ClientForMapping)
}
one := false

View File

@ -153,13 +153,8 @@ func RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
return fmt.Errorf("unable to parse %q: %v", patch, err)
}
mapper, typer, err := f.UnstructuredObject()
if err != nil {
return err
}
r := f.NewBuilder().
Unstructured(f.UnstructuredClientForMapping, mapper, typer).
Unstructured().
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &options.FilenameOptions).
@ -196,7 +191,6 @@ func RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
// Copy the resource info and update with the result of applying the user's patch
infoCopy := *info
infoCopy.Object = patchedObj
infoCopy.VersionedObject = patchedObj
if patch, patchType, err := cmdutil.ChangeResourcePatch(&infoCopy, f.Command(cmd, true)); err == nil {
if recordedObj, err := helper.Patch(info.Namespace, info.Name, patchType, patch); err != nil {
glog.V(4).Infof("error recording reason: %v", err)
@ -244,7 +238,7 @@ func RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
count++
originalObjJS, err := runtime.Encode(unstructured.UnstructuredJSONScheme, info.VersionedObject)
originalObjJS, err := runtime.Encode(unstructured.UnstructuredJSONScheme, info.Object)
if err != nil {
return err
}

View File

@ -27,7 +27,6 @@ import (
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
@ -120,24 +119,20 @@ func RunReplace(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []str
return fmt.Errorf("--timeout must have --force specified")
}
mapper, typer, err := f.UnstructuredObject()
if err != nil {
return err
}
r := f.NewBuilder().
Unstructured(f.UnstructuredClientForMapping, mapper, typer).
Unstructured().
Schema(schema).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, options).
Flatten().
Do()
err = r.Err()
if err != nil {
if err := r.Err(); err != nil {
return err
}
mapper := r.Mapper().RESTMapper
return r.Visit(func(info *resource.Info, err error) error {
if err != nil {
return err
@ -193,21 +188,19 @@ func forceReplace(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []s
}
}
mapper, typer, err := f.UnstructuredObject()
if err != nil {
return err
}
r := resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
r := f.NewBuilder().Unstructured().
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, options).
ResourceTypeOrNameArgs(false, args...).RequireObject(false).
Flatten().
Do()
err = r.Err()
if err != nil {
if err := r.Err(); err != nil {
return err
}
mapper := r.Mapper().RESTMapper
//Replace will create a resource if it doesn't exist already, so ignore not found error
ignoreNotFound := true
timeout := cmdutil.GetFlagDuration(cmd, "timeout")
@ -250,7 +243,7 @@ func forceReplace(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []s
}
r = f.NewBuilder().
Unstructured(f.UnstructuredClientForMapping, mapper, typer).
Unstructured().
Schema(schema).
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().

View File

@ -56,6 +56,7 @@ go_test(
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/json:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/streaming:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/util/diff: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",

View File

@ -395,11 +395,11 @@ func findNewName(args []string, oldRc *api.ReplicationController) string {
}
func isReplicasDefaulted(info *resource.Info) bool {
if info == nil || info.VersionedObject == nil {
if info == nil {
// was unable to recover versioned info
return false
}
switch t := info.VersionedObject.(type) {
switch t := info.AsVersioned().(type) {
case *v1.ReplicationController:
return t.Spec.Replicas == nil
}

View File

@ -19,7 +19,6 @@ go_library(
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/set",
visibility = ["//build/visible_to:pkg_kubectl_cmd_set_CONSUMERS"],
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//pkg/apis/rbac:go_default_library",
"//pkg/kubectl:go_default_library",
"//pkg/kubectl/cmd/templates:go_default_library",

View File

@ -126,14 +126,7 @@ type patchFn func(*resource.Info) ([]byte, error)
// the changes in the object. Encoder must be able to encode the info into the appropriate destination type.
// This function returns whether the mutation function made any change in the original object.
func CalculatePatch(patch *Patch, encoder runtime.Encoder, mutateFn patchFn) bool {
versioned, err := patch.Info.Mapping.ConvertToVersion(patch.Info.Object, patch.Info.Mapping.GroupVersionKind.GroupVersion())
if err != nil {
patch.Err = err
return true
}
patch.Info.VersionedObject = versioned
patch.Before, patch.Err = runtime.Encode(encoder, patch.Info.VersionedObject)
patch.Before, patch.Err = runtime.Encode(encoder, patch.Info.Object)
patch.After, patch.Err = mutateFn(patch.Info)
if patch.Err != nil {
return true
@ -142,7 +135,7 @@ func CalculatePatch(patch *Patch, encoder runtime.Encoder, mutateFn patchFn) boo
return false
}
patch.Patch, patch.Err = strategicpatch.CreateTwoWayMergePatch(patch.Before, patch.After, patch.Info.VersionedObject)
patch.Patch, patch.Err = strategicpatch.CreateTwoWayMergePatch(patch.Before, patch.After, patch.Info.Object)
return true
}

View File

@ -247,7 +247,7 @@ func (o *EnvOptions) RunEnv(f cmdutil.Factory) error {
ResourceTypeOrNameArgs(o.All, o.From).
Latest()
} else {
b = b.Local(f.ClientForMapping)
b = b.Local()
}
infos, err := b.Do().Infos()
@ -315,7 +315,7 @@ func (o *EnvOptions) RunEnv(f cmdutil.Factory) error {
ResourceTypeOrNameArgs(o.All, o.Resources...).
Latest()
} else {
b = b.Local(f.ClientForMapping)
b = b.Local()
}
o.Infos, err = b.Do().Infos()
@ -323,7 +323,8 @@ func (o *EnvOptions) RunEnv(f cmdutil.Factory) error {
return err
}
patches := CalculatePatches(o.Infos, o.Encoder, func(info *resource.Info) ([]byte, error) {
_, err := o.UpdatePodSpecForObject(info.VersionedObject, func(spec *v1.PodSpec) error {
info.Object = info.AsVersioned()
_, err := o.UpdatePodSpecForObject(info.Object, func(spec *v1.PodSpec) error {
resolutionErrorsEncountered := false
containers, _ := selectContainers(spec.Containers, o.ContainerSelector)
if len(containers) == 0 {
@ -389,7 +390,7 @@ func (o *EnvOptions) RunEnv(f cmdutil.Factory) error {
})
if err == nil {
return runtime.Encode(o.Encoder, info.VersionedObject)
return runtime.Encode(o.Encoder, info.Object)
}
return nil, err
})
@ -413,7 +414,7 @@ func (o *EnvOptions) RunEnv(f cmdutil.Factory) error {
}
if o.PrintObject != nil && (o.Local || o.DryRun) {
if err := o.PrintObject(o.Cmd, o.Local, o.Mapper, patch.Info.VersionedObject, o.Out); err != nil {
if err := o.PrintObject(o.Cmd, o.Local, o.Mapper, patch.Info.AsVersioned(), o.Out); err != nil {
return err
}
continue
@ -433,11 +434,7 @@ func (o *EnvOptions) RunEnv(f cmdutil.Factory) error {
}
if len(o.Output) > 0 {
versionedObject, err := patch.Info.Mapping.ConvertToVersion(obj, patch.Info.Mapping.GroupVersionKind.GroupVersion())
if err != nil {
return err
}
if err := o.PrintObject(o.Cmd, o.Local, o.Mapper, versionedObject, o.Out); err != nil {
if err := o.PrintObject(o.Cmd, o.Local, o.Mapper, info.AsVersioned(), o.Out); err != nil {
return err
}
continue

View File

@ -162,7 +162,7 @@ func (o *ImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st
return resource.LocalResourceError
}
builder = builder.Local(f.ClientForMapping)
builder = builder.Local()
}
o.Infos, err = builder.Do().Infos()
@ -191,7 +191,8 @@ func (o *ImageOptions) Run() error {
patches := CalculatePatches(o.Infos, o.Encoder, func(info *resource.Info) ([]byte, error) {
transformed := false
_, err := o.UpdatePodSpecForObject(info.VersionedObject, func(spec *v1.PodSpec) error {
info.Object = info.AsVersioned()
_, err := o.UpdatePodSpecForObject(info.Object, func(spec *v1.PodSpec) error {
for name, image := range o.ContainerImages {
var (
containerFound bool
@ -228,7 +229,7 @@ func (o *ImageOptions) Run() error {
return nil
})
if transformed && err == nil {
return runtime.Encode(o.Encoder, info.VersionedObject)
return runtime.Encode(o.Encoder, info.Object)
}
return nil, err
})
@ -246,7 +247,7 @@ func (o *ImageOptions) Run() error {
}
if o.PrintObject != nil && (o.Local || o.DryRun) {
if err := o.PrintObject(o.Cmd, o.Local, o.Mapper, patch.Info.VersionedObject, o.Out); err != nil {
if err := o.PrintObject(o.Cmd, o.Local, o.Mapper, patch.Info.AsVersioned(), o.Out); err != nil {
return err
}
continue
@ -272,11 +273,7 @@ func (o *ImageOptions) Run() error {
info.Refresh(obj, true)
if len(o.Output) > 0 {
versionedObject, err := patch.Info.Mapping.ConvertToVersion(obj, patch.Info.Mapping.GroupVersionKind.GroupVersion())
if err != nil {
return err
}
if err := o.PrintObject(o.Cmd, o.Local, o.Mapper, versionedObject, o.Out); err != nil {
if err := o.PrintObject(o.Cmd, o.Local, o.Mapper, info.AsVersioned(), o.Out); err != nil {
return err
}
continue

View File

@ -164,7 +164,7 @@ func (o *ResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
return resource.LocalResourceError
}
builder = builder.Local(f.ClientForMapping)
builder = builder.Local()
}
o.Infos, err = builder.Do().Infos()
@ -192,7 +192,8 @@ func (o *ResourcesOptions) Run() error {
allErrs := []error{}
patches := CalculatePatches(o.Infos, o.Encoder, func(info *resource.Info) ([]byte, error) {
transformed := false
_, err := o.UpdatePodSpecForObject(info.VersionedObject, func(spec *v1.PodSpec) error {
info.Object = info.AsVersioned()
_, err := o.UpdatePodSpecForObject(info.Object, func(spec *v1.PodSpec) error {
containers, _ := selectContainers(spec.Containers, o.ContainerSelector)
if len(containers) != 0 {
for i := range containers {
@ -217,7 +218,7 @@ func (o *ResourcesOptions) Run() error {
return nil
})
if transformed && err == nil {
return runtime.Encode(o.Encoder, info.VersionedObject)
return runtime.Encode(o.Encoder, info.Object)
}
return nil, err
})
@ -236,7 +237,7 @@ func (o *ResourcesOptions) Run() error {
}
if o.Local || cmdutil.GetDryRunFlag(o.Cmd) {
if err := o.PrintObject(o.Cmd, o.Local, o.Mapper, patch.Info.VersionedObject, o.Out); err != nil {
if err := o.PrintObject(o.Cmd, o.Local, o.Mapper, patch.Info.AsVersioned(), o.Out); err != nil {
return err
}
continue
@ -261,11 +262,7 @@ func (o *ResourcesOptions) Run() error {
shortOutput := o.Output == "name"
if len(o.Output) > 0 && !shortOutput {
versionedObject, err := patch.Info.Mapping.ConvertToVersion(obj, patch.Info.Mapping.GroupVersionKind.GroupVersion())
if err != nil {
return err
}
if err := o.PrintObject(o.Cmd, o.Local, o.Mapper, versionedObject, o.Out); err != nil {
if err := o.PrintObject(o.Cmd, o.Local, o.Mapper, info.AsVersioned(), o.Out); err != nil {
return err
}
continue

View File

@ -442,57 +442,59 @@ func TestSetResourcesRemote(t *testing.T) {
args: []string{"replicationcontroller", "nginx"},
},
}
for _, input := range inputs {
groupVersion := schema.GroupVersion{Group: input.apiGroup, Version: input.apiVersion}
testapi.Default = testapi.Groups[input.testAPIGroup]
f, tf, _, ns := cmdtesting.NewAPIFactory()
codec := scheme.Codecs.CodecForVersions(scheme.Codecs.LegacyCodec(groupVersion), scheme.Codecs.UniversalDecoder(groupVersion), groupVersion, groupVersion)
mapper, typer := f.Object()
tf.Printer = &printers.NamePrinter{Decoders: []runtime.Decoder{testapi.Default.Codec()}, Typer: typer, Mapper: mapper}
tf.Namespace = "test"
tf.CategoryExpander = categories.LegacyCategoryExpander
tf.Client = &fake.RESTClient{
GroupVersion: groupVersion,
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
resourcePath := testapi.Default.ResourcePath(input.args[0]+"s", tf.Namespace, input.args[1])
switch p, m := req.URL.Path, req.Method; {
case p == resourcePath && m == http.MethodGet:
return &http.Response{StatusCode: http.StatusOK, Header: defaultHeader(), Body: objBody(codec, input.object)}, nil
case p == resourcePath && m == http.MethodPatch:
stream, err := req.GetBody()
if err != nil {
return nil, err
for i, input := range inputs {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
groupVersion := schema.GroupVersion{Group: input.apiGroup, Version: input.apiVersion}
testapi.Default = testapi.Groups[input.testAPIGroup]
f, tf, _, ns := cmdtesting.NewAPIFactory()
codec := scheme.Codecs.CodecForVersions(scheme.Codecs.LegacyCodec(groupVersion), scheme.Codecs.UniversalDecoder(groupVersion), groupVersion, groupVersion)
mapper, typer := f.Object()
tf.Printer = &printers.NamePrinter{Decoders: []runtime.Decoder{testapi.Default.Codec()}, Typer: typer, Mapper: mapper}
tf.Namespace = "test"
tf.CategoryExpander = categories.LegacyCategoryExpander
tf.Client = &fake.RESTClient{
GroupVersion: groupVersion,
NegotiatedSerializer: ns,
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
resourcePath := testapi.Default.ResourcePath(input.args[0]+"s", tf.Namespace, input.args[1])
switch p, m := req.URL.Path, req.Method; {
case p == resourcePath && m == http.MethodGet:
return &http.Response{StatusCode: http.StatusOK, Header: defaultHeader(), Body: objBody(codec, input.object)}, nil
case p == resourcePath && m == http.MethodPatch:
stream, err := req.GetBody()
if err != nil {
return nil, err
}
bytes, err := ioutil.ReadAll(stream)
if err != nil {
return nil, err
}
assert.Contains(t, string(bytes), "200m", fmt.Sprintf("resources not updated for %#v", input.object))
return &http.Response{StatusCode: http.StatusOK, Header: defaultHeader(), Body: objBody(codec, input.object)}, nil
default:
t.Errorf("%s: unexpected request: %s %#v\n%#v", "resources", req.Method, req.URL, req)
return nil, fmt.Errorf("unexpected request")
}
bytes, err := ioutil.ReadAll(stream)
if err != nil {
return nil, err
}
assert.Contains(t, string(bytes), "200m", fmt.Sprintf("resources not updated for %#v", input.object))
return &http.Response{StatusCode: http.StatusOK, Header: defaultHeader(), Body: objBody(codec, input.object)}, nil
default:
t.Errorf("%s: unexpected request: %s %#v\n%#v", "resources", req.Method, req.URL, req)
return nil, fmt.Errorf("unexpected request")
}
}),
VersionedAPIPath: path.Join(input.apiPrefix, testapi.Default.GroupVersion().String()),
}
buf := new(bytes.Buffer)
cmd := NewCmdResources(f, buf, buf)
cmd.SetOutput(buf)
cmd.Flags().Set("output", "yaml")
opts := ResourcesOptions{
Out: buf,
Local: true,
Limits: "cpu=200m,memory=512Mi",
ContainerSelector: "*"}
err := opts.Complete(f, cmd, input.args)
if err == nil {
err = opts.Validate()
}
if err == nil {
err = opts.Run()
}
assert.NoError(t, err)
}),
VersionedAPIPath: path.Join(input.apiPrefix, testapi.Default.GroupVersion().String()),
}
buf := new(bytes.Buffer)
cmd := NewCmdResources(f, buf, buf)
cmd.SetOutput(buf)
cmd.Flags().Set("output", "yaml")
opts := ResourcesOptions{
Out: buf,
Local: true,
Limits: "cpu=200m,memory=512Mi",
ContainerSelector: "*"}
err := opts.Complete(f, cmd, input.args)
if err == nil {
err = opts.Validate()
}
if err == nil {
err = opts.Run()
}
assert.NoError(t, err)
})
}
}

View File

@ -147,7 +147,7 @@ func (o *SelectorOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [
return resource.LocalResourceError
}
o.builder = o.builder.Local(f.ClientForMapping)
o.builder = o.builder.Local()
}
o.PrintObject = func(obj runtime.Object) error {
@ -181,15 +181,12 @@ func (o *SelectorOptions) RunSelector() error {
return r.Visit(func(info *resource.Info, err error) error {
patch := &Patch{Info: info}
CalculatePatch(patch, o.encoder, func(info *resource.Info) ([]byte, error) {
versioned, err := info.Mapping.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion())
if err != nil {
return nil, err
}
patch.Info.VersionedObject = versioned
selectErr := updateSelectorForObject(info.VersionedObject, *o.selector)
versioned := info.AsVersioned()
patch.Info.Object = versioned
selectErr := updateSelectorForObject(info.Object, *o.selector)
if selectErr == nil {
return runtime.Encode(o.encoder, info.VersionedObject)
return runtime.Encode(o.encoder, info.Object)
}
return nil, selectErr
})
@ -198,7 +195,7 @@ func (o *SelectorOptions) RunSelector() error {
return patch.Err
}
if o.local || o.dryrun {
return o.PrintObject(info.VersionedObject)
return o.PrintObject(info.Object)
}
patched, err := resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, types.StrategicMergePatchType, patch.Patch)

View File

@ -138,7 +138,7 @@ func (saConfig *serviceAccountConfig) Complete(f cmdutil.Factory, cmd *cobra.Com
builder.ResourceTypeOrNameArgs(saConfig.all, resources...).
Latest()
} else {
builder = builder.Local(f.ClientForMapping)
builder = builder.Local()
}
saConfig.infos, err = builder.Do().Infos()
if err != nil {
@ -151,11 +151,12 @@ func (saConfig *serviceAccountConfig) Complete(f cmdutil.Factory, cmd *cobra.Com
func (saConfig *serviceAccountConfig) Run() error {
patchErrs := []error{}
patchFn := func(info *resource.Info) ([]byte, error) {
saConfig.updatePodSpecForObject(info.VersionedObject, func(podSpec *v1.PodSpec) error {
info.Object = info.AsVersioned()
saConfig.updatePodSpecForObject(info.Object, func(podSpec *v1.PodSpec) error {
podSpec.ServiceAccountName = saConfig.serviceAccountName
return nil
})
return runtime.Encode(saConfig.encoder, info.VersionedObject)
return runtime.Encode(saConfig.encoder, info.Object)
}
patches := CalculatePatches(saConfig.infos, saConfig.encoder, patchFn)
for _, patch := range patches {
@ -165,7 +166,7 @@ func (saConfig *serviceAccountConfig) Run() error {
continue
}
if saConfig.local || saConfig.dryRun {
if err := saConfig.PrintObject(saConfig.cmd, saConfig.local, saConfig.mapper, patch.Info.VersionedObject, saConfig.out); err != nil {
if err := saConfig.PrintObject(saConfig.cmd, saConfig.local, saConfig.mapper, patch.Info.AsVersioned(), saConfig.out); err != nil {
return err
}
continue
@ -184,11 +185,7 @@ func (saConfig *serviceAccountConfig) Run() error {
}
}
if len(saConfig.output) > 0 {
versionedObject, err := patch.Info.Mapping.ConvertToVersion(patched, patch.Info.Mapping.GroupVersionKind.GroupVersion())
if err != nil {
return err
}
if err := saConfig.PrintObject(saConfig.cmd, saConfig.local, saConfig.mapper, versionedObject, saConfig.out); err != nil {
if err := saConfig.PrintObject(saConfig.cmd, saConfig.local, saConfig.mapper, info.AsVersioned(), saConfig.out); err != nil {
return err
}
continue

View File

@ -66,32 +66,34 @@ func TestSetServiceAccountLocal(t *testing.T) {
{yaml: "../../../../test/fixtures/doc-yaml/user-guide/deployment.yaml", apiGroup: "extensions"},
}
f, tf, _, _ := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Version: "v1"},
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req)
return nil, nil
}),
}
tf.Namespace = "test"
out := new(bytes.Buffer)
cmd := NewCmdServiceAccount(f, out, out)
cmd.SetOutput(out)
cmd.Flags().Set("output", "yaml")
cmd.Flags().Set("local", "true")
for _, input := range inputs {
testapi.Default = testapi.Groups[input.apiGroup]
tf.Printer = printers.NewVersionedPrinter(&printers.YAMLPrinter{}, testapi.Default.Converter(), *testapi.Default.GroupVersion())
saConfig := serviceAccountConfig{fileNameOptions: resource.FilenameOptions{
Filenames: []string{input.yaml}},
out: out,
local: true}
err := saConfig.Complete(f, cmd, []string{serviceAccount})
assert.NoError(t, err)
err = saConfig.Run()
assert.NoError(t, err)
assert.Contains(t, out.String(), "serviceAccountName: "+serviceAccount, fmt.Sprintf("serviceaccount not updated for %s", input.yaml))
for i, input := range inputs {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
f, tf, _, _ := cmdtesting.NewAPIFactory()
tf.Client = &fake.RESTClient{
GroupVersion: schema.GroupVersion{Version: "v1"},
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req)
return nil, nil
}),
}
tf.Namespace = "test"
out := new(bytes.Buffer)
cmd := NewCmdServiceAccount(f, out, out)
cmd.SetOutput(out)
cmd.Flags().Set("output", "yaml")
cmd.Flags().Set("local", "true")
testapi.Default = testapi.Groups[input.apiGroup]
tf.Printer = printers.NewVersionedPrinter(&printers.YAMLPrinter{}, testapi.Default.Converter(), *testapi.Default.GroupVersion())
saConfig := serviceAccountConfig{fileNameOptions: resource.FilenameOptions{
Filenames: []string{input.yaml}},
out: out,
local: true}
err := saConfig.Complete(f, cmd, []string{serviceAccount})
assert.NoError(t, err)
err = saConfig.Run()
assert.NoError(t, err)
assert.Contains(t, out.String(), "serviceAccountName: "+serviceAccount, fmt.Sprintf("serviceaccount not updated for %s", input.yaml))
})
}
}

View File

@ -28,7 +28,6 @@ import (
"k8s.io/apimachinery/pkg/types"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/rbac"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
@ -126,7 +125,17 @@ func (o *SubjectOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []
}
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
builder := f.NewBuilder().
builder := f.NewBuilder()
if o.Local {
// if a --local flag was provided, and a resource was specified in the form
// <resource>/<name>, fail immediately as --local cannot query the api server
// for the specified resource.
if len(args) > 0 {
return resource.LocalResourceError
}
builder = builder.Local()
}
builder = builder.
ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &o.FilenameOptions).
@ -138,15 +147,6 @@ func (o *SubjectOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []
LabelSelectorParam(o.Selector).
ResourceTypeOrNameArgs(o.All, args...).
Latest()
} else {
// if a --local flag was provided, and a resource was specified in the form
// <resource>/<name>, fail immediately as --local cannot query the api server
// for the specified resource.
if len(args) > 0 {
return resource.LocalResourceError
}
builder = builder.Local(f.ClientForMapping)
}
o.Infos, err = builder.Do().Infos()
@ -219,9 +219,8 @@ func (o *SubjectOptions) Run(f cmdutil.Factory, fn updateSubjects) error {
transformed, err := updateSubjectForObject(info.Object, subjects, fn)
if transformed && err == nil {
// TODO: switch UpdatePodSpecForObject to work on v1.PodSpec, use info.VersionedObject, and avoid conversion completely
versionedEncoder := legacyscheme.Codecs.EncoderForVersion(o.Encoder, info.Mapping.GroupVersionKind.GroupVersion())
return runtime.Encode(versionedEncoder, info.Object)
// TODO: switch UpdatePodSpecForObject to work on v1.PodSpec
return runtime.Encode(o.Encoder, info.AsVersioned())
}
return nil, err
})
@ -256,7 +255,7 @@ func (o *SubjectOptions) Run(f cmdutil.Factory, fn updateSubjects) error {
shortOutput := o.Output == "name"
if len(o.Output) > 0 && !shortOutput {
return o.PrintObject(o.Mapper, info.Object, o.Out)
return o.PrintObject(o.Mapper, info.AsVersioned(), o.Out)
}
f.PrintSuccess(o.Mapper, shortOutput, o.Out, info.Mapping.Resource, info.Name, false, "subjects updated")
}

View File

@ -1,7 +1,7 @@
# Please edit the 'last-applied-configuration' annotations below.
# Lines beginning with a '#' will be ignored, and an empty file will abort the edit.
#
# The edited file had a syntax error: unable to get type info from the object "*unstructured.Unstructured": Object 'apiVersion' is missing in 'unstructured object has no version'
# The edited file had a syntax error: unable to get type info from the object "*unstructured.Unstructured": Object 'apiVersion' is missing in 'object has no apiVersion field'
#
apiVersion: v1
items:

View File

@ -32,6 +32,7 @@ go_library(
"//vendor/k8s.io/api/core/v1: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/unstructured: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/serializer:go_default_library",

View File

@ -107,12 +107,12 @@ func (o *EditOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, args []
if err != nil {
return err
}
mapper, typer, err := f.UnstructuredObject()
mapper, _, err := f.UnstructuredObject()
if err != nil {
return err
}
b := f.NewBuilder().Unstructured(f.UnstructuredClientForMapping, mapper, typer)
b := f.NewBuilder().Unstructured()
if o.EditMode == NormalEditMode || o.EditMode == ApplyEditMode {
// when do normal edit or apply edit we need to always retrieve the latest resource from server
b = b.ResourceTypeOrNameArgs(true, args...).Latest()
@ -132,7 +132,8 @@ func (o *EditOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, args []
o.updatedResultGetter = func(data []byte) *resource.Result {
// resource builder to read objects from edited data
return resource.NewBuilder(mapper, f.CategoryExpander(), typer, resource.ClientMapperFunc(f.UnstructuredClientForMapping), unstructured.UnstructuredJSONScheme).
return f.NewBuilder().
Unstructured().
Stream(bytes.NewReader(data), "edited-file").
IncludeUninitialized(includeUninitialized).
ContinueOnError().

View File

@ -193,6 +193,7 @@ type ObjectMappingFactory interface {
// runtime.Unstructured. This performs API calls to discover types.
UnstructuredObject() (meta.RESTMapper, runtime.ObjectTyper, error)
// Returns interface for expanding categories like `all`.
// TODO: this should probably return an error if the full expander can't be loaded.
CategoryExpander() categories.CategoryExpander
// Returns a RESTClient for working with the specified RESTMapping or an error. This is intended
// for working with arbitrary resources and is not guaranteed to point to a Kubernetes APIServer.