Merge pull request #54554 from zjj2wry/set-dep
Automatic merge from submit-queue (batch tested with PRs 53337, 55465, 55512, 55522, 54554). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. switch UpdatePodSpecForObject to work on v1.PodSpec, use info.VersionedObject, and avoid conversion completely **What this PR does / why we need it**: ref #54212 ref #https://github.com/kubernetes/kubectl/issues/83 **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes # **Special notes for your reviewer**: cc @liggitt @pwittrock **Release note**: ```release-note NONE ```
This commit is contained in:
		| @@ -29,6 +29,7 @@ go_library( | |||||||
|         "//pkg/kubectl/resource:go_default_library", |         "//pkg/kubectl/resource:go_default_library", | ||||||
|         "//pkg/kubectl/util/i18n:go_default_library", |         "//pkg/kubectl/util/i18n:go_default_library", | ||||||
|         "//vendor/github.com/spf13/cobra:go_default_library", |         "//vendor/github.com/spf13/cobra:go_default_library", | ||||||
|  |         "//vendor/k8s.io/api/core/v1:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", | ||||||
| @@ -38,6 +39,7 @@ go_library( | |||||||
|         "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/util/validation:go_default_library", | ||||||
|  |         "//vendor/k8s.io/client-go/kubernetes:go_default_library", | ||||||
|     ], |     ], | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -61,7 +63,6 @@ go_test( | |||||||
|     deps = [ |     deps = [ | ||||||
|         "//pkg/api/legacyscheme:go_default_library", |         "//pkg/api/legacyscheme:go_default_library", | ||||||
|         "//pkg/api/testapi:go_default_library", |         "//pkg/api/testapi:go_default_library", | ||||||
|         "//pkg/apis/apps:go_default_library", |  | ||||||
|         "//pkg/apis/batch:go_default_library", |         "//pkg/apis/batch:go_default_library", | ||||||
|         "//pkg/apis/core:go_default_library", |         "//pkg/apis/core:go_default_library", | ||||||
|         "//pkg/apis/extensions:go_default_library", |         "//pkg/apis/extensions:go_default_library", | ||||||
| @@ -69,9 +70,16 @@ go_test( | |||||||
|         "//pkg/kubectl/cmd/testing:go_default_library", |         "//pkg/kubectl/cmd/testing:go_default_library", | ||||||
|         "//pkg/kubectl/cmd/util:go_default_library", |         "//pkg/kubectl/cmd/util:go_default_library", | ||||||
|         "//pkg/kubectl/resource:go_default_library", |         "//pkg/kubectl/resource:go_default_library", | ||||||
|  |         "//pkg/kubectl/scheme:go_default_library", | ||||||
|         "//pkg/printers:go_default_library", |         "//pkg/printers:go_default_library", | ||||||
|         "//vendor/github.com/spf13/cobra:go_default_library", |         "//vendor/github.com/spf13/cobra:go_default_library", | ||||||
|         "//vendor/github.com/stretchr/testify/assert:go_default_library", |         "//vendor/github.com/stretchr/testify/assert:go_default_library", | ||||||
|  |         "//vendor/k8s.io/api/apps/v1:go_default_library", | ||||||
|  |         "//vendor/k8s.io/api/apps/v1beta1:go_default_library", | ||||||
|  |         "//vendor/k8s.io/api/apps/v1beta2:go_default_library", | ||||||
|  |         "//vendor/k8s.io/api/batch/v1:go_default_library", | ||||||
|  |         "//vendor/k8s.io/api/core/v1:go_default_library", | ||||||
|  |         "//vendor/k8s.io/api/extensions/v1beta1:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", | ||||||
|   | |||||||
| @@ -21,20 +21,19 @@ import ( | |||||||
| 	"io" | 	"io" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
|  | 	"k8s.io/api/core/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/api/errors" | 	"k8s.io/apimachinery/pkg/api/errors" | ||||||
| 	"k8s.io/apimachinery/pkg/runtime" | 	"k8s.io/apimachinery/pkg/runtime" | ||||||
| 	"k8s.io/apimachinery/pkg/util/sets" | 	"k8s.io/apimachinery/pkg/util/sets" | ||||||
| 	"k8s.io/apimachinery/pkg/util/strategicpatch" | 	"k8s.io/apimachinery/pkg/util/strategicpatch" | ||||||
| 	"k8s.io/kubernetes/pkg/api/legacyscheme" |  | ||||||
| 	api "k8s.io/kubernetes/pkg/apis/core" |  | ||||||
| 	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" | 	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" | ||||||
| 	"k8s.io/kubernetes/pkg/kubectl/resource" | 	"k8s.io/kubernetes/pkg/kubectl/resource" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // selectContainers allows one or more containers to be matched against a string or wildcard | // selectContainers allows one or more containers to be matched against a string or wildcard | ||||||
| func selectContainers(containers []api.Container, spec string) ([]*api.Container, []*api.Container) { | func selectContainers(containers []v1.Container, spec string) ([]*v1.Container, []*v1.Container) { | ||||||
| 	out := []*api.Container{} | 	out := []*v1.Container{} | ||||||
| 	skipped := []*api.Container{} | 	skipped := []*v1.Container{} | ||||||
| 	for i, c := range containers { | 	for i, c := range containers { | ||||||
| 		if selectString(c.Name, spec) { | 		if selectString(c.Name, spec) { | ||||||
| 			out = append(out, &containers[i]) | 			out = append(out, &containers[i]) | ||||||
| @@ -127,10 +126,14 @@ 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. | // 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. | // This function returns whether the mutation function made any change in the original object. | ||||||
| func CalculatePatch(patch *Patch, encoder runtime.Encoder, mutateFn patchFn) bool { | func CalculatePatch(patch *Patch, encoder runtime.Encoder, mutateFn patchFn) bool { | ||||||
| 	versionedEncoder := legacyscheme.Codecs.EncoderForVersion(encoder, patch.Info.Mapping.GroupVersionKind.GroupVersion()) | 	versioned, err := patch.Info.Mapping.ConvertToVersion(patch.Info.Object, patch.Info.Mapping.GroupVersionKind.GroupVersion()) | ||||||
|  | 	if err != nil { | ||||||
| 	patch.Before, patch.Err = runtime.Encode(versionedEncoder, patch.Info.Object) | 		patch.Err = err | ||||||
|  | 		return true | ||||||
|  | 	} | ||||||
|  | 	patch.Info.VersionedObject = versioned | ||||||
|  |  | ||||||
|  | 	patch.Before, patch.Err = runtime.Encode(encoder, patch.Info.VersionedObject) | ||||||
| 	patch.After, patch.Err = mutateFn(patch.Info) | 	patch.After, patch.Err = mutateFn(patch.Info) | ||||||
| 	if patch.Err != nil { | 	if patch.Err != nil { | ||||||
| 		return true | 		return true | ||||||
| @@ -139,14 +142,7 @@ func CalculatePatch(patch *Patch, encoder runtime.Encoder, mutateFn patchFn) boo | |||||||
| 		return false | 		return false | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// TODO: should be via New | 	patch.Patch, patch.Err = strategicpatch.CreateTwoWayMergePatch(patch.Before, patch.After, patch.Info.VersionedObject) | ||||||
| 	versioned, err := patch.Info.Mapping.ConvertToVersion(patch.Info.Object, patch.Info.Mapping.GroupVersionKind.GroupVersion()) |  | ||||||
| 	if err != nil { |  | ||||||
| 		patch.Err = err |  | ||||||
| 		return true |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	patch.Patch, patch.Err = strategicpatch.CreateTwoWayMergePatch(patch.Before, patch.After, versioned) |  | ||||||
| 	return true | 	return true | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -163,17 +159,17 @@ func CalculatePatches(infos []*resource.Info, encoder runtime.Encoder, mutateFn | |||||||
| 	return patches | 	return patches | ||||||
| } | } | ||||||
|  |  | ||||||
| func findEnv(env []api.EnvVar, name string) (api.EnvVar, bool) { | func findEnv(env []v1.EnvVar, name string) (v1.EnvVar, bool) { | ||||||
| 	for _, e := range env { | 	for _, e := range env { | ||||||
| 		if e.Name == name { | 		if e.Name == name { | ||||||
| 			return e, true | 			return e, true | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return api.EnvVar{}, false | 	return v1.EnvVar{}, false | ||||||
| } | } | ||||||
|  |  | ||||||
| func updateEnv(existing []api.EnvVar, env []api.EnvVar, remove []string) []api.EnvVar { | func updateEnv(existing []v1.EnvVar, env []v1.EnvVar, remove []string) []v1.EnvVar { | ||||||
| 	out := []api.EnvVar{} | 	out := []v1.EnvVar{} | ||||||
| 	covered := sets.NewString(remove...) | 	covered := sets.NewString(remove...) | ||||||
| 	for _, e := range existing { | 	for _, e := range existing { | ||||||
| 		if covered.Has(e.Name) { | 		if covered.Has(e.Name) { | ||||||
|   | |||||||
| @@ -25,11 +25,11 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"github.com/spf13/cobra" | 	"github.com/spf13/cobra" | ||||||
|  | 	"k8s.io/api/core/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/api/meta" | 	"k8s.io/apimachinery/pkg/api/meta" | ||||||
| 	"k8s.io/apimachinery/pkg/runtime" | 	"k8s.io/apimachinery/pkg/runtime" | ||||||
| 	"k8s.io/apimachinery/pkg/types" | 	"k8s.io/apimachinery/pkg/types" | ||||||
| 	"k8s.io/kubernetes/pkg/api/legacyscheme" | 	"k8s.io/client-go/kubernetes" | ||||||
| 	api "k8s.io/kubernetes/pkg/apis/core" |  | ||||||
| 	"k8s.io/kubernetes/pkg/kubectl/cmd/templates" | 	"k8s.io/kubernetes/pkg/kubectl/cmd/templates" | ||||||
| 	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" | 	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" | ||||||
| 	envutil "k8s.io/kubernetes/pkg/kubectl/cmd/util/env" | 	envutil "k8s.io/kubernetes/pkg/kubectl/cmd/util/env" | ||||||
| @@ -116,14 +116,13 @@ type EnvOptions struct { | |||||||
| 	Prefix            string | 	Prefix            string | ||||||
|  |  | ||||||
| 	Mapper  meta.RESTMapper | 	Mapper  meta.RESTMapper | ||||||
| 	Typer   runtime.ObjectTyper |  | ||||||
| 	Builder *resource.Builder | 	Builder *resource.Builder | ||||||
| 	Infos   []*resource.Info | 	Infos   []*resource.Info | ||||||
| 	Encoder runtime.Encoder | 	Encoder runtime.Encoder | ||||||
|  |  | ||||||
| 	Cmd *cobra.Command | 	Cmd *cobra.Command | ||||||
|  |  | ||||||
| 	UpdatePodSpecForObject func(obj runtime.Object, fn func(*api.PodSpec) error) (bool, error) | 	UpdatePodSpecForObject func(obj runtime.Object, fn func(*v1.PodSpec) error) (bool, error) | ||||||
| 	PrintObject            func(cmd *cobra.Command, isLocal bool, mapper meta.RESTMapper, obj runtime.Object, out io.Writer) error | 	PrintObject            func(cmd *cobra.Command, isLocal bool, mapper meta.RESTMapper, obj runtime.Object, out io.Writer) error | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -163,7 +162,7 @@ func NewCmdEnv(f cmdutil.Factory, in io.Reader, out, errout io.Writer) *cobra.Co | |||||||
| 	return cmd | 	return cmd | ||||||
| } | } | ||||||
|  |  | ||||||
| func validateNoOverwrites(existing []api.EnvVar, env []api.EnvVar) error { | func validateNoOverwrites(existing []v1.EnvVar, env []v1.EnvVar) error { | ||||||
| 	for _, e := range env { | 	for _, e := range env { | ||||||
| 		if current, exists := findEnv(existing, e.Name); exists && current.Value != e.Value { | 		if current, exists := findEnv(existing, e.Name); exists && current.Value != e.Value { | ||||||
| 			return fmt.Errorf("'%s' already has a value (%s), and --overwrite is false", current.Name, current.Value) | 			return fmt.Errorf("'%s' already has a value (%s), and --overwrite is false", current.Name, current.Value) | ||||||
| @@ -186,7 +185,7 @@ func (o *EnvOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []stri | |||||||
| 		return cmdutil.UsageErrorf(cmd, "one or more resources must be specified as <resource> <name> or <resource>/<name>") | 		return cmdutil.UsageErrorf(cmd, "one or more resources must be specified as <resource> <name> or <resource>/<name>") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	o.Mapper, o.Typer = f.Object() | 	o.Mapper, _ = f.Object() | ||||||
| 	o.UpdatePodSpecForObject = f.UpdatePodSpecForObject | 	o.UpdatePodSpecForObject = f.UpdatePodSpecForObject | ||||||
| 	o.Encoder = f.JSONEncoder() | 	o.Encoder = f.JSONEncoder() | ||||||
| 	o.ContainerSelector = cmdutil.GetFlagString(cmd, "containers") | 	o.ContainerSelector = cmdutil.GetFlagString(cmd, "containers") | ||||||
| @@ -216,9 +215,13 @@ func (o *EnvOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []stri | |||||||
|  |  | ||||||
| // RunEnv contains all the necessary functionality for the OpenShift cli env command | // RunEnv contains all the necessary functionality for the OpenShift cli env command | ||||||
| func (o *EnvOptions) RunEnv(f cmdutil.Factory) error { | func (o *EnvOptions) RunEnv(f cmdutil.Factory) error { | ||||||
| 	kubeClient, err := f.ClientSet() | 	var kubeClient *kubernetes.Clientset | ||||||
| 	if err != nil { | 	if o.List { | ||||||
| 		return err | 		client, err := f.KubernetesClientSet() | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 		kubeClient = client | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	cmdNamespace, enforceNamespace, err := f.DefaultNamespace() | 	cmdNamespace, enforceNamespace, err := f.DefaultNamespace() | ||||||
| @@ -253,14 +256,18 @@ func (o *EnvOptions) RunEnv(f cmdutil.Factory) error { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		for _, info := range infos { | 		for _, info := range infos { | ||||||
| 			switch from := info.Object.(type) { | 			versionedObject, err := info.Mapping.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion()) | ||||||
| 			case *api.Secret: | 			if err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 			switch from := versionedObject.(type) { | ||||||
|  | 			case *v1.Secret: | ||||||
| 				for key := range from.Data { | 				for key := range from.Data { | ||||||
| 					envVar := api.EnvVar{ | 					envVar := v1.EnvVar{ | ||||||
| 						Name: keyToEnvName(key), | 						Name: keyToEnvName(key), | ||||||
| 						ValueFrom: &api.EnvVarSource{ | 						ValueFrom: &v1.EnvVarSource{ | ||||||
| 							SecretKeyRef: &api.SecretKeySelector{ | 							SecretKeyRef: &v1.SecretKeySelector{ | ||||||
| 								LocalObjectReference: api.LocalObjectReference{ | 								LocalObjectReference: v1.LocalObjectReference{ | ||||||
| 									Name: from.Name, | 									Name: from.Name, | ||||||
| 								}, | 								}, | ||||||
| 								Key: key, | 								Key: key, | ||||||
| @@ -269,13 +276,13 @@ func (o *EnvOptions) RunEnv(f cmdutil.Factory) error { | |||||||
| 					} | 					} | ||||||
| 					env = append(env, envVar) | 					env = append(env, envVar) | ||||||
| 				} | 				} | ||||||
| 			case *api.ConfigMap: | 			case *v1.ConfigMap: | ||||||
| 				for key := range from.Data { | 				for key := range from.Data { | ||||||
| 					envVar := api.EnvVar{ | 					envVar := v1.EnvVar{ | ||||||
| 						Name: keyToEnvName(key), | 						Name: keyToEnvName(key), | ||||||
| 						ValueFrom: &api.EnvVarSource{ | 						ValueFrom: &v1.EnvVarSource{ | ||||||
| 							ConfigMapKeyRef: &api.ConfigMapKeySelector{ | 							ConfigMapKeyRef: &v1.ConfigMapKeySelector{ | ||||||
| 								LocalObjectReference: api.LocalObjectReference{ | 								LocalObjectReference: v1.LocalObjectReference{ | ||||||
| 									Name: from.Name, | 									Name: from.Name, | ||||||
| 								}, | 								}, | ||||||
| 								Key: key, | 								Key: key, | ||||||
| @@ -316,7 +323,7 @@ func (o *EnvOptions) RunEnv(f cmdutil.Factory) error { | |||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	patches := CalculatePatches(o.Infos, o.Encoder, func(info *resource.Info) ([]byte, error) { | 	patches := CalculatePatches(o.Infos, o.Encoder, func(info *resource.Info) ([]byte, error) { | ||||||
| 		_, err := o.UpdatePodSpecForObject(info.Object, func(spec *api.PodSpec) error { | 		_, err := o.UpdatePodSpecForObject(info.VersionedObject, func(spec *v1.PodSpec) error { | ||||||
| 			resolutionErrorsEncountered := false | 			resolutionErrorsEncountered := false | ||||||
| 			containers, _ := selectContainers(spec.Containers, o.ContainerSelector) | 			containers, _ := selectContainers(spec.Containers, o.ContainerSelector) | ||||||
| 			if len(containers) == 0 { | 			if len(containers) == 0 { | ||||||
| @@ -382,9 +389,7 @@ func (o *EnvOptions) RunEnv(f cmdutil.Factory) error { | |||||||
| 		}) | 		}) | ||||||
|  |  | ||||||
| 		if err == nil { | 		if err == nil { | ||||||
| 			// TODO: switch UpdatePodSpecForObject to work on v1.PodSpec, use info.VersionedObject, and avoid conversion completely | 			return runtime.Encode(o.Encoder, info.VersionedObject) | ||||||
| 			versionedEncoder := legacyscheme.Codecs.EncoderForVersion(o.Encoder, info.Mapping.GroupVersionKind.GroupVersion()) |  | ||||||
| 			return runtime.Encode(versionedEncoder, info.Object) |  | ||||||
| 		} | 		} | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	}) | 	}) | ||||||
| @@ -408,7 +413,7 @@ func (o *EnvOptions) RunEnv(f cmdutil.Factory) error { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if o.PrintObject != nil && (o.Local || o.DryRun) { | 		if o.PrintObject != nil && (o.Local || o.DryRun) { | ||||||
| 			if err := o.PrintObject(o.Cmd, o.Local, o.Mapper, info.Object, o.Out); err != nil { | 			if err := o.PrintObject(o.Cmd, o.Local, o.Mapper, patch.Info.VersionedObject, o.Out); err != nil { | ||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
| 			continue | 			continue | ||||||
| @@ -428,7 +433,11 @@ func (o *EnvOptions) RunEnv(f cmdutil.Factory) error { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if len(o.Output) > 0 { | 		if len(o.Output) > 0 { | ||||||
| 			if err := o.PrintObject(o.Cmd, o.Local, o.Mapper, obj, o.Out); err != nil { | 			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 { | ||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
| 			continue | 			continue | ||||||
|   | |||||||
| @@ -18,25 +18,37 @@ package set | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"bytes" | 	"bytes" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io/ioutil" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"os" | 	"os" | ||||||
|  | 	"path" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | 	appsv1 "k8s.io/api/apps/v1" | ||||||
|  | 	appsv1beta1 "k8s.io/api/apps/v1beta1" | ||||||
|  | 	appsv1beta2 "k8s.io/api/apps/v1beta2" | ||||||
|  | 	batchv1 "k8s.io/api/batch/v1" | ||||||
|  | 	"k8s.io/api/core/v1" | ||||||
|  | 	extensionsv1beta1 "k8s.io/api/extensions/v1beta1" | ||||||
|  | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/runtime" | 	"k8s.io/apimachinery/pkg/runtime" | ||||||
|  | 	"k8s.io/apimachinery/pkg/runtime/schema" | ||||||
| 	restclient "k8s.io/client-go/rest" | 	restclient "k8s.io/client-go/rest" | ||||||
| 	"k8s.io/client-go/rest/fake" | 	"k8s.io/client-go/rest/fake" | ||||||
| 	"k8s.io/kubernetes/pkg/api/legacyscheme" | 	"k8s.io/kubernetes/pkg/api/testapi" | ||||||
| 	api "k8s.io/kubernetes/pkg/apis/core" |  | ||||||
| 	cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" | 	cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" | ||||||
| 	"k8s.io/kubernetes/pkg/kubectl/resource" | 	"k8s.io/kubernetes/pkg/kubectl/resource" | ||||||
|  | 	"k8s.io/kubernetes/pkg/kubectl/scheme" | ||||||
| 	"k8s.io/kubernetes/pkg/printers" | 	"k8s.io/kubernetes/pkg/printers" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func TestSetEnvLocal(t *testing.T) { | func TestSetEnvLocal(t *testing.T) { | ||||||
| 	f, tf, codec, ns := cmdtesting.NewAPIFactory() | 	f, tf, codec, ns := cmdtesting.NewAPIFactory() | ||||||
| 	tf.Client = &fake.RESTClient{ | 	tf.Client = &fake.RESTClient{ | ||||||
| 		GroupVersion:         legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, | 		GroupVersion:         schema.GroupVersion{Version: ""}, | ||||||
| 		NegotiatedSerializer: ns, | 		NegotiatedSerializer: ns, | ||||||
| 		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | 		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | ||||||
| 			t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) | 			t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) | ||||||
| @@ -44,7 +56,7 @@ func TestSetEnvLocal(t *testing.T) { | |||||||
| 		}), | 		}), | ||||||
| 	} | 	} | ||||||
| 	tf.Namespace = "test" | 	tf.Namespace = "test" | ||||||
| 	tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion}} | 	tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}} | ||||||
|  |  | ||||||
| 	buf := bytes.NewBuffer([]byte{}) | 	buf := bytes.NewBuffer([]byte{}) | ||||||
| 	cmd := NewCmdEnv(f, os.Stdin, buf, buf) | 	cmd := NewCmdEnv(f, os.Stdin, buf, buf) | ||||||
| @@ -73,7 +85,7 @@ func TestSetEnvLocal(t *testing.T) { | |||||||
| func TestSetMultiResourcesEnvLocal(t *testing.T) { | func TestSetMultiResourcesEnvLocal(t *testing.T) { | ||||||
| 	f, tf, codec, ns := cmdtesting.NewAPIFactory() | 	f, tf, codec, ns := cmdtesting.NewAPIFactory() | ||||||
| 	tf.Client = &fake.RESTClient{ | 	tf.Client = &fake.RESTClient{ | ||||||
| 		GroupVersion:         legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, | 		GroupVersion:         schema.GroupVersion{Version: ""}, | ||||||
| 		NegotiatedSerializer: ns, | 		NegotiatedSerializer: ns, | ||||||
| 		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | 		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | ||||||
| 			t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) | 			t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) | ||||||
| @@ -81,7 +93,7 @@ func TestSetMultiResourcesEnvLocal(t *testing.T) { | |||||||
| 		}), | 		}), | ||||||
| 	} | 	} | ||||||
| 	tf.Namespace = "test" | 	tf.Namespace = "test" | ||||||
| 	tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion}} | 	tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}} | ||||||
|  |  | ||||||
| 	buf := bytes.NewBuffer([]byte{}) | 	buf := bytes.NewBuffer([]byte{}) | ||||||
| 	cmd := NewCmdEnv(f, os.Stdin, buf, buf) | 	cmd := NewCmdEnv(f, os.Stdin, buf, buf) | ||||||
| @@ -108,3 +120,359 @@ func TestSetMultiResourcesEnvLocal(t *testing.T) { | |||||||
| 		t.Errorf("expected out:\n%s\nbut got:\n%s", expectedOut, buf.String()) | 		t.Errorf("expected out:\n%s\nbut got:\n%s", expectedOut, buf.String()) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func TestSetEnvRemote(t *testing.T) { | ||||||
|  | 	inputs := []struct { | ||||||
|  | 		object                          runtime.Object | ||||||
|  | 		apiPrefix, apiGroup, apiVersion string | ||||||
|  | 		testAPIGroup                    string | ||||||
|  | 		args                            []string | ||||||
|  | 	}{ | ||||||
|  | 		{ | ||||||
|  | 			object: &extensionsv1beta1.ReplicaSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: extensionsv1beta1.ReplicaSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "extensions", apiVersion: "v1beta1", | ||||||
|  | 			args: []string{"replicaset", "nginx", "env=prod"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1beta2.ReplicaSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1beta2.ReplicaSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta2", | ||||||
|  | 			args: []string{"replicaset", "nginx", "env=prod"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1.ReplicaSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1.ReplicaSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1", | ||||||
|  | 			args: []string{"replicaset", "nginx", "env=prod"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &extensionsv1beta1.DaemonSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: extensionsv1beta1.DaemonSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "extensions", apiVersion: "v1beta1", | ||||||
|  | 			args: []string{"daemonset", "nginx", "env=prod"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1beta2.DaemonSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1beta2.DaemonSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta2", | ||||||
|  | 			args: []string{"daemonset", "nginx", "env=prod"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1.DaemonSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1.DaemonSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1", | ||||||
|  | 			args: []string{"daemonset", "nginx", "env=prod"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &extensionsv1beta1.Deployment{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: extensionsv1beta1.DeploymentSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "extensions", apiVersion: "v1beta1", | ||||||
|  | 			args: []string{"deployment", "nginx", "env=prod"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1beta1.Deployment{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1beta1.DeploymentSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta1", | ||||||
|  | 			args: []string{"deployment", "nginx", "env=prod"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1beta2.Deployment{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1beta2.DeploymentSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta2", | ||||||
|  | 			args: []string{"deployment", "nginx", "env=prod"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1.Deployment{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1.DeploymentSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1", | ||||||
|  | 			args: []string{"deployment", "nginx", "env=prod"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1beta1.StatefulSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1beta1.StatefulSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "apps", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta1", | ||||||
|  | 			args: []string{"statefulset", "nginx", "env=prod"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1beta2.StatefulSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1beta2.StatefulSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "apps", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta2", | ||||||
|  | 			args: []string{"statefulset", "nginx", "env=prod"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1.StatefulSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1.StatefulSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "apps", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1", | ||||||
|  | 			args: []string{"statefulset", "nginx", "env=prod"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &batchv1.Job{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: batchv1.JobSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "batch", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "batch", apiVersion: "v1", | ||||||
|  | 			args: []string{"job", "nginx", "env=prod"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &v1.ReplicationController{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: v1.ReplicationControllerSpec{ | ||||||
|  | 					Template: &v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "", | ||||||
|  | 			apiPrefix:    "/api", apiGroup: "", apiVersion: "v1", | ||||||
|  | 			args: []string{"replicationcontroller", "nginx", "env=prod"}, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	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) | ||||||
|  | 		tf.Printer = printers.NewVersionedPrinter(&printers.YAMLPrinter{}, testapi.Default.Converter(), *testapi.Default.GroupVersion()) | ||||||
|  | 		tf.Namespace = "test" | ||||||
|  | 		tf.CategoryExpander = resource.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), `"value":`+`"`+"prod"+`"`, fmt.Sprintf("env 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", "image", req.Method, req.URL, req) | ||||||
|  | 					return nil, fmt.Errorf("unexpected request") | ||||||
|  | 				} | ||||||
|  | 			}), | ||||||
|  | 			VersionedAPIPath: path.Join(input.apiPrefix, testapi.Default.GroupVersion().String()), | ||||||
|  | 		} | ||||||
|  | 		out := new(bytes.Buffer) | ||||||
|  | 		cmd := NewCmdEnv(f, out, out, out) | ||||||
|  | 		cmd.SetOutput(out) | ||||||
|  | 		cmd.Flags().Set("output", "yaml") | ||||||
|  | 		opts := EnvOptions{ | ||||||
|  | 			Out:   out, | ||||||
|  | 			Local: false} | ||||||
|  | 		err := opts.Complete(f, cmd, input.args) | ||||||
|  | 		assert.NoError(t, err) | ||||||
|  | 		err = opts.RunEnv(f) | ||||||
|  | 		assert.NoError(t, err) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|   | |||||||
| @@ -21,12 +21,11 @@ import ( | |||||||
| 	"io" | 	"io" | ||||||
|  |  | ||||||
| 	"github.com/spf13/cobra" | 	"github.com/spf13/cobra" | ||||||
|  | 	"k8s.io/api/core/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/api/meta" | 	"k8s.io/apimachinery/pkg/api/meta" | ||||||
| 	"k8s.io/apimachinery/pkg/runtime" | 	"k8s.io/apimachinery/pkg/runtime" | ||||||
| 	"k8s.io/apimachinery/pkg/types" | 	"k8s.io/apimachinery/pkg/types" | ||||||
| 	utilerrors "k8s.io/apimachinery/pkg/util/errors" | 	utilerrors "k8s.io/apimachinery/pkg/util/errors" | ||||||
| 	"k8s.io/kubernetes/pkg/api/legacyscheme" |  | ||||||
| 	api "k8s.io/kubernetes/pkg/apis/core" |  | ||||||
| 	"k8s.io/kubernetes/pkg/kubectl/cmd/templates" | 	"k8s.io/kubernetes/pkg/kubectl/cmd/templates" | ||||||
| 	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" | 	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" | ||||||
| 	"k8s.io/kubernetes/pkg/kubectl/resource" | 	"k8s.io/kubernetes/pkg/kubectl/resource" | ||||||
| @@ -39,9 +38,9 @@ type ImageOptions struct { | |||||||
| 	resource.FilenameOptions | 	resource.FilenameOptions | ||||||
|  |  | ||||||
| 	Mapper       meta.RESTMapper | 	Mapper       meta.RESTMapper | ||||||
| 	Typer        runtime.ObjectTyper |  | ||||||
| 	Infos        []*resource.Info | 	Infos        []*resource.Info | ||||||
| 	Encoder      runtime.Encoder | 	Encoder      runtime.Encoder | ||||||
|  | 	Decoder      runtime.Decoder | ||||||
| 	Selector     string | 	Selector     string | ||||||
| 	Out          io.Writer | 	Out          io.Writer | ||||||
| 	Err          io.Writer | 	Err          io.Writer | ||||||
| @@ -56,7 +55,7 @@ type ImageOptions struct { | |||||||
| 	ResolveImage func(in string) (string, error) | 	ResolveImage func(in string) (string, error) | ||||||
|  |  | ||||||
| 	PrintObject            func(cmd *cobra.Command, isLocal bool, mapper meta.RESTMapper, obj runtime.Object, out io.Writer) error | 	PrintObject            func(cmd *cobra.Command, isLocal bool, mapper meta.RESTMapper, obj runtime.Object, out io.Writer) error | ||||||
| 	UpdatePodSpecForObject func(obj runtime.Object, fn func(*api.PodSpec) error) (bool, error) | 	UpdatePodSpecForObject func(obj runtime.Object, fn func(*v1.PodSpec) error) (bool, error) | ||||||
| 	Resources              []string | 	Resources              []string | ||||||
| 	ContainerImages        map[string]string | 	ContainerImages        map[string]string | ||||||
| } | } | ||||||
| @@ -116,9 +115,10 @@ func NewCmdImage(f cmdutil.Factory, out, err io.Writer) *cobra.Command { | |||||||
| } | } | ||||||
|  |  | ||||||
| func (o *ImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { | func (o *ImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { | ||||||
| 	o.Mapper, o.Typer = f.Object() | 	o.Mapper, _ = f.Object() | ||||||
| 	o.UpdatePodSpecForObject = f.UpdatePodSpecForObject | 	o.UpdatePodSpecForObject = f.UpdatePodSpecForObject | ||||||
| 	o.Encoder = f.JSONEncoder() | 	o.Encoder = f.JSONEncoder() | ||||||
|  | 	o.Decoder = f.Decoder(true) | ||||||
| 	o.ShortOutput = cmdutil.GetFlagString(cmd, "output") == "name" | 	o.ShortOutput = cmdutil.GetFlagString(cmd, "output") == "name" | ||||||
| 	o.Record = cmdutil.GetRecordFlag(cmd) | 	o.Record = cmdutil.GetRecordFlag(cmd) | ||||||
| 	o.ChangeCause = f.Command(cmd, false) | 	o.ChangeCause = f.Command(cmd, false) | ||||||
| @@ -189,7 +189,7 @@ func (o *ImageOptions) Run() error { | |||||||
|  |  | ||||||
| 	patches := CalculatePatches(o.Infos, o.Encoder, func(info *resource.Info) ([]byte, error) { | 	patches := CalculatePatches(o.Infos, o.Encoder, func(info *resource.Info) ([]byte, error) { | ||||||
| 		transformed := false | 		transformed := false | ||||||
| 		_, err := o.UpdatePodSpecForObject(info.Object, func(spec *api.PodSpec) error { | 		_, err := o.UpdatePodSpecForObject(info.VersionedObject, func(spec *v1.PodSpec) error { | ||||||
| 			for name, image := range o.ContainerImages { | 			for name, image := range o.ContainerImages { | ||||||
| 				var ( | 				var ( | ||||||
| 					containerFound bool | 					containerFound bool | ||||||
| @@ -226,9 +226,7 @@ func (o *ImageOptions) Run() error { | |||||||
| 			return nil | 			return nil | ||||||
| 		}) | 		}) | ||||||
| 		if transformed && err == nil { | 		if transformed && err == nil { | ||||||
| 			// TODO: switch UpdatePodSpecForObject to work on v1.PodSpec, use info.VersionedObject, and avoid conversion completely | 			return runtime.Encode(o.Encoder, info.VersionedObject) | ||||||
| 			versionedEncoder := legacyscheme.Codecs.EncoderForVersion(o.Encoder, info.Mapping.GroupVersionKind.GroupVersion()) |  | ||||||
| 			return runtime.Encode(versionedEncoder, info.Object) |  | ||||||
| 		} | 		} | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	}) | 	}) | ||||||
| @@ -246,7 +244,7 @@ func (o *ImageOptions) Run() error { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if o.PrintObject != nil && (o.Local || o.DryRun) { | 		if o.PrintObject != nil && (o.Local || o.DryRun) { | ||||||
| 			if err := o.PrintObject(o.Cmd, o.Local, o.Mapper, info.Object, o.Out); err != nil { | 			if err := o.PrintObject(o.Cmd, o.Local, o.Mapper, patch.Info.VersionedObject, o.Out); err != nil { | ||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
| 			continue | 			continue | ||||||
| @@ -272,7 +270,11 @@ func (o *ImageOptions) Run() error { | |||||||
| 		info.Refresh(obj, true) | 		info.Refresh(obj, true) | ||||||
|  |  | ||||||
| 		if len(o.Output) > 0 { | 		if len(o.Output) > 0 { | ||||||
| 			if err := o.PrintObject(o.Cmd, o.Local, o.Mapper, obj, o.Out); err != nil { | 			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 { | ||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
| 			continue | 			continue | ||||||
|   | |||||||
| @@ -18,24 +18,36 @@ package set | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"bytes" | 	"bytes" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io/ioutil" | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  | 	"path" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | 	appsv1 "k8s.io/api/apps/v1" | ||||||
|  | 	appsv1beta1 "k8s.io/api/apps/v1beta1" | ||||||
|  | 	appsv1beta2 "k8s.io/api/apps/v1beta2" | ||||||
|  | 	batchv1 "k8s.io/api/batch/v1" | ||||||
|  | 	"k8s.io/api/core/v1" | ||||||
|  | 	extensionsv1beta1 "k8s.io/api/extensions/v1beta1" | ||||||
|  | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/runtime" | 	"k8s.io/apimachinery/pkg/runtime" | ||||||
|  | 	"k8s.io/apimachinery/pkg/runtime/schema" | ||||||
| 	restclient "k8s.io/client-go/rest" | 	restclient "k8s.io/client-go/rest" | ||||||
| 	"k8s.io/client-go/rest/fake" | 	"k8s.io/client-go/rest/fake" | ||||||
| 	"k8s.io/kubernetes/pkg/api/legacyscheme" | 	"k8s.io/kubernetes/pkg/api/testapi" | ||||||
| 	api "k8s.io/kubernetes/pkg/apis/core" |  | ||||||
| 	cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" | 	cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" | ||||||
| 	"k8s.io/kubernetes/pkg/kubectl/resource" | 	"k8s.io/kubernetes/pkg/kubectl/resource" | ||||||
|  | 	"k8s.io/kubernetes/pkg/kubectl/scheme" | ||||||
| 	"k8s.io/kubernetes/pkg/printers" | 	"k8s.io/kubernetes/pkg/printers" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func TestImageLocal(t *testing.T) { | func TestImageLocal(t *testing.T) { | ||||||
| 	f, tf, codec, ns := cmdtesting.NewAPIFactory() | 	f, tf, codec, ns := cmdtesting.NewAPIFactory() | ||||||
| 	tf.Client = &fake.RESTClient{ | 	tf.Client = &fake.RESTClient{ | ||||||
| 		GroupVersion:         legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, | 		GroupVersion:         schema.GroupVersion{Version: ""}, | ||||||
| 		NegotiatedSerializer: ns, | 		NegotiatedSerializer: ns, | ||||||
| 		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | 		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | ||||||
| 			t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) | 			t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) | ||||||
| @@ -43,7 +55,7 @@ func TestImageLocal(t *testing.T) { | |||||||
| 		}), | 		}), | ||||||
| 	} | 	} | ||||||
| 	tf.Namespace = "test" | 	tf.Namespace = "test" | ||||||
| 	tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion}} | 	tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}} | ||||||
|  |  | ||||||
| 	buf := bytes.NewBuffer([]byte{}) | 	buf := bytes.NewBuffer([]byte{}) | ||||||
| 	cmd := NewCmdImage(f, buf, buf) | 	cmd := NewCmdImage(f, buf, buf) | ||||||
| @@ -138,7 +150,7 @@ func TestSetImageValidation(t *testing.T) { | |||||||
| func TestSetMultiResourcesImageLocal(t *testing.T) { | func TestSetMultiResourcesImageLocal(t *testing.T) { | ||||||
| 	f, tf, codec, ns := cmdtesting.NewAPIFactory() | 	f, tf, codec, ns := cmdtesting.NewAPIFactory() | ||||||
| 	tf.Client = &fake.RESTClient{ | 	tf.Client = &fake.RESTClient{ | ||||||
| 		GroupVersion:         legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, | 		GroupVersion:         schema.GroupVersion{Version: ""}, | ||||||
| 		NegotiatedSerializer: ns, | 		NegotiatedSerializer: ns, | ||||||
| 		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | 		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | ||||||
| 			t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) | 			t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) | ||||||
| @@ -146,7 +158,7 @@ func TestSetMultiResourcesImageLocal(t *testing.T) { | |||||||
| 		}), | 		}), | ||||||
| 	} | 	} | ||||||
| 	tf.Namespace = "test" | 	tf.Namespace = "test" | ||||||
| 	tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion}} | 	tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}} | ||||||
|  |  | ||||||
| 	buf := bytes.NewBuffer([]byte{}) | 	buf := bytes.NewBuffer([]byte{}) | ||||||
| 	cmd := NewCmdImage(f, buf, buf) | 	cmd := NewCmdImage(f, buf, buf) | ||||||
| @@ -175,3 +187,359 @@ func TestSetMultiResourcesImageLocal(t *testing.T) { | |||||||
| 		t.Errorf("expected out:\n%s\nbut got:\n%s", expectedOut, buf.String()) | 		t.Errorf("expected out:\n%s\nbut got:\n%s", expectedOut, buf.String()) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func TestSetImageRemote(t *testing.T) { | ||||||
|  | 	inputs := []struct { | ||||||
|  | 		object                          runtime.Object | ||||||
|  | 		apiPrefix, apiGroup, apiVersion string | ||||||
|  | 		testAPIGroup                    string | ||||||
|  | 		args                            []string | ||||||
|  | 	}{ | ||||||
|  | 		{ | ||||||
|  | 			object: &extensionsv1beta1.ReplicaSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: extensionsv1beta1.ReplicaSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "extensions", apiVersion: "v1beta1", | ||||||
|  | 			args: []string{"replicaset", "nginx", "*=thingy"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1beta2.ReplicaSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1beta2.ReplicaSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta2", | ||||||
|  | 			args: []string{"replicaset", "nginx", "*=thingy"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1.ReplicaSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1.ReplicaSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1", | ||||||
|  | 			args: []string{"replicaset", "nginx", "*=thingy"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &extensionsv1beta1.DaemonSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: extensionsv1beta1.DaemonSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "extensions", apiVersion: "v1beta1", | ||||||
|  | 			args: []string{"daemonset", "nginx", "*=thingy"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1beta2.DaemonSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1beta2.DaemonSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta2", | ||||||
|  | 			args: []string{"daemonset", "nginx", "*=thingy"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1.DaemonSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1.DaemonSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1", | ||||||
|  | 			args: []string{"daemonset", "nginx", "*=thingy"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &extensionsv1beta1.Deployment{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: extensionsv1beta1.DeploymentSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "extensions", apiVersion: "v1beta1", | ||||||
|  | 			args: []string{"deployment", "nginx", "*=thingy"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1beta1.Deployment{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1beta1.DeploymentSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta1", | ||||||
|  | 			args: []string{"deployment", "nginx", "*=thingy"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1beta2.Deployment{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1beta2.DeploymentSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta2", | ||||||
|  | 			args: []string{"deployment", "nginx", "*=thingy"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1.Deployment{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1.DeploymentSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1", | ||||||
|  | 			args: []string{"deployment", "nginx", "*=thingy"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1beta1.StatefulSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1beta1.StatefulSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "apps", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta1", | ||||||
|  | 			args: []string{"statefulset", "nginx", "*=thingy"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1beta2.StatefulSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1beta2.StatefulSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "apps", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta2", | ||||||
|  | 			args: []string{"statefulset", "nginx", "*=thingy"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1.StatefulSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1.StatefulSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "apps", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1", | ||||||
|  | 			args: []string{"statefulset", "nginx", "*=thingy"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &batchv1.Job{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: batchv1.JobSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "batch", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "batch", apiVersion: "v1", | ||||||
|  | 			args: []string{"job", "nginx", "*=thingy"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &v1.ReplicationController{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: v1.ReplicationControllerSpec{ | ||||||
|  | 					Template: &v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "", | ||||||
|  | 			apiPrefix:    "/api", apiGroup: "", apiVersion: "v1", | ||||||
|  | 			args: []string{"replicationcontroller", "nginx", "*=thingy"}, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	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) | ||||||
|  | 		tf.Printer = printers.NewVersionedPrinter(&printers.YAMLPrinter{}, testapi.Default.Converter(), *testapi.Default.GroupVersion()) | ||||||
|  | 		tf.Namespace = "test" | ||||||
|  | 		tf.CategoryExpander = resource.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), `"image":`+`"`+"thingy"+`"`, fmt.Sprintf("image 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", "image", req.Method, req.URL, req) | ||||||
|  | 					return nil, fmt.Errorf("unexpected request") | ||||||
|  | 				} | ||||||
|  | 			}), | ||||||
|  | 			VersionedAPIPath: path.Join(input.apiPrefix, testapi.Default.GroupVersion().String()), | ||||||
|  | 		} | ||||||
|  | 		out := new(bytes.Buffer) | ||||||
|  | 		cmd := NewCmdImage(f, out, out) | ||||||
|  | 		cmd.SetOutput(out) | ||||||
|  | 		cmd.Flags().Set("output", "yaml") | ||||||
|  | 		opts := ImageOptions{ | ||||||
|  | 			Out:   out, | ||||||
|  | 			Local: false} | ||||||
|  | 		err := opts.Complete(f, cmd, input.args) | ||||||
|  | 		assert.NoError(t, err) | ||||||
|  | 		err = opts.Run() | ||||||
|  | 		assert.NoError(t, err) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|   | |||||||
| @@ -22,13 +22,12 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
| 	"github.com/spf13/cobra" | 	"github.com/spf13/cobra" | ||||||
|  | 	"k8s.io/api/core/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/api/meta" | 	"k8s.io/apimachinery/pkg/api/meta" | ||||||
| 	api "k8s.io/kubernetes/pkg/apis/core" |  | ||||||
|  |  | ||||||
| 	"k8s.io/apimachinery/pkg/runtime" | 	"k8s.io/apimachinery/pkg/runtime" | ||||||
| 	"k8s.io/apimachinery/pkg/types" | 	"k8s.io/apimachinery/pkg/types" | ||||||
| 	utilerrors "k8s.io/apimachinery/pkg/util/errors" | 	utilerrors "k8s.io/apimachinery/pkg/util/errors" | ||||||
| 	"k8s.io/kubernetes/pkg/api/legacyscheme" |  | ||||||
| 	"k8s.io/kubernetes/pkg/kubectl" | 	"k8s.io/kubernetes/pkg/kubectl" | ||||||
| 	"k8s.io/kubernetes/pkg/kubectl/cmd/templates" | 	"k8s.io/kubernetes/pkg/kubectl/cmd/templates" | ||||||
| 	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" | 	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" | ||||||
| @@ -64,7 +63,6 @@ type ResourcesOptions struct { | |||||||
| 	resource.FilenameOptions | 	resource.FilenameOptions | ||||||
|  |  | ||||||
| 	Mapper            meta.RESTMapper | 	Mapper            meta.RESTMapper | ||||||
| 	Typer             runtime.ObjectTyper |  | ||||||
| 	Infos             []*resource.Info | 	Infos             []*resource.Info | ||||||
| 	Encoder           runtime.Encoder | 	Encoder           runtime.Encoder | ||||||
| 	Out               io.Writer | 	Out               io.Writer | ||||||
| @@ -80,10 +78,10 @@ type ResourcesOptions struct { | |||||||
|  |  | ||||||
| 	Limits               string | 	Limits               string | ||||||
| 	Requests             string | 	Requests             string | ||||||
| 	ResourceRequirements api.ResourceRequirements | 	ResourceRequirements v1.ResourceRequirements | ||||||
|  |  | ||||||
| 	PrintObject            func(cmd *cobra.Command, isLocal bool, mapper meta.RESTMapper, obj runtime.Object, out io.Writer) error | 	PrintObject            func(cmd *cobra.Command, isLocal bool, mapper meta.RESTMapper, obj runtime.Object, out io.Writer) error | ||||||
| 	UpdatePodSpecForObject func(obj runtime.Object, fn func(*api.PodSpec) error) (bool, error) | 	UpdatePodSpecForObject func(obj runtime.Object, fn func(*v1.PodSpec) error) (bool, error) | ||||||
| 	Resources              []string | 	Resources              []string | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -128,7 +126,7 @@ func NewCmdResources(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra. | |||||||
| } | } | ||||||
|  |  | ||||||
| func (o *ResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { | func (o *ResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { | ||||||
| 	o.Mapper, o.Typer = f.Object() | 	o.Mapper, _ = f.Object() | ||||||
| 	o.UpdatePodSpecForObject = f.UpdatePodSpecForObject | 	o.UpdatePodSpecForObject = f.UpdatePodSpecForObject | ||||||
| 	o.Encoder = f.JSONEncoder() | 	o.Encoder = f.JSONEncoder() | ||||||
| 	o.Output = cmdutil.GetFlagString(cmd, "output") | 	o.Output = cmdutil.GetFlagString(cmd, "output") | ||||||
| @@ -180,7 +178,7 @@ func (o *ResourcesOptions) Validate() error { | |||||||
| 		return fmt.Errorf("you must specify an update to requests or limits (in the form of --requests/--limits)") | 		return fmt.Errorf("you must specify an update to requests or limits (in the form of --requests/--limits)") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	o.ResourceRequirements, err = kubectl.HandleResourceRequirements(map[string]string{"limits": o.Limits, "requests": o.Requests}) | 	o.ResourceRequirements, err = kubectl.HandleResourceRequirementsV1(map[string]string{"limits": o.Limits, "requests": o.Requests}) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| @@ -192,19 +190,19 @@ func (o *ResourcesOptions) Run() error { | |||||||
| 	allErrs := []error{} | 	allErrs := []error{} | ||||||
| 	patches := CalculatePatches(o.Infos, o.Encoder, func(info *resource.Info) ([]byte, error) { | 	patches := CalculatePatches(o.Infos, o.Encoder, func(info *resource.Info) ([]byte, error) { | ||||||
| 		transformed := false | 		transformed := false | ||||||
| 		_, err := o.UpdatePodSpecForObject(info.Object, func(spec *api.PodSpec) error { | 		_, err := o.UpdatePodSpecForObject(info.VersionedObject, func(spec *v1.PodSpec) error { | ||||||
| 			containers, _ := selectContainers(spec.Containers, o.ContainerSelector) | 			containers, _ := selectContainers(spec.Containers, o.ContainerSelector) | ||||||
| 			if len(containers) != 0 { | 			if len(containers) != 0 { | ||||||
| 				for i := range containers { | 				for i := range containers { | ||||||
| 					if len(o.Limits) != 0 && len(containers[i].Resources.Limits) == 0 { | 					if len(o.Limits) != 0 && len(containers[i].Resources.Limits) == 0 { | ||||||
| 						containers[i].Resources.Limits = make(api.ResourceList) | 						containers[i].Resources.Limits = make(v1.ResourceList) | ||||||
| 					} | 					} | ||||||
| 					for key, value := range o.ResourceRequirements.Limits { | 					for key, value := range o.ResourceRequirements.Limits { | ||||||
| 						containers[i].Resources.Limits[key] = value | 						containers[i].Resources.Limits[key] = value | ||||||
| 					} | 					} | ||||||
|  |  | ||||||
| 					if len(o.Requests) != 0 && len(containers[i].Resources.Requests) == 0 { | 					if len(o.Requests) != 0 && len(containers[i].Resources.Requests) == 0 { | ||||||
| 						containers[i].Resources.Requests = make(api.ResourceList) | 						containers[i].Resources.Requests = make(v1.ResourceList) | ||||||
| 					} | 					} | ||||||
| 					for key, value := range o.ResourceRequirements.Requests { | 					for key, value := range o.ResourceRequirements.Requests { | ||||||
| 						containers[i].Resources.Requests[key] = value | 						containers[i].Resources.Requests[key] = value | ||||||
| @@ -217,9 +215,7 @@ func (o *ResourcesOptions) Run() error { | |||||||
| 			return nil | 			return nil | ||||||
| 		}) | 		}) | ||||||
| 		if transformed && err == nil { | 		if transformed && err == nil { | ||||||
| 			// TODO: switch UpdatePodSpecForObject to work on v1.PodSpec, use info.VersionedObject, and avoid conversion completely | 			return runtime.Encode(o.Encoder, info.VersionedObject) | ||||||
| 			versionedEncoder := legacyscheme.Codecs.EncoderForVersion(o.Encoder, info.Mapping.GroupVersionKind.GroupVersion()) |  | ||||||
| 			return runtime.Encode(versionedEncoder, info.Object) |  | ||||||
| 		} | 		} | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	}) | 	}) | ||||||
| @@ -238,7 +234,7 @@ func (o *ResourcesOptions) Run() error { | |||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		if o.Local || cmdutil.GetDryRunFlag(o.Cmd) { | 		if o.Local || cmdutil.GetDryRunFlag(o.Cmd) { | ||||||
| 			if err := o.PrintObject(o.Cmd, o.Local, o.Mapper, info.Object, o.Out); err != nil { | 			if err := o.PrintObject(o.Cmd, o.Local, o.Mapper, patch.Info.VersionedObject, o.Out); err != nil { | ||||||
| 				return err | 				return err | ||||||
| 			} | 			} | ||||||
| 			continue | 			continue | ||||||
| @@ -263,7 +259,14 @@ func (o *ResourcesOptions) Run() error { | |||||||
|  |  | ||||||
| 		shortOutput := o.Output == "name" | 		shortOutput := o.Output == "name" | ||||||
| 		if len(o.Output) > 0 && !shortOutput { | 		if len(o.Output) > 0 && !shortOutput { | ||||||
| 			return o.PrintObject(o.Cmd, o.Local, o.Mapper, info.Object, o.Out) | 			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 { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 			continue | ||||||
| 		} | 		} | ||||||
| 		cmdutil.PrintSuccess(o.Mapper, shortOutput, o.Out, info.Mapping.Resource, info.Name, false, "resource requirements updated") | 		cmdutil.PrintSuccess(o.Mapper, shortOutput, o.Out, info.Mapping.Resource, info.Name, false, "resource requirements updated") | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -18,24 +18,36 @@ package set | |||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"bytes" | 	"bytes" | ||||||
|  | 	"fmt" | ||||||
|  | 	"io/ioutil" | ||||||
| 	"net/http" | 	"net/http" | ||||||
|  | 	"path" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | 	appsv1 "k8s.io/api/apps/v1" | ||||||
|  | 	appsv1beta1 "k8s.io/api/apps/v1beta1" | ||||||
|  | 	appsv1beta2 "k8s.io/api/apps/v1beta2" | ||||||
|  | 	batchv1 "k8s.io/api/batch/v1" | ||||||
|  | 	"k8s.io/api/core/v1" | ||||||
|  | 	extensionsv1beta1 "k8s.io/api/extensions/v1beta1" | ||||||
|  | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/runtime" | 	"k8s.io/apimachinery/pkg/runtime" | ||||||
|  | 	"k8s.io/apimachinery/pkg/runtime/schema" | ||||||
| 	restclient "k8s.io/client-go/rest" | 	restclient "k8s.io/client-go/rest" | ||||||
| 	"k8s.io/client-go/rest/fake" | 	"k8s.io/client-go/rest/fake" | ||||||
| 	"k8s.io/kubernetes/pkg/api/legacyscheme" | 	"k8s.io/kubernetes/pkg/api/testapi" | ||||||
| 	api "k8s.io/kubernetes/pkg/apis/core" |  | ||||||
| 	cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" | 	cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" | ||||||
| 	"k8s.io/kubernetes/pkg/kubectl/resource" | 	"k8s.io/kubernetes/pkg/kubectl/resource" | ||||||
|  | 	"k8s.io/kubernetes/pkg/kubectl/scheme" | ||||||
| 	"k8s.io/kubernetes/pkg/printers" | 	"k8s.io/kubernetes/pkg/printers" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| func TestResourcesLocal(t *testing.T) { | func TestResourcesLocal(t *testing.T) { | ||||||
| 	f, tf, codec, ns := cmdtesting.NewAPIFactory() | 	f, tf, codec, ns := cmdtesting.NewAPIFactory() | ||||||
| 	tf.Client = &fake.RESTClient{ | 	tf.Client = &fake.RESTClient{ | ||||||
| 		GroupVersion:         legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, | 		GroupVersion:         schema.GroupVersion{Version: ""}, | ||||||
| 		NegotiatedSerializer: ns, | 		NegotiatedSerializer: ns, | ||||||
| 		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | 		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | ||||||
| 			t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) | 			t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) | ||||||
| @@ -43,7 +55,7 @@ func TestResourcesLocal(t *testing.T) { | |||||||
| 		}), | 		}), | ||||||
| 	} | 	} | ||||||
| 	tf.Namespace = "test" | 	tf.Namespace = "test" | ||||||
| 	tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion}} | 	tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}} | ||||||
|  |  | ||||||
| 	buf := bytes.NewBuffer([]byte{}) | 	buf := bytes.NewBuffer([]byte{}) | ||||||
| 	cmd := NewCmdResources(f, buf, buf) | 	cmd := NewCmdResources(f, buf, buf) | ||||||
| @@ -79,7 +91,7 @@ func TestResourcesLocal(t *testing.T) { | |||||||
| func TestSetMultiResourcesLimitsLocal(t *testing.T) { | func TestSetMultiResourcesLimitsLocal(t *testing.T) { | ||||||
| 	f, tf, codec, ns := cmdtesting.NewAPIFactory() | 	f, tf, codec, ns := cmdtesting.NewAPIFactory() | ||||||
| 	tf.Client = &fake.RESTClient{ | 	tf.Client = &fake.RESTClient{ | ||||||
| 		GroupVersion:         legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, | 		GroupVersion:         schema.GroupVersion{Version: ""}, | ||||||
| 		NegotiatedSerializer: ns, | 		NegotiatedSerializer: ns, | ||||||
| 		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | 		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | ||||||
| 			t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) | 			t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) | ||||||
| @@ -87,7 +99,7 @@ func TestSetMultiResourcesLimitsLocal(t *testing.T) { | |||||||
| 		}), | 		}), | ||||||
| 	} | 	} | ||||||
| 	tf.Namespace = "test" | 	tf.Namespace = "test" | ||||||
| 	tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion}} | 	tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}} | ||||||
|  |  | ||||||
| 	buf := bytes.NewBuffer([]byte{}) | 	buf := bytes.NewBuffer([]byte{}) | ||||||
| 	cmd := NewCmdResources(f, buf, buf) | 	cmd := NewCmdResources(f, buf, buf) | ||||||
| @@ -120,3 +132,366 @@ func TestSetMultiResourcesLimitsLocal(t *testing.T) { | |||||||
| 		t.Errorf("expected out:\n%s\nbut got:\n%s", expectedOut, buf.String()) | 		t.Errorf("expected out:\n%s\nbut got:\n%s", expectedOut, buf.String()) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func TestSetResourcesRemote(t *testing.T) { | ||||||
|  | 	inputs := []struct { | ||||||
|  | 		object                          runtime.Object | ||||||
|  | 		apiPrefix, apiGroup, apiVersion string | ||||||
|  | 		testAPIGroup                    string | ||||||
|  | 		args                            []string | ||||||
|  | 	}{ | ||||||
|  | 		{ | ||||||
|  | 			object: &extensionsv1beta1.ReplicaSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: extensionsv1beta1.ReplicaSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "extensions", apiVersion: "v1beta1", | ||||||
|  | 			args: []string{"replicaset", "nginx"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1beta2.ReplicaSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1beta2.ReplicaSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta2", | ||||||
|  | 			args: []string{"replicaset", "nginx"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1.ReplicaSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1.ReplicaSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1", | ||||||
|  | 			args: []string{"replicaset", "nginx"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &extensionsv1beta1.DaemonSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: extensionsv1beta1.DaemonSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "extensions", apiVersion: "v1beta1", | ||||||
|  | 			args: []string{"daemonset", "nginx"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1beta2.DaemonSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1beta2.DaemonSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta2", | ||||||
|  | 			args: []string{"daemonset", "nginx"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1.DaemonSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1.DaemonSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1", | ||||||
|  | 			args: []string{"daemonset", "nginx"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &extensionsv1beta1.Deployment{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: extensionsv1beta1.DeploymentSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "extensions", apiVersion: "v1beta1", | ||||||
|  | 			args: []string{"deployment", "nginx"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1beta1.Deployment{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1beta1.DeploymentSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta1", | ||||||
|  | 			args: []string{"deployment", "nginx"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1beta2.Deployment{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1beta2.DeploymentSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta2", | ||||||
|  | 			args: []string{"deployment", "nginx"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1.Deployment{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1.DeploymentSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1", | ||||||
|  | 			args: []string{"deployment", "nginx"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1beta1.StatefulSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1beta1.StatefulSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "apps", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta1", | ||||||
|  | 			args: []string{"statefulset", "nginx"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1beta2.StatefulSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1beta2.StatefulSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "apps", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta2", | ||||||
|  | 			args: []string{"statefulset", "nginx"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1.StatefulSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1.StatefulSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "apps", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1", | ||||||
|  | 			args: []string{"statefulset", "nginx"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &batchv1.Job{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: batchv1.JobSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "batch", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "batch", apiVersion: "v1", | ||||||
|  | 			args: []string{"job", "nginx"}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &v1.ReplicationController{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: v1.ReplicationControllerSpec{ | ||||||
|  | 					Template: &v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "", | ||||||
|  | 			apiPrefix:    "/api", apiGroup: "", apiVersion: "v1", | ||||||
|  | 			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 = resource.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") | ||||||
|  | 				} | ||||||
|  | 			}), | ||||||
|  | 			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) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|   | |||||||
| @@ -23,11 +23,11 @@ import ( | |||||||
|  |  | ||||||
| 	"github.com/spf13/cobra" | 	"github.com/spf13/cobra" | ||||||
|  |  | ||||||
|  | 	"k8s.io/api/core/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/api/meta" | 	"k8s.io/apimachinery/pkg/api/meta" | ||||||
| 	"k8s.io/apimachinery/pkg/runtime" | 	"k8s.io/apimachinery/pkg/runtime" | ||||||
| 	"k8s.io/apimachinery/pkg/types" | 	"k8s.io/apimachinery/pkg/types" | ||||||
| 	utilerrors "k8s.io/apimachinery/pkg/util/errors" | 	utilerrors "k8s.io/apimachinery/pkg/util/errors" | ||||||
| 	api "k8s.io/kubernetes/pkg/apis/core" |  | ||||||
| 	"k8s.io/kubernetes/pkg/kubectl/cmd/templates" | 	"k8s.io/kubernetes/pkg/kubectl/cmd/templates" | ||||||
| 	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" | 	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" | ||||||
| 	"k8s.io/kubernetes/pkg/kubectl/resource" | 	"k8s.io/kubernetes/pkg/kubectl/resource" | ||||||
| @@ -61,14 +61,15 @@ type serviceAccountConfig struct { | |||||||
| 	out                    io.Writer | 	out                    io.Writer | ||||||
| 	err                    io.Writer | 	err                    io.Writer | ||||||
| 	dryRun                 bool | 	dryRun                 bool | ||||||
|  | 	cmd                    *cobra.Command | ||||||
| 	shortOutput            bool | 	shortOutput            bool | ||||||
| 	all                    bool | 	all                    bool | ||||||
| 	record                 bool | 	record                 bool | ||||||
| 	output                 string | 	output                 string | ||||||
| 	changeCause            string | 	changeCause            string | ||||||
| 	local                  bool | 	local                  bool | ||||||
| 	saPrint                func(obj runtime.Object) error | 	PrintObject            func(cmd *cobra.Command, isLocal bool, mapper meta.RESTMapper, obj runtime.Object, out io.Writer) error | ||||||
| 	updatePodSpecForObject func(runtime.Object, func(*api.PodSpec) error) (bool, error) | 	updatePodSpecForObject func(runtime.Object, func(*v1.PodSpec) error) (bool, error) | ||||||
| 	infos                  []*resource.Info | 	infos                  []*resource.Info | ||||||
| 	serviceAccountName     string | 	serviceAccountName     string | ||||||
| } | } | ||||||
| @@ -113,9 +114,9 @@ func (saConfig *serviceAccountConfig) Complete(f cmdutil.Factory, cmd *cobra.Com | |||||||
| 	saConfig.dryRun = cmdutil.GetDryRunFlag(cmd) | 	saConfig.dryRun = cmdutil.GetDryRunFlag(cmd) | ||||||
| 	saConfig.output = cmdutil.GetFlagString(cmd, "output") | 	saConfig.output = cmdutil.GetFlagString(cmd, "output") | ||||||
| 	saConfig.updatePodSpecForObject = f.UpdatePodSpecForObject | 	saConfig.updatePodSpecForObject = f.UpdatePodSpecForObject | ||||||
| 	saConfig.saPrint = func(obj runtime.Object) error { | 	saConfig.PrintObject = f.PrintObject | ||||||
| 		return f.PrintObject(cmd, saConfig.local, saConfig.mapper, obj, saConfig.out) | 	saConfig.cmd = cmd | ||||||
| 	} |  | ||||||
| 	cmdNamespace, enforceNamespace, err := f.DefaultNamespace() | 	cmdNamespace, enforceNamespace, err := f.DefaultNamespace() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| @@ -148,11 +149,11 @@ func (saConfig *serviceAccountConfig) Complete(f cmdutil.Factory, cmd *cobra.Com | |||||||
| func (saConfig *serviceAccountConfig) Run() error { | func (saConfig *serviceAccountConfig) Run() error { | ||||||
| 	patchErrs := []error{} | 	patchErrs := []error{} | ||||||
| 	patchFn := func(info *resource.Info) ([]byte, error) { | 	patchFn := func(info *resource.Info) ([]byte, error) { | ||||||
| 		saConfig.updatePodSpecForObject(info.Object, func(podSpec *api.PodSpec) error { | 		saConfig.updatePodSpecForObject(info.VersionedObject, func(podSpec *v1.PodSpec) error { | ||||||
| 			podSpec.ServiceAccountName = saConfig.serviceAccountName | 			podSpec.ServiceAccountName = saConfig.serviceAccountName | ||||||
| 			return nil | 			return nil | ||||||
| 		}) | 		}) | ||||||
| 		return runtime.Encode(saConfig.encoder, info.Object) | 		return runtime.Encode(saConfig.encoder, info.VersionedObject) | ||||||
| 	} | 	} | ||||||
| 	patches := CalculatePatches(saConfig.infos, saConfig.encoder, patchFn) | 	patches := CalculatePatches(saConfig.infos, saConfig.encoder, patchFn) | ||||||
| 	for _, patch := range patches { | 	for _, patch := range patches { | ||||||
| @@ -162,7 +163,9 @@ func (saConfig *serviceAccountConfig) Run() error { | |||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
| 		if saConfig.local || saConfig.dryRun { | 		if saConfig.local || saConfig.dryRun { | ||||||
| 			saConfig.saPrint(patch.Info.Object) | 			if err := saConfig.PrintObject(saConfig.cmd, saConfig.local, saConfig.mapper, patch.Info.VersionedObject, saConfig.out); err != nil { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
| 			continue | 			continue | ||||||
| 		} | 		} | ||||||
| 		patched, err := resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, types.StrategicMergePatchType, patch.Patch) | 		patched, err := resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, types.StrategicMergePatchType, patch.Patch) | ||||||
| @@ -179,7 +182,14 @@ func (saConfig *serviceAccountConfig) Run() error { | |||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		if len(saConfig.output) > 0 { | 		if len(saConfig.output) > 0 { | ||||||
| 			saConfig.saPrint(patched) | 			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 { | ||||||
|  | 				return err | ||||||
|  | 			} | ||||||
|  | 			continue | ||||||
| 		} | 		} | ||||||
| 		cmdutil.PrintSuccess(saConfig.mapper, saConfig.shortOutput, saConfig.out, info.Mapping.Resource, info.Name, saConfig.dryRun, "serviceaccount updated") | 		cmdutil.PrintSuccess(saConfig.mapper, saConfig.shortOutput, saConfig.out, info.Mapping.Resource, info.Name, saConfig.dryRun, "serviceaccount updated") | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -26,19 +26,21 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
|  |  | ||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
|  | 	appsv1 "k8s.io/api/apps/v1" | ||||||
|  | 	appsv1beta1 "k8s.io/api/apps/v1beta1" | ||||||
|  | 	appsv1beta2 "k8s.io/api/apps/v1beta2" | ||||||
|  | 	batchv1 "k8s.io/api/batch/v1" | ||||||
|  | 	"k8s.io/api/core/v1" | ||||||
|  | 	extensionsv1beta1 "k8s.io/api/extensions/v1beta1" | ||||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/runtime" | 	"k8s.io/apimachinery/pkg/runtime" | ||||||
| 	"k8s.io/apimachinery/pkg/runtime/schema" | 	"k8s.io/apimachinery/pkg/runtime/schema" | ||||||
|  | 	restclient "k8s.io/client-go/rest" | ||||||
| 	"k8s.io/client-go/rest/fake" | 	"k8s.io/client-go/rest/fake" | ||||||
| 	"k8s.io/kubernetes/pkg/api/legacyscheme" |  | ||||||
| 	"k8s.io/kubernetes/pkg/api/testapi" | 	"k8s.io/kubernetes/pkg/api/testapi" | ||||||
| 	"k8s.io/kubernetes/pkg/apis/apps" |  | ||||||
| 	"k8s.io/kubernetes/pkg/apis/batch" |  | ||||||
| 	api "k8s.io/kubernetes/pkg/apis/core" |  | ||||||
| 	"k8s.io/kubernetes/pkg/apis/extensions" |  | ||||||
| 	cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" | 	cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" | ||||||
| 	"k8s.io/kubernetes/pkg/kubectl/resource" | 	"k8s.io/kubernetes/pkg/kubectl/resource" | ||||||
|  | 	"k8s.io/kubernetes/pkg/kubectl/scheme" | ||||||
| 	"k8s.io/kubernetes/pkg/printers" | 	"k8s.io/kubernetes/pkg/printers" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| @@ -51,22 +53,21 @@ Example resource specifications include: | |||||||
|    '<resource> <name>' |    '<resource> <name>' | ||||||
|    '<resource>'` |    '<resource>'` | ||||||
|  |  | ||||||
| func TestServiceAccountLocal(t *testing.T) { | func TestSetServiceAccountLocal(t *testing.T) { | ||||||
| 	inputs := []struct { | 	inputs := []struct { | ||||||
| 		yaml     string | 		yaml     string | ||||||
| 		apiGroup string | 		apiGroup string | ||||||
| 	}{ | 	}{ | ||||||
| 		{yaml: "../../../../test/fixtures/doc-yaml/user-guide/replication.yaml", apiGroup: api.GroupName}, | 		{yaml: "../../../../test/fixtures/doc-yaml/user-guide/replication.yaml", apiGroup: ""}, | ||||||
| 		{yaml: "../../../../test/fixtures/doc-yaml/admin/daemon.yaml", apiGroup: extensions.GroupName}, | 		{yaml: "../../../../test/fixtures/doc-yaml/admin/daemon.yaml", apiGroup: "extensions"}, | ||||||
| 		{yaml: "../../../../test/fixtures/doc-yaml/user-guide/replicaset/redis-slave.yaml", apiGroup: extensions.GroupName}, | 		{yaml: "../../../../test/fixtures/doc-yaml/user-guide/replicaset/redis-slave.yaml", apiGroup: "extensions"}, | ||||||
| 		{yaml: "../../../../test/fixtures/doc-yaml/user-guide/job.yaml", apiGroup: batch.GroupName}, | 		{yaml: "../../../../test/fixtures/doc-yaml/user-guide/job.yaml", apiGroup: "batch"}, | ||||||
| 		{yaml: "../../../../test/fixtures/doc-yaml/user-guide/deployment.yaml", apiGroup: extensions.GroupName}, | 		{yaml: "../../../../test/fixtures/doc-yaml/user-guide/deployment.yaml", apiGroup: "extensions"}, | ||||||
| 		{yaml: "../../../../examples/storage/minio/minio-distributed-statefulset.yaml", apiGroup: apps.GroupName}, |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	f, tf, _, _ := cmdtesting.NewAPIFactory() | 	f, tf, _, _ := cmdtesting.NewAPIFactory() | ||||||
| 	tf.Client = &fake.RESTClient{ | 	tf.Client = &fake.RESTClient{ | ||||||
| 		GroupVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion, | 		GroupVersion: schema.GroupVersion{Version: "v1"}, | ||||||
| 		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | 		Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | ||||||
| 			t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) | 			t.Fatalf("unexpected request: %s %#v\n%#v", req.Method, req.URL, req) | ||||||
| 			return nil, nil | 			return nil, nil | ||||||
| @@ -93,71 +94,232 @@ func TestServiceAccountLocal(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestServiceAccountRemote(t *testing.T) { | func TestSetServiceAccountMultiLocal(t *testing.T) { | ||||||
|  | 	testapi.Default = testapi.Groups[""] | ||||||
|  | 	f, tf, codec, ns := cmdtesting.NewAPIFactory() | ||||||
|  | 	tf.Client = &fake.RESTClient{ | ||||||
|  | 		GroupVersion:         schema.GroupVersion{Version: ""}, | ||||||
|  | 		NegotiatedSerializer: ns, | ||||||
|  | 		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" | ||||||
|  | 	tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}} | ||||||
|  |  | ||||||
|  | 	buf := bytes.NewBuffer([]byte{}) | ||||||
|  | 	cmd := NewCmdServiceAccount(f, buf, buf) | ||||||
|  | 	cmd.SetOutput(buf) | ||||||
|  | 	cmd.Flags().Set("output", "name") | ||||||
|  | 	cmd.Flags().Set("local", "true") | ||||||
|  | 	mapper, typer := f.Object() | ||||||
|  | 	tf.Printer = &printers.NamePrinter{Decoders: []runtime.Decoder{codec}, Typer: typer, Mapper: mapper} | ||||||
|  | 	opts := serviceAccountConfig{fileNameOptions: resource.FilenameOptions{ | ||||||
|  | 		Filenames: []string{"../../../../test/fixtures/pkg/kubectl/cmd/set/multi-resource-yaml.yaml"}}, | ||||||
|  | 		out:   buf, | ||||||
|  | 		local: true} | ||||||
|  |  | ||||||
|  | 	err := opts.Complete(f, cmd, []string{serviceAccount}) | ||||||
|  | 	if err == nil { | ||||||
|  | 		err = opts.Run() | ||||||
|  | 	} | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("unexpected error: %v", err) | ||||||
|  | 	} | ||||||
|  | 	expectedOut := "replicationcontrollers/first-rc\nreplicationcontrollers/second-rc\n" | ||||||
|  | 	if buf.String() != expectedOut { | ||||||
|  | 		t.Errorf("expected out:\n%s\nbut got:\n%s", expectedOut, buf.String()) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestSetServiceAccountRemote(t *testing.T) { | ||||||
| 	inputs := []struct { | 	inputs := []struct { | ||||||
| 		object              runtime.Object | 		object                          runtime.Object | ||||||
| 		apiPrefix, apiGroup string | 		apiPrefix, apiGroup, apiVersion string | ||||||
| 		args                []string | 		testAPIGroup                    string | ||||||
|  | 		args                            []string | ||||||
| 	}{ | 	}{ | ||||||
| 		{ | 		{ | ||||||
| 			object: &extensions.ReplicaSet{ | 			object: &extensionsv1beta1.ReplicaSet{ | ||||||
| 				TypeMeta:   metav1.TypeMeta{Kind: "ReplicaSet", APIVersion: legacyscheme.Registry.GroupOrDie(extensions.GroupName).GroupVersion.String()}, |  | ||||||
| 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
| 			}, | 			}, | ||||||
| 			apiPrefix: "/apis", apiGroup: extensions.GroupName, | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "extensions", apiVersion: "v1beta1", | ||||||
| 			args: []string{"replicaset", "nginx", serviceAccount}, | 			args: []string{"replicaset", "nginx", serviceAccount}, | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			object: &extensions.DaemonSet{ | 			object: &appsv1beta2.ReplicaSet{ | ||||||
| 				TypeMeta:   metav1.TypeMeta{Kind: "DaemonSet", APIVersion: legacyscheme.Registry.GroupOrDie(extensions.GroupName).GroupVersion.String()}, | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1beta2.ReplicaSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta2", | ||||||
|  | 			args: []string{"replicaset", "nginx", serviceAccount}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1.ReplicaSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1.ReplicaSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1", | ||||||
|  | 			args: []string{"replicaset", "nginx", serviceAccount}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &extensionsv1beta1.DaemonSet{ | ||||||
| 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
| 			}, | 			}, | ||||||
| 			apiPrefix: "/apis", apiGroup: extensions.GroupName, | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "extensions", apiVersion: "v1beta1", | ||||||
| 			args: []string{"daemonset", "nginx", serviceAccount}, | 			args: []string{"daemonset", "nginx", serviceAccount}, | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			object: &api.ReplicationController{ | 			object: &appsv1beta2.DaemonSet{ | ||||||
| 				TypeMeta:   metav1.TypeMeta{Kind: "ReplicationController", APIVersion: legacyscheme.Registry.GroupOrDie(api.GroupName).GroupVersion.String()}, |  | ||||||
| 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
| 			}, | 			}, | ||||||
| 			apiPrefix: "/api", apiGroup: api.GroupName, | 			testAPIGroup: "extensions", | ||||||
| 			args: []string{"replicationcontroller", "nginx", serviceAccount}}, | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta2", | ||||||
|  | 			args: []string{"daemonset", "nginx", serviceAccount}, | ||||||
|  | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			object: &extensions.Deployment{ | 			object: &appsv1.DaemonSet{ | ||||||
| 				TypeMeta:   metav1.TypeMeta{Kind: "Deployment", APIVersion: legacyscheme.Registry.GroupOrDie(extensions.GroupName).GroupVersion.String()}, |  | ||||||
| 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
| 			}, | 			}, | ||||||
| 			apiPrefix: "/apis", apiGroup: extensions.GroupName, | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1", | ||||||
|  | 			args: []string{"daemonset", "nginx", serviceAccount}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &extensionsv1beta1.Deployment{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "extensions", apiVersion: "v1beta1", | ||||||
| 			args: []string{"deployment", "nginx", serviceAccount}, | 			args: []string{"deployment", "nginx", serviceAccount}, | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			object: &batch.Job{ | 			object: &appsv1beta1.Deployment{ | ||||||
| 				TypeMeta:   metav1.TypeMeta{Kind: "Job", APIVersion: legacyscheme.Registry.GroupOrDie(batch.GroupName).GroupVersion.String()}, |  | ||||||
| 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
| 			}, | 			}, | ||||||
| 			apiPrefix: "/apis", apiGroup: batch.GroupName, | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta1", | ||||||
|  | 			args: []string{"deployment", "nginx", serviceAccount}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1beta2.Deployment{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta2", | ||||||
|  | 			args: []string{"deployment", "nginx", serviceAccount}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1.Deployment{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1.DeploymentSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "extensions", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1", | ||||||
|  | 			args: []string{"deployment", "nginx", serviceAccount}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1beta1.StatefulSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "apps", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta1", | ||||||
|  | 			args: []string{"statefulset", "nginx", serviceAccount}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1beta2.StatefulSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "apps", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1beta2", | ||||||
|  | 			args: []string{"statefulset", "nginx", serviceAccount}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &appsv1.StatefulSet{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 				Spec: appsv1.StatefulSetSpec{ | ||||||
|  | 					Template: v1.PodTemplateSpec{ | ||||||
|  | 						Spec: v1.PodSpec{ | ||||||
|  | 							Containers: []v1.Container{ | ||||||
|  | 								{ | ||||||
|  | 									Name:  "nginx", | ||||||
|  | 									Image: "nginx", | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "apps", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "apps", apiVersion: "v1", | ||||||
|  | 			args: []string{"statefulset", "nginx", serviceAccount}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			object: &batchv1.Job{ | ||||||
|  | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
|  | 			}, | ||||||
|  | 			testAPIGroup: "batch", | ||||||
|  | 			apiPrefix:    "/apis", apiGroup: "batch", apiVersion: "v1", | ||||||
| 			args: []string{"job", "nginx", serviceAccount}, | 			args: []string{"job", "nginx", serviceAccount}, | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			object: &apps.StatefulSet{ | 			object: &v1.ReplicationController{ | ||||||
| 				TypeMeta:   metav1.TypeMeta{Kind: "StatefulSet", APIVersion: legacyscheme.Registry.GroupOrDie(apps.GroupName).GroupVersion.String()}, |  | ||||||
| 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | 				ObjectMeta: metav1.ObjectMeta{Name: "nginx"}, | ||||||
| 			}, | 			}, | ||||||
| 			apiPrefix: "/apis", apiGroup: apps.GroupName, | 			testAPIGroup: "", | ||||||
| 			args: []string{"statefulset", "nginx", serviceAccount}, | 			apiPrefix:    "/api", apiGroup: "", apiVersion: "v1", | ||||||
|  | 			args: []string{"replicationcontroller", "nginx", serviceAccount}, | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 	for _, input := range inputs { | 	for _, input := range inputs { | ||||||
|  | 		groupVersion := schema.GroupVersion{Group: input.apiGroup, Version: input.apiVersion} | ||||||
| 		groupVersion := legacyscheme.Registry.GroupOrDie(input.apiGroup).GroupVersion | 		testapi.Default = testapi.Groups[input.testAPIGroup] | ||||||
| 		testapi.Default = testapi.Groups[input.apiGroup] | 		f, tf, _, ns := cmdtesting.NewAPIFactory() | ||||||
| 		f, tf, codec, _ := cmdtesting.NewAPIFactory() | 		codec := scheme.Codecs.CodecForVersions(scheme.Codecs.LegacyCodec(groupVersion), scheme.Codecs.UniversalDecoder(groupVersion), groupVersion, groupVersion) | ||||||
| 		tf.Printer = printers.NewVersionedPrinter(&printers.YAMLPrinter{}, testapi.Default.Converter(), *testapi.Default.GroupVersion()) | 		tf.Printer = printers.NewVersionedPrinter(&printers.YAMLPrinter{}, testapi.Default.Converter(), *testapi.Default.GroupVersion()) | ||||||
| 		tf.Namespace = "test" | 		tf.Namespace = "test" | ||||||
| 		tf.CategoryExpander = resource.LegacyCategoryExpander | 		tf.CategoryExpander = resource.LegacyCategoryExpander | ||||||
| 		tf.Client = &fake.RESTClient{ | 		tf.Client = &fake.RESTClient{ | ||||||
| 			GroupVersion:         legacyscheme.Registry.GroupOrDie(input.apiGroup).GroupVersion, | 			GroupVersion:         groupVersion, | ||||||
| 			NegotiatedSerializer: testapi.Default.NegotiatedSerializer(), | 			NegotiatedSerializer: ns, | ||||||
| 			Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | 			Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { | ||||||
| 				resourcePath := testapi.Default.ResourcePath(input.args[0]+"s", tf.Namespace, input.args[1]) | 				resourcePath := testapi.Default.ResourcePath(input.args[0]+"s", tf.Namespace, input.args[1]) | ||||||
| 				switch p, m := req.URL.Path, req.Method; { | 				switch p, m := req.URL.Path, req.Method; { | ||||||
| @@ -179,13 +341,12 @@ func TestServiceAccountRemote(t *testing.T) { | |||||||
| 					return nil, fmt.Errorf("unexpected request") | 					return nil, fmt.Errorf("unexpected request") | ||||||
| 				} | 				} | ||||||
| 			}), | 			}), | ||||||
| 			VersionedAPIPath: path.Join(input.apiPrefix, groupVersion.String()), | 			VersionedAPIPath: path.Join(input.apiPrefix, testapi.Default.GroupVersion().String()), | ||||||
| 		} | 		} | ||||||
| 		out := new(bytes.Buffer) | 		out := new(bytes.Buffer) | ||||||
| 		cmd := NewCmdServiceAccount(f, out, out) | 		cmd := NewCmdServiceAccount(f, out, out) | ||||||
| 		cmd.SetOutput(out) | 		cmd.SetOutput(out) | ||||||
| 		cmd.Flags().Set("output", "yaml") | 		cmd.Flags().Set("output", "yaml") | ||||||
|  |  | ||||||
| 		saConfig := serviceAccountConfig{ | 		saConfig := serviceAccountConfig{ | ||||||
| 			out:   out, | 			out:   out, | ||||||
| 			local: false} | 			local: false} | ||||||
|   | |||||||
| @@ -27,6 +27,7 @@ go_library( | |||||||
|         "//pkg/printers:go_default_library", |         "//pkg/printers:go_default_library", | ||||||
|         "//vendor/github.com/spf13/cobra:go_default_library", |         "//vendor/github.com/spf13/cobra:go_default_library", | ||||||
|         "//vendor/github.com/spf13/pflag:go_default_library", |         "//vendor/github.com/spf13/pflag:go_default_library", | ||||||
|  |         "//vendor/k8s.io/api/core/v1:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library", | ||||||
|   | |||||||
| @@ -26,6 +26,7 @@ import ( | |||||||
| 	"github.com/spf13/cobra" | 	"github.com/spf13/cobra" | ||||||
| 	"github.com/spf13/pflag" | 	"github.com/spf13/pflag" | ||||||
|  |  | ||||||
|  | 	"k8s.io/api/core/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/api/meta" | 	"k8s.io/apimachinery/pkg/api/meta" | ||||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | ||||||
| @@ -448,7 +449,7 @@ func (f *FakeFactory) ApproximatePodTemplateForObject(obj runtime.Object) (*api. | |||||||
| 	return f.ApproximatePodTemplateForObject(obj) | 	return f.ApproximatePodTemplateForObject(obj) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (f *FakeFactory) UpdatePodSpecForObject(obj runtime.Object, fn func(*api.PodSpec) error) (bool, error) { | func (f *FakeFactory) UpdatePodSpecForObject(obj runtime.Object, fn func(*v1.PodSpec) error) (bool, error) { | ||||||
| 	return false, nil | 	return false, nil | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -48,9 +48,13 @@ go_library( | |||||||
|         "//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library", |         "//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library", | ||||||
|         "//vendor/github.com/spf13/cobra:go_default_library", |         "//vendor/github.com/spf13/cobra:go_default_library", | ||||||
|         "//vendor/github.com/spf13/pflag:go_default_library", |         "//vendor/github.com/spf13/pflag:go_default_library", | ||||||
|  |         "//vendor/k8s.io/api/apps/v1:go_default_library", | ||||||
|         "//vendor/k8s.io/api/apps/v1beta1:go_default_library", |         "//vendor/k8s.io/api/apps/v1beta1:go_default_library", | ||||||
|  |         "//vendor/k8s.io/api/apps/v1beta2:go_default_library", | ||||||
|  |         "//vendor/k8s.io/api/batch/v1:go_default_library", | ||||||
|         "//vendor/k8s.io/api/batch/v2alpha1:go_default_library", |         "//vendor/k8s.io/api/batch/v2alpha1:go_default_library", | ||||||
|         "//vendor/k8s.io/api/core/v1:go_default_library", |         "//vendor/k8s.io/api/core/v1:go_default_library", | ||||||
|  |         "//vendor/k8s.io/api/extensions/v1beta1:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								pkg/kubectl/cmd/util/env/BUILD
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								pkg/kubectl/cmd/util/env/BUILD
									
									
									
									
										vendored
									
									
								
							| @@ -10,13 +10,13 @@ go_library( | |||||||
|     importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/util/env", |     importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/util/env", | ||||||
|     visibility = ["//visibility:public"], |     visibility = ["//visibility:public"], | ||||||
|     deps = [ |     deps = [ | ||||||
|         "//pkg/api/resource:go_default_library", |         "//pkg/api/v1/resource:go_default_library", | ||||||
|         "//pkg/apis/core:go_default_library", |  | ||||||
|         "//pkg/client/clientset_generated/internalclientset:go_default_library", |  | ||||||
|         "//pkg/fieldpath:go_default_library", |         "//pkg/fieldpath:go_default_library", | ||||||
|  |         "//vendor/k8s.io/api/core/v1:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", | ||||||
|  |         "//vendor/k8s.io/client-go/kubernetes:go_default_library", | ||||||
|     ], |     ], | ||||||
| ) | ) | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								pkg/kubectl/cmd/util/env/env_parse.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								pkg/kubectl/cmd/util/env/env_parse.go
									
									
									
									
										vendored
									
									
								
							| @@ -24,8 +24,8 @@ import ( | |||||||
| 	"regexp" | 	"regexp" | ||||||
| 	"strings" | 	"strings" | ||||||
|  |  | ||||||
|  | 	"k8s.io/api/core/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/util/sets" | 	"k8s.io/apimachinery/pkg/util/sets" | ||||||
| 	api "k8s.io/kubernetes/pkg/apis/core" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // Env returns an environment variable if not nil, or a default value. | // Env returns an environment variable if not nil, or a default value. | ||||||
| @@ -83,8 +83,8 @@ func SplitEnvironmentFromResources(args []string) (resources, envArgs []string, | |||||||
|  |  | ||||||
| // parseIntoEnvVar parses the list of key-value pairs into kubernetes EnvVar. | // parseIntoEnvVar parses the list of key-value pairs into kubernetes EnvVar. | ||||||
| // envVarType is for making errors more specific to user intentions. | // envVarType is for making errors more specific to user intentions. | ||||||
| func parseIntoEnvVar(spec []string, defaultReader io.Reader, envVarType string) ([]api.EnvVar, []string, error) { | func parseIntoEnvVar(spec []string, defaultReader io.Reader, envVarType string) ([]v1.EnvVar, []string, error) { | ||||||
| 	env := []api.EnvVar{} | 	env := []v1.EnvVar{} | ||||||
| 	exists := sets.NewString() | 	exists := sets.NewString() | ||||||
| 	var remove []string | 	var remove []string | ||||||
| 	for _, envSpec := range spec { | 	for _, envSpec := range spec { | ||||||
| @@ -106,7 +106,7 @@ func parseIntoEnvVar(spec []string, defaultReader io.Reader, envVarType string) | |||||||
| 				return nil, nil, fmt.Errorf("invalid %s: %v", envVarType, envSpec) | 				return nil, nil, fmt.Errorf("invalid %s: %v", envVarType, envSpec) | ||||||
| 			} | 			} | ||||||
| 			exists.Insert(parts[0]) | 			exists.Insert(parts[0]) | ||||||
| 			env = append(env, api.EnvVar{ | 			env = append(env, v1.EnvVar{ | ||||||
| 				Name:  parts[0], | 				Name:  parts[0], | ||||||
| 				Value: parts[1], | 				Value: parts[1], | ||||||
| 			}) | 			}) | ||||||
| @@ -126,12 +126,12 @@ func parseIntoEnvVar(spec []string, defaultReader io.Reader, envVarType string) | |||||||
|  |  | ||||||
| // ParseEnv parses the elements of the first argument looking for environment variables in key=value form and, if one of those values is "-", it also scans the reader. | // ParseEnv parses the elements of the first argument looking for environment variables in key=value form and, if one of those values is "-", it also scans the reader. | ||||||
| // The same environment variable cannot be both modified and removed in the same command. | // The same environment variable cannot be both modified and removed in the same command. | ||||||
| func ParseEnv(spec []string, defaultReader io.Reader) ([]api.EnvVar, []string, error) { | func ParseEnv(spec []string, defaultReader io.Reader) ([]v1.EnvVar, []string, error) { | ||||||
| 	return parseIntoEnvVar(spec, defaultReader, "environment variable") | 	return parseIntoEnvVar(spec, defaultReader, "environment variable") | ||||||
| } | } | ||||||
|  |  | ||||||
| func readEnv(r io.Reader, envVarType string) ([]api.EnvVar, error) { | func readEnv(r io.Reader, envVarType string) ([]v1.EnvVar, error) { | ||||||
| 	env := []api.EnvVar{} | 	env := []v1.EnvVar{} | ||||||
| 	scanner := bufio.NewScanner(r) | 	scanner := bufio.NewScanner(r) | ||||||
| 	for scanner.Scan() { | 	for scanner.Scan() { | ||||||
| 		envSpec := scanner.Text() | 		envSpec := scanner.Text() | ||||||
| @@ -143,7 +143,7 @@ func readEnv(r io.Reader, envVarType string) ([]api.EnvVar, error) { | |||||||
| 			if len(parts) != 2 { | 			if len(parts) != 2 { | ||||||
| 				return nil, fmt.Errorf("invalid %s: %v", envVarType, envSpec) | 				return nil, fmt.Errorf("invalid %s: %v", envVarType, envSpec) | ||||||
| 			} | 			} | ||||||
| 			env = append(env, api.EnvVar{ | 			env = append(env, v1.EnvVar{ | ||||||
| 				Name:  parts[0], | 				Name:  parts[0], | ||||||
| 				Value: parts[1], | 				Value: parts[1], | ||||||
| 			}) | 			}) | ||||||
|   | |||||||
							
								
								
									
										2
									
								
								pkg/kubectl/cmd/util/env/env_parse_test.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								pkg/kubectl/cmd/util/env/env_parse_test.go
									
									
									
									
										vendored
									
									
								
							| @@ -84,7 +84,7 @@ func ExampleParseEnv_good() { | |||||||
| 	ss := []string{"ENV=VARIABLE", "AND=ANOTHER", "REMOVE-", "-"} | 	ss := []string{"ENV=VARIABLE", "AND=ANOTHER", "REMOVE-", "-"} | ||||||
| 	fmt.Println(ParseEnv(ss, r)) | 	fmt.Println(ParseEnv(ss, r)) | ||||||
| 	// Output: | 	// Output: | ||||||
| 	// [{ENV VARIABLE <nil>} {AND ANOTHER <nil>} {FROM READER <nil>}] [REMOVE] <nil> | 	// [{ENV VARIABLE nil} {AND ANOTHER nil} {FROM READER nil}] [REMOVE] <nil> | ||||||
| } | } | ||||||
|  |  | ||||||
| func ExampleParseEnv_bad() { | func ExampleParseEnv_bad() { | ||||||
|   | |||||||
							
								
								
									
										26
									
								
								pkg/kubectl/cmd/util/env/env_resolve.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								pkg/kubectl/cmd/util/env/env_resolve.go
									
									
									
									
										vendored
									
									
								
							| @@ -19,30 +19,30 @@ package env | |||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  |  | ||||||
|  | 	"k8s.io/api/core/v1" | ||||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/runtime" | 	"k8s.io/apimachinery/pkg/runtime" | ||||||
| 	"k8s.io/kubernetes/pkg/api/resource" | 	"k8s.io/client-go/kubernetes" | ||||||
| 	api "k8s.io/kubernetes/pkg/apis/core" | 	"k8s.io/kubernetes/pkg/api/v1/resource" | ||||||
| 	clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" |  | ||||||
| 	"k8s.io/kubernetes/pkg/fieldpath" | 	"k8s.io/kubernetes/pkg/fieldpath" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| // ResourceStore defines a new resource store data structure. | // ResourceStore defines a new resource store data structure. | ||||||
| type ResourceStore struct { | type ResourceStore struct { | ||||||
| 	SecretStore    map[string]*api.Secret | 	SecretStore    map[string]*v1.Secret | ||||||
| 	ConfigMapStore map[string]*api.ConfigMap | 	ConfigMapStore map[string]*v1.ConfigMap | ||||||
| } | } | ||||||
|  |  | ||||||
| // NewResourceStore returns a pointer to a new resource store data structure. | // NewResourceStore returns a pointer to a new resource store data structure. | ||||||
| func NewResourceStore() *ResourceStore { | func NewResourceStore() *ResourceStore { | ||||||
| 	return &ResourceStore{ | 	return &ResourceStore{ | ||||||
| 		SecretStore:    make(map[string]*api.Secret), | 		SecretStore:    make(map[string]*v1.Secret), | ||||||
| 		ConfigMapStore: make(map[string]*api.ConfigMap), | 		ConfigMapStore: make(map[string]*v1.ConfigMap), | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // getSecretRefValue returns the value of a secret in the supplied namespace | // getSecretRefValue returns the value of a secret in the supplied namespace | ||||||
| func getSecretRefValue(client clientset.Interface, namespace string, store *ResourceStore, secretSelector *api.SecretKeySelector) (string, error) { | func getSecretRefValue(client kubernetes.Interface, namespace string, store *ResourceStore, secretSelector *v1.SecretKeySelector) (string, error) { | ||||||
| 	secret, ok := store.SecretStore[secretSelector.Name] | 	secret, ok := store.SecretStore[secretSelector.Name] | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		var err error | 		var err error | ||||||
| @@ -60,7 +60,7 @@ func getSecretRefValue(client clientset.Interface, namespace string, store *Reso | |||||||
| } | } | ||||||
|  |  | ||||||
| // getConfigMapRefValue returns the value of a configmap in the supplied namespace | // getConfigMapRefValue returns the value of a configmap in the supplied namespace | ||||||
| func getConfigMapRefValue(client clientset.Interface, namespace string, store *ResourceStore, configMapSelector *api.ConfigMapKeySelector) (string, error) { | func getConfigMapRefValue(client kubernetes.Interface, namespace string, store *ResourceStore, configMapSelector *v1.ConfigMapKeySelector) (string, error) { | ||||||
| 	configMap, ok := store.ConfigMapStore[configMapSelector.Name] | 	configMap, ok := store.ConfigMapStore[configMapSelector.Name] | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		var err error | 		var err error | ||||||
| @@ -77,17 +77,17 @@ func getConfigMapRefValue(client clientset.Interface, namespace string, store *R | |||||||
| } | } | ||||||
|  |  | ||||||
| // getFieldRef returns the value of the supplied path in the given object | // getFieldRef returns the value of the supplied path in the given object | ||||||
| func getFieldRef(obj runtime.Object, from *api.EnvVarSource) (string, error) { | func getFieldRef(obj runtime.Object, from *v1.EnvVarSource) (string, error) { | ||||||
| 	return fieldpath.ExtractFieldPathAsString(obj, from.FieldRef.FieldPath) | 	return fieldpath.ExtractFieldPathAsString(obj, from.FieldRef.FieldPath) | ||||||
| } | } | ||||||
|  |  | ||||||
| // getResourceFieldRef returns the value of a resource in the given container | // getResourceFieldRef returns the value of a resource in the given container | ||||||
| func getResourceFieldRef(from *api.EnvVarSource, c *api.Container) (string, error) { | func getResourceFieldRef(from *v1.EnvVarSource, c *v1.Container) (string, error) { | ||||||
| 	return resource.ExtractContainerResourceValue(from.ResourceFieldRef, c) | 	return resource.ExtractContainerResourceValue(from.ResourceFieldRef, c) | ||||||
| } | } | ||||||
|  |  | ||||||
| // GetEnvVarRefValue returns the value referenced by the supplied EnvVarSource given the other supplied information. | // GetEnvVarRefValue returns the value referenced by the supplied EnvVarSource given the other supplied information. | ||||||
| func GetEnvVarRefValue(kc clientset.Interface, ns string, store *ResourceStore, from *api.EnvVarSource, obj runtime.Object, c *api.Container) (string, error) { | func GetEnvVarRefValue(kc kubernetes.Interface, ns string, store *ResourceStore, from *v1.EnvVarSource, obj runtime.Object, c *v1.Container) (string, error) { | ||||||
| 	if from.SecretKeyRef != nil { | 	if from.SecretKeyRef != nil { | ||||||
| 		return getSecretRefValue(kc, ns, store, from.SecretKeyRef) | 		return getSecretRefValue(kc, ns, store, from.SecretKeyRef) | ||||||
| 	} | 	} | ||||||
| @@ -108,7 +108,7 @@ func GetEnvVarRefValue(kc clientset.Interface, ns string, store *ResourceStore, | |||||||
| } | } | ||||||
|  |  | ||||||
| // GetEnvVarRefString returns a text description of whichever field is set within the supplied EnvVarSource argument. | // GetEnvVarRefString returns a text description of whichever field is set within the supplied EnvVarSource argument. | ||||||
| func GetEnvVarRefString(from *api.EnvVarSource) string { | func GetEnvVarRefString(from *v1.EnvVarSource) string { | ||||||
| 	if from.ConfigMapKeyRef != nil { | 	if from.ConfigMapKeyRef != nil { | ||||||
| 		return fmt.Sprintf("configmap %s, key %s", from.ConfigMapKeyRef.Name, from.ConfigMapKeyRef.Key) | 		return fmt.Sprintf("configmap %s, key %s", from.ConfigMapKeyRef.Name, from.ConfigMapKeyRef.Key) | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -116,7 +116,7 @@ type ClientAccessFactory interface { | |||||||
|  |  | ||||||
| 	// UpdatePodSpecForObject will call the provided function on the pod spec this object supports, | 	// UpdatePodSpecForObject will call the provided function on the pod spec this object supports, | ||||||
| 	// return false if no pod spec is supported, or return an error. | 	// return false if no pod spec is supported, or return an error. | ||||||
| 	UpdatePodSpecForObject(obj runtime.Object, fn func(*api.PodSpec) error) (bool, error) | 	UpdatePodSpecForObject(obj runtime.Object, fn func(*v1.PodSpec) error) (bool, error) | ||||||
|  |  | ||||||
| 	// MapBasedSelectorForObject returns the map-based selector associated with the provided object. If a | 	// MapBasedSelectorForObject returns the map-based selector associated with the provided object. If a | ||||||
| 	// new set-based selector is provided, an error is returned if the selector cannot be converted to a | 	// new set-based selector is provided, an error is returned if the selector cannot be converted to a | ||||||
|   | |||||||
| @@ -125,8 +125,13 @@ func (f *ring2Factory) PrintObject(cmd *cobra.Command, isLocal bool, mapper meta | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  | 	// Prefer the existing external version if specified | ||||||
|  | 	var preferredVersion []string | ||||||
|  | 	if gvks[0].Version != "" && gvks[0].Version != runtime.APIVersionInternal { | ||||||
|  | 		preferredVersion = []string{gvks[0].Version} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	mapping, err := mapper.RESTMapping(gvks[0].GroupKind()) | 	mapping, err := mapper.RESTMapping(gvks[0].GroupKind(), preferredVersion...) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -29,11 +29,17 @@ import ( | |||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" | 	"time" | ||||||
|  |  | ||||||
|  | 	"k8s.io/api/core/v1" | ||||||
|  |  | ||||||
| 	"github.com/spf13/cobra" | 	"github.com/spf13/cobra" | ||||||
| 	"github.com/spf13/pflag" | 	"github.com/spf13/pflag" | ||||||
|  |  | ||||||
|  | 	appsv1 "k8s.io/api/apps/v1" | ||||||
| 	appsv1beta1 "k8s.io/api/apps/v1beta1" | 	appsv1beta1 "k8s.io/api/apps/v1beta1" | ||||||
|  | 	appsv1beta2 "k8s.io/api/apps/v1beta2" | ||||||
|  | 	batchv1 "k8s.io/api/batch/v1" | ||||||
| 	batchv2alpha1 "k8s.io/api/batch/v2alpha1" | 	batchv2alpha1 "k8s.io/api/batch/v2alpha1" | ||||||
|  | 	extensionsv1beta1 "k8s.io/api/extensions/v1beta1" | ||||||
| 	apierrors "k8s.io/apimachinery/pkg/api/errors" | 	apierrors "k8s.io/apimachinery/pkg/api/errors" | ||||||
| 	"k8s.io/apimachinery/pkg/api/meta" | 	"k8s.io/apimachinery/pkg/api/meta" | ||||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| @@ -47,7 +53,6 @@ import ( | |||||||
| 	"k8s.io/client-go/util/homedir" | 	"k8s.io/client-go/util/homedir" | ||||||
| 	"k8s.io/kubernetes/pkg/api/legacyscheme" | 	"k8s.io/kubernetes/pkg/api/legacyscheme" | ||||||
| 	"k8s.io/kubernetes/pkg/apis/apps" | 	"k8s.io/kubernetes/pkg/apis/apps" | ||||||
| 	"k8s.io/kubernetes/pkg/apis/batch" |  | ||||||
| 	api "k8s.io/kubernetes/pkg/apis/core" | 	api "k8s.io/kubernetes/pkg/apis/core" | ||||||
| 	"k8s.io/kubernetes/pkg/apis/extensions" | 	"k8s.io/kubernetes/pkg/apis/extensions" | ||||||
| 	"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" | 	"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" | ||||||
| @@ -226,25 +231,49 @@ func (f *ring0Factory) JSONEncoder() runtime.Encoder { | |||||||
| 	return legacyscheme.Codecs.LegacyCodec(legacyscheme.Registry.EnabledVersions()...) | 	return legacyscheme.Codecs.LegacyCodec(legacyscheme.Registry.EnabledVersions()...) | ||||||
| } | } | ||||||
|  |  | ||||||
| func (f *ring0Factory) UpdatePodSpecForObject(obj runtime.Object, fn func(*api.PodSpec) error) (bool, error) { | func (f *ring0Factory) UpdatePodSpecForObject(obj runtime.Object, fn func(*v1.PodSpec) error) (bool, error) { | ||||||
| 	// TODO: replace with a swagger schema based approach (identify pod template via schema introspection) | 	// TODO: replace with a swagger schema based approach (identify pod template via schema introspection) | ||||||
| 	switch t := obj.(type) { | 	switch t := obj.(type) { | ||||||
| 	case *api.Pod: | 	case *v1.Pod: | ||||||
| 		return true, fn(&t.Spec) | 		return true, fn(&t.Spec) | ||||||
| 	case *api.ReplicationController: | 	// ReplicationController | ||||||
|  | 	case *v1.ReplicationController: | ||||||
| 		if t.Spec.Template == nil { | 		if t.Spec.Template == nil { | ||||||
| 			t.Spec.Template = &api.PodTemplateSpec{} | 			t.Spec.Template = &v1.PodTemplateSpec{} | ||||||
| 		} | 		} | ||||||
| 		return true, fn(&t.Spec.Template.Spec) | 		return true, fn(&t.Spec.Template.Spec) | ||||||
| 	case *extensions.Deployment: | 	// Deployment | ||||||
|  | 	case *extensionsv1beta1.Deployment: | ||||||
| 		return true, fn(&t.Spec.Template.Spec) | 		return true, fn(&t.Spec.Template.Spec) | ||||||
| 	case *extensions.DaemonSet: | 	case *appsv1beta1.Deployment: | ||||||
| 		return true, fn(&t.Spec.Template.Spec) | 		return true, fn(&t.Spec.Template.Spec) | ||||||
| 	case *extensions.ReplicaSet: | 	case *appsv1beta2.Deployment: | ||||||
| 		return true, fn(&t.Spec.Template.Spec) | 		return true, fn(&t.Spec.Template.Spec) | ||||||
| 	case *apps.StatefulSet: | 	case *appsv1.Deployment: | ||||||
| 		return true, fn(&t.Spec.Template.Spec) | 		return true, fn(&t.Spec.Template.Spec) | ||||||
| 	case *batch.Job: | 	// DaemonSet | ||||||
|  | 	case *extensionsv1beta1.DaemonSet: | ||||||
|  | 		return true, fn(&t.Spec.Template.Spec) | ||||||
|  | 	case *appsv1beta2.DaemonSet: | ||||||
|  | 		return true, fn(&t.Spec.Template.Spec) | ||||||
|  | 	case *appsv1.DaemonSet: | ||||||
|  | 		return true, fn(&t.Spec.Template.Spec) | ||||||
|  | 	// ReplicaSet | ||||||
|  | 	case *extensionsv1beta1.ReplicaSet: | ||||||
|  | 		return true, fn(&t.Spec.Template.Spec) | ||||||
|  | 	case *appsv1beta2.ReplicaSet: | ||||||
|  | 		return true, fn(&t.Spec.Template.Spec) | ||||||
|  | 	case *appsv1.ReplicaSet: | ||||||
|  | 		return true, fn(&t.Spec.Template.Spec) | ||||||
|  | 	// StatefulSet | ||||||
|  | 	case *appsv1beta1.StatefulSet: | ||||||
|  | 		return true, fn(&t.Spec.Template.Spec) | ||||||
|  | 	case *appsv1beta2.StatefulSet: | ||||||
|  | 		return true, fn(&t.Spec.Template.Spec) | ||||||
|  | 	case *appsv1.StatefulSet: | ||||||
|  | 		return true, fn(&t.Spec.Template.Spec) | ||||||
|  | 	// Job | ||||||
|  | 	case *batchv1.Job: | ||||||
| 		return true, fn(&t.Spec.Template.Spec) | 		return true, fn(&t.Spec.Template.Spec) | ||||||
| 	default: | 	default: | ||||||
| 		return false, fmt.Errorf("the object is not a pod or does not have a pod template") | 		return false, fmt.Errorf("the object is not a pod or does not have a pod template") | ||||||
|   | |||||||
| @@ -31,7 +31,6 @@ import ( | |||||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/runtime" | 	"k8s.io/apimachinery/pkg/runtime" | ||||||
| 	"k8s.io/apimachinery/pkg/util/validation" | 	"k8s.io/apimachinery/pkg/util/validation" | ||||||
| 	api "k8s.io/kubernetes/pkg/apis/core" |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| type DeploymentV1Beta1 struct{} | type DeploymentV1Beta1 struct{} | ||||||
| @@ -606,31 +605,6 @@ func (BasicReplicationController) ParamNames() []GeneratorParam { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
| // populateResourceList takes strings of form <resourceName1>=<value1>,<resourceName1>=<value2> |  | ||||||
| // and returns ResourceList. |  | ||||||
| func populateResourceList(spec string) (api.ResourceList, error) { |  | ||||||
| 	// empty input gets a nil response to preserve generator test expected behaviors |  | ||||||
| 	if spec == "" { |  | ||||||
| 		return nil, nil |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	result := api.ResourceList{} |  | ||||||
| 	resourceStatements := strings.Split(spec, ",") |  | ||||||
| 	for _, resourceStatement := range resourceStatements { |  | ||||||
| 		parts := strings.Split(resourceStatement, "=") |  | ||||||
| 		if len(parts) != 2 { |  | ||||||
| 			return nil, fmt.Errorf("Invalid argument syntax %v, expected <resource>=<value>", resourceStatement) |  | ||||||
| 		} |  | ||||||
| 		resourceName := api.ResourceName(parts[0]) |  | ||||||
| 		resourceQuantity, err := resource.ParseQuantity(parts[1]) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return nil, err |  | ||||||
| 		} |  | ||||||
| 		result[resourceName] = resourceQuantity |  | ||||||
| 	} |  | ||||||
| 	return result, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // populateResourceListV1 takes strings of form <resourceName1>=<value1>,<resourceName1>=<value2> | // populateResourceListV1 takes strings of form <resourceName1>=<value1>,<resourceName1>=<value2> | ||||||
| // and returns ResourceList. | // and returns ResourceList. | ||||||
| func populateResourceListV1(spec string) (v1.ResourceList, error) { | func populateResourceListV1(spec string) (v1.ResourceList, error) { | ||||||
| @@ -656,23 +630,6 @@ func populateResourceListV1(spec string) (v1.ResourceList, error) { | |||||||
| 	return result, nil | 	return result, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| // HandleResourceRequirements parses the limits and requests parameters if specified |  | ||||||
| // and returns ResourceRequirements. |  | ||||||
| func HandleResourceRequirements(params map[string]string) (api.ResourceRequirements, error) { |  | ||||||
| 	result := api.ResourceRequirements{} |  | ||||||
| 	limits, err := populateResourceList(params["limits"]) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return result, err |  | ||||||
| 	} |  | ||||||
| 	result.Limits = limits |  | ||||||
| 	requests, err := populateResourceList(params["requests"]) |  | ||||||
| 	if err != nil { |  | ||||||
| 		return result, err |  | ||||||
| 	} |  | ||||||
| 	result.Requests = requests |  | ||||||
| 	return result, nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // HandleResourceRequirementsV1 parses the limits and requests parameters if specified | // HandleResourceRequirementsV1 parses the limits and requests parameters if specified | ||||||
| // and returns ResourceRequirements. | // and returns ResourceRequirements. | ||||||
| func HandleResourceRequirementsV1(params map[string]string) (v1.ResourceRequirements, error) { | func HandleResourceRequirementsV1(params map[string]string) (v1.ResourceRequirements, error) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Kubernetes Submit Queue
					Kubernetes Submit Queue