diff --git a/pkg/kubectl/cmd/rollout/rollout_pause.go b/pkg/kubectl/cmd/rollout/rollout_pause.go index 65888248cd9..9460e70397c 100644 --- a/pkg/kubectl/cmd/rollout/rollout_pause.go +++ b/pkg/kubectl/cmd/rollout/rollout_pause.go @@ -30,6 +30,7 @@ import ( "k8s.io/kubernetes/pkg/kubectl/genericclioptions" "k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers" "k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource" + "k8s.io/kubernetes/pkg/kubectl/polymorphichelpers" "k8s.io/kubernetes/pkg/kubectl/scheme" "k8s.io/kubernetes/pkg/kubectl/util/i18n" ) @@ -41,7 +42,7 @@ type PauseConfig struct { PrintFlags *genericclioptions.PrintFlags ToPrinter func(string) (printers.ResourcePrinter, error) - Pauser func(info *resource.Info) ([]byte, error) + Pauser polymorphichelpers.ObjectPauserFunc Infos []*resource.Info genericclioptions.IOStreams @@ -101,7 +102,7 @@ func (o *PauseConfig) CompletePause(f cmdutil.Factory, cmd *cobra.Command, args return cmdutil.UsageErrorf(cmd, "%s", cmd.Use) } - o.Pauser = f.Pauser + o.Pauser = polymorphichelpers.ObjectPauserFn cmdNamespace, enforceNamespace, err := f.DefaultNamespace() if err != nil { @@ -136,7 +137,7 @@ func (o *PauseConfig) CompletePause(f cmdutil.Factory, cmd *cobra.Command, args func (o PauseConfig) RunPause() error { allErrs := []error{} - for _, patch := range set.CalculatePatches(o.Infos, cmdutil.InternalVersionJSONEncoder(), o.Pauser) { + for _, patch := range set.CalculatePatches(o.Infos, cmdutil.InternalVersionJSONEncoder(), set.PatchFn(o.Pauser)) { info := patch.Info if patch.Err != nil { resourceString := info.Mapping.Resource.Resource diff --git a/pkg/kubectl/cmd/rollout/rollout_resume.go b/pkg/kubectl/cmd/rollout/rollout_resume.go index 16dde958d83..3208bc3c2d7 100644 --- a/pkg/kubectl/cmd/rollout/rollout_resume.go +++ b/pkg/kubectl/cmd/rollout/rollout_resume.go @@ -30,6 +30,7 @@ import ( "k8s.io/kubernetes/pkg/kubectl/genericclioptions" "k8s.io/kubernetes/pkg/kubectl/genericclioptions/printers" "k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource" + "k8s.io/kubernetes/pkg/kubectl/polymorphichelpers" "k8s.io/kubernetes/pkg/kubectl/scheme" "k8s.io/kubernetes/pkg/kubectl/util/i18n" ) @@ -41,7 +42,7 @@ type ResumeConfig struct { PrintFlags *genericclioptions.PrintFlags ToPrinter func(string) (printers.ResourcePrinter, error) - Resumer func(object *resource.Info) ([]byte, error) + Resumer polymorphichelpers.ObjectResumerFunc Infos []*resource.Info genericclioptions.IOStreams @@ -99,7 +100,7 @@ func (o *ResumeConfig) CompleteResume(f cmdutil.Factory, cmd *cobra.Command, arg return cmdutil.UsageErrorf(cmd, "%s", cmd.Use) } - o.Resumer = f.Resumer + o.Resumer = polymorphichelpers.ObjectResumerFn cmdNamespace, enforceNamespace, err := f.DefaultNamespace() if err != nil { @@ -140,7 +141,7 @@ func (o *ResumeConfig) CompleteResume(f cmdutil.Factory, cmd *cobra.Command, arg func (o ResumeConfig) RunResume() error { allErrs := []error{} - for _, patch := range set.CalculatePatches(o.Infos, cmdutil.InternalVersionJSONEncoder(), o.Resumer) { + for _, patch := range set.CalculatePatches(o.Infos, cmdutil.InternalVersionJSONEncoder(), set.PatchFn(o.Resumer)) { info := patch.Info if patch.Err != nil { diff --git a/pkg/kubectl/cmd/set/helper.go b/pkg/kubectl/cmd/set/helper.go index 4d267c28da2..42b1bb8a9e6 100644 --- a/pkg/kubectl/cmd/set/helper.go +++ b/pkg/kubectl/cmd/set/helper.go @@ -118,16 +118,16 @@ type Patch struct { Patch []byte } -// patchFn is a function type that accepts an info object and returns a byte slice. -// Implementations of patchFn should update the object and return it encoded. -type patchFn func(*resource.Info) ([]byte, error) +// PatchFn is a function type that accepts an info object and returns a byte slice. +// Implementations of PatchFn should update the object and return it encoded. +type PatchFn func(runtime.Object) ([]byte, error) // CalculatePatch calls the mutation function on the provided info object, and generates a strategic merge patch for // the changes in the object. Encoder must be able to encode the info into the appropriate destination type. // This function returns whether the mutation function made any change in the original object. -func CalculatePatch(patch *Patch, encoder runtime.Encoder, mutateFn patchFn) bool { +func CalculatePatch(patch *Patch, encoder runtime.Encoder, mutateFn PatchFn) bool { patch.Before, patch.Err = runtime.Encode(encoder, patch.Info.Object) - patch.After, patch.Err = mutateFn(patch.Info) + patch.After, patch.Err = mutateFn(patch.Info.Object) if patch.Err != nil { return true } @@ -141,7 +141,7 @@ func CalculatePatch(patch *Patch, encoder runtime.Encoder, mutateFn patchFn) boo // CalculatePatches calculates patches on each provided info object. If the provided mutateFn // makes no change in an object, the object is not included in the final list of patches. -func CalculatePatches(infos []*resource.Info, encoder runtime.Encoder, mutateFn patchFn) []*Patch { +func CalculatePatches(infos []*resource.Info, encoder runtime.Encoder, mutateFn PatchFn) []*Patch { var patches []*Patch for _, info := range infos { patch := &Patch{Info: info} diff --git a/pkg/kubectl/cmd/set/set_env.go b/pkg/kubectl/cmd/set/set_env.go index 87a83c7a10d..51d01e51294 100644 --- a/pkg/kubectl/cmd/set/set_env.go +++ b/pkg/kubectl/cmd/set/set_env.go @@ -26,6 +26,7 @@ import ( "github.com/spf13/cobra" "k8s.io/api/core/v1" + meta "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" utilerrors "k8s.io/apimachinery/pkg/util/errors" @@ -323,12 +324,53 @@ func (o *EnvOptions) RunEnv() error { if err != nil { return err } - patches := CalculatePatches(infos, scheme.DefaultJSONEncoder(), func(info *resource.Info) ([]byte, error) { - _, err := o.updatePodSpecForObject(info.Object, func(spec *v1.PodSpec) error { + patches := CalculatePatches(infos, scheme.DefaultJSONEncoder(), func(obj runtime.Object) ([]byte, error) { + _, err := o.updatePodSpecForObject(obj, func(spec *v1.PodSpec) error { resolutionErrorsEncountered := false containers, _ := selectContainers(spec.Containers, o.ContainerSelector) + objName, err := meta.NewAccessor().Name(obj) + if err != nil { + return err + } + + gvks, _, err := scheme.Scheme.ObjectKinds(obj) + if err != nil { + return err + } + objKind := obj.GetObjectKind().GroupVersionKind().Kind + if len(objKind) == 0 { + for _, gvk := range gvks { + if len(gvk.Kind) == 0 { + continue + } + if len(gvk.Version) == 0 || gvk.Version == runtime.APIVersionInternal { + continue + } + + objKind = gvk.Kind + break + } + } + if len(containers) == 0 { - fmt.Fprintf(o.ErrOut, "warning: %s/%s does not have any containers matching %q\n", info.Mapping.Resource, info.Name, o.ContainerSelector) + if gvks, _, err := scheme.Scheme.ObjectKinds(obj); err == nil { + objKind := obj.GetObjectKind().GroupVersionKind().Kind + if len(objKind) == 0 { + for _, gvk := range gvks { + if len(gvk.Kind) == 0 { + continue + } + if len(gvk.Version) == 0 || gvk.Version == runtime.APIVersionInternal { + continue + } + + objKind = gvk.Kind + break + } + } + + fmt.Fprintf(o.ErrOut, "warning: %s/%s does not have any containers matching %q\n", objKind, objName, o.ContainerSelector) + } return nil } for _, c := range containers { @@ -343,7 +385,7 @@ func (o *EnvOptions) RunEnv() error { resolveErrors := map[string][]string{} store := envutil.NewResourceStore() - fmt.Fprintf(o.Out, "# %s %s, container %s\n", info.Mapping.Resource, info.Name, c.Name) + fmt.Fprintf(o.Out, "# %s %s, container %s\n", objKind, objName, c.Name) for _, env := range c.Env { // Print the simple value if env.ValueFrom == nil { @@ -357,7 +399,7 @@ func (o *EnvOptions) RunEnv() error { continue } - value, err := envutil.GetEnvVarRefValue(o.clientset, o.namespace, store, env.ValueFrom, info.Object, c) + value, err := envutil.GetEnvVarRefValue(o.clientset, o.namespace, store, env.ValueFrom, obj, c) // Print the resolved value if err == nil { fmt.Fprintf(o.Out, "%s=%s\n", env.Name, value) @@ -390,7 +432,7 @@ func (o *EnvOptions) RunEnv() error { }) if err == nil { - return runtime.Encode(scheme.DefaultJSONEncoder(), info.Object) + return runtime.Encode(scheme.DefaultJSONEncoder(), obj) } return nil, err }) diff --git a/pkg/kubectl/cmd/set/set_image.go b/pkg/kubectl/cmd/set/set_image.go index 540e40bebc9..0e8251b944d 100644 --- a/pkg/kubectl/cmd/set/set_image.go +++ b/pkg/kubectl/cmd/set/set_image.go @@ -210,9 +210,9 @@ func (o *SetImageOptions) Validate() error { func (o *SetImageOptions) Run() error { allErrs := []error{} - patches := CalculatePatches(o.Infos, scheme.DefaultJSONEncoder(), func(info *resource.Info) ([]byte, error) { + patches := CalculatePatches(o.Infos, scheme.DefaultJSONEncoder(), func(obj runtime.Object) ([]byte, error) { transformed := false - _, err := o.UpdatePodSpecForObject(info.Object, func(spec *v1.PodSpec) error { + _, err := o.UpdatePodSpecForObject(obj, func(spec *v1.PodSpec) error { for name, image := range o.ContainerImages { var ( containerFound bool @@ -255,11 +255,11 @@ func (o *SetImageOptions) Run() error { return nil, nil } // record this change (for rollout history) - if err := o.Recorder.Record(info.Object); err != nil { + if err := o.Recorder.Record(obj); err != nil { glog.V(4).Infof("error recording current command: %v", err) } - return runtime.Encode(scheme.DefaultJSONEncoder(), info.Object) + return runtime.Encode(scheme.DefaultJSONEncoder(), obj) }) for _, patch := range patches { diff --git a/pkg/kubectl/cmd/set/set_resources.go b/pkg/kubectl/cmd/set/set_resources.go index 1089b3f61f5..aa6b33a4fee 100644 --- a/pkg/kubectl/cmd/set/set_resources.go +++ b/pkg/kubectl/cmd/set/set_resources.go @@ -222,9 +222,9 @@ func (o *SetResourcesOptions) Validate() error { func (o *SetResourcesOptions) Run() error { allErrs := []error{} - patches := CalculatePatches(o.Infos, scheme.DefaultJSONEncoder(), func(info *resource.Info) ([]byte, error) { + patches := CalculatePatches(o.Infos, scheme.DefaultJSONEncoder(), func(obj runtime.Object) ([]byte, error) { transformed := false - _, err := o.UpdatePodSpecForObject(info.Object, func(spec *v1.PodSpec) error { + _, err := o.UpdatePodSpecForObject(obj, func(spec *v1.PodSpec) error { containers, _ := selectContainers(spec.Containers, o.ContainerSelector) if len(containers) != 0 { for i := range containers { @@ -255,11 +255,11 @@ func (o *SetResourcesOptions) Run() error { return nil, nil } // record this change (for rollout history) - if err := o.Recorder.Record(info.Object); err != nil { + if err := o.Recorder.Record(obj); err != nil { glog.V(4).Infof("error recording current command: %v", err) } - return runtime.Encode(scheme.DefaultJSONEncoder(), info.Object) + return runtime.Encode(scheme.DefaultJSONEncoder(), obj) }) for _, patch := range patches { diff --git a/pkg/kubectl/cmd/set/set_selector.go b/pkg/kubectl/cmd/set/set_selector.go index ce8cca2a16f..0a6d6200270 100644 --- a/pkg/kubectl/cmd/set/set_selector.go +++ b/pkg/kubectl/cmd/set/set_selector.go @@ -200,7 +200,7 @@ func (o *SetSelectorOptions) RunSelector() error { return r.Visit(func(info *resource.Info, err error) error { patch := &Patch{Info: info} - CalculatePatch(patch, scheme.DefaultJSONEncoder(), func(info *resource.Info) ([]byte, error) { + CalculatePatch(patch, scheme.DefaultJSONEncoder(), func(obj runtime.Object) ([]byte, error) { selectErr := updateSelectorForObject(info.Object, *o.selector) if selectErr != nil { return nil, selectErr diff --git a/pkg/kubectl/cmd/set/set_serviceaccount.go b/pkg/kubectl/cmd/set/set_serviceaccount.go index e33e12ac3b7..ddf015ef10c 100644 --- a/pkg/kubectl/cmd/set/set_serviceaccount.go +++ b/pkg/kubectl/cmd/set/set_serviceaccount.go @@ -173,8 +173,8 @@ func (o *SetServiceAccountOptions) Complete(f cmdutil.Factory, cmd *cobra.Comman // Run creates and applies the patch either locally or calling apiserver. func (o *SetServiceAccountOptions) Run() error { patchErrs := []error{} - patchFn := func(info *resource.Info) ([]byte, error) { - _, err := o.updatePodSpecForObject(info.Object, func(podSpec *v1.PodSpec) error { + patchFn := func(obj runtime.Object) ([]byte, error) { + _, err := o.updatePodSpecForObject(obj, func(podSpec *v1.PodSpec) error { podSpec.ServiceAccountName = o.serviceAccountName return nil }) @@ -182,11 +182,11 @@ func (o *SetServiceAccountOptions) Run() error { return nil, err } // record this change (for rollout history) - if err := o.Recorder.Record(info.Object); err != nil { + if err := o.Recorder.Record(obj); err != nil { glog.V(4).Infof("error recording current command: %v", err) } - return runtime.Encode(scheme.DefaultJSONEncoder(), info.Object) + return runtime.Encode(scheme.DefaultJSONEncoder(), obj) } patches := CalculatePatches(o.infos, scheme.DefaultJSONEncoder(), patchFn) diff --git a/pkg/kubectl/cmd/set/set_subject.go b/pkg/kubectl/cmd/set/set_subject.go index 10fd4031e10..9a0cc736d5c 100644 --- a/pkg/kubectl/cmd/set/set_subject.go +++ b/pkg/kubectl/cmd/set/set_subject.go @@ -194,7 +194,7 @@ func (o *SubjectOptions) Validate() error { } func (o *SubjectOptions) Run(fn updateSubjects) error { - patches := CalculatePatches(o.Infos, scheme.DefaultJSONEncoder(), func(info *resource.Info) ([]byte, error) { + patches := CalculatePatches(o.Infos, scheme.DefaultJSONEncoder(), func(obj runtime.Object) ([]byte, error) { subjects := []rbacv1.Subject{} for _, user := range sets.NewString(o.Users...).List() { subject := rbacv1.Subject{ @@ -227,10 +227,10 @@ func (o *SubjectOptions) Run(fn updateSubjects) error { subjects = append(subjects, subject) } - transformed, err := updateSubjectForObject(info.Object, subjects, fn) + transformed, err := updateSubjectForObject(obj, subjects, fn) if transformed && err == nil { // TODO: switch UpdatePodSpecForObject to work on v1.PodSpec - return runtime.Encode(scheme.DefaultJSONEncoder(), info.Object) + return runtime.Encode(scheme.DefaultJSONEncoder(), obj) } return nil, err }) diff --git a/pkg/kubectl/cmd/util/factory.go b/pkg/kubectl/cmd/util/factory.go index d13bd99dc82..2ca941f9cab 100644 --- a/pkg/kubectl/cmd/util/factory.go +++ b/pkg/kubectl/cmd/util/factory.go @@ -92,15 +92,6 @@ type ClientAccessFactory interface { // SuggestedPodTemplateResources returns a list of resource types that declare a pod template SuggestedPodTemplateResources() []schema.GroupResource - // Pauser marks the object in the info as paused. Currently supported only for Deployments. - // Returns the patched object in bytes and any error that occurred during the encoding or - // in case the object is already paused. - Pauser(info *resource.Info) ([]byte, error) - // Resumer resumes a paused object inside the info. Currently supported only for Deployments. - // Returns the patched object in bytes and any error that occurred during the encoding or - // in case the object is already resumed. - Resumer(info *resource.Info) ([]byte, error) - // Returns the default namespace to use in cases where no // other namespace is specified and whether the namespace was // overridden. diff --git a/pkg/kubectl/cmd/util/factory_client_access.go b/pkg/kubectl/cmd/util/factory_client_access.go index e357da65c77..4aacd4dce95 100644 --- a/pkg/kubectl/cmd/util/factory_client_access.go +++ b/pkg/kubectl/cmd/util/factory_client_access.go @@ -19,7 +19,6 @@ limitations under the License. package util import ( - "errors" "fmt" "io" "os" @@ -218,32 +217,6 @@ func (f *ring0Factory) SuggestedPodTemplateResources() []schema.GroupResource { } } -func (f *ring0Factory) Pauser(info *resource.Info) ([]byte, error) { - switch obj := info.Object.(type) { - case *extensions.Deployment: - if obj.Spec.Paused { - return nil, errors.New("is already paused") - } - obj.Spec.Paused = true - return runtime.Encode(InternalVersionJSONEncoder(), info.Object) - default: - return nil, fmt.Errorf("pausing is not supported") - } -} - -func (f *ring0Factory) Resumer(info *resource.Info) ([]byte, error) { - switch obj := info.Object.(type) { - case *extensions.Deployment: - if !obj.Spec.Paused { - return nil, errors.New("is not paused") - } - obj.Spec.Paused = false - return runtime.Encode(InternalVersionJSONEncoder(), info.Object) - default: - return nil, fmt.Errorf("resuming is not supported") - } -} - func (f *ring0Factory) DefaultNamespace() (string, bool, error) { return f.clientGetter.ToRawKubeConfigLoader().Namespace() } diff --git a/pkg/kubectl/polymorphichelpers/BUILD b/pkg/kubectl/polymorphichelpers/BUILD index 747a974c5ef..2097c87d7c5 100644 --- a/pkg/kubectl/polymorphichelpers/BUILD +++ b/pkg/kubectl/polymorphichelpers/BUILD @@ -10,6 +10,8 @@ go_library( "historyviewer.go", "interface.go", "logsforobject.go", + "objectpauser.go", + "objectresumer.go", "portsforobject.go", "statusviewer.go", "updatepodspec.go", @@ -17,6 +19,7 @@ go_library( importpath = "k8s.io/kubernetes/pkg/kubectl/polymorphichelpers", visibility = ["//visibility:public"], deps = [ + "//pkg/api/legacyscheme:go_default_library", "//pkg/apis/apps:go_default_library", "//pkg/apis/batch:go_default_library", "//pkg/apis/core:go_default_library", @@ -37,6 +40,7 @@ go_library( "//vendor/k8s.io/api/extensions/v1beta1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library", "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", diff --git a/pkg/kubectl/polymorphichelpers/interface.go b/pkg/kubectl/polymorphichelpers/interface.go index 0ff35cd5b68..02329a4b126 100644 --- a/pkg/kubectl/polymorphichelpers/interface.go +++ b/pkg/kubectl/polymorphichelpers/interface.go @@ -77,3 +77,19 @@ type CanBeExposedFunc func(kind schema.GroupKind) error // CanBeExposedFn gives a way to easily override the function for unit testing if needed var CanBeExposedFn CanBeExposedFunc = canBeExposed + +// ObjectPauserFunc is a function type that marks the object in a given info as paused. +type ObjectPauserFunc func(runtime.Object) ([]byte, error) + +// ObjectPauserFn gives a way to easily override the function for unit testing if needed. +// Returns the patched object in bytes and any error that occurred during the encoding or +// in case the object is already paused. +var ObjectPauserFn ObjectPauserFunc = defaultObjectPauser + +// ObjectResumerFunc is a function type that marks the object in a given info as resumed. +type ObjectResumerFunc func(runtime.Object) ([]byte, error) + +// ObjectResumerFn gives a way to easily override the function for unit testing if needed. +// Returns the patched object in bytes and any error that occurred during the encoding or +// in case the object is already resumed. +var ObjectResumerFn ObjectResumerFunc = defaultObjectResumer diff --git a/pkg/kubectl/polymorphichelpers/objectpauser.go b/pkg/kubectl/polymorphichelpers/objectpauser.go new file mode 100644 index 00000000000..f6fbde55893 --- /dev/null +++ b/pkg/kubectl/polymorphichelpers/objectpauser.go @@ -0,0 +1,46 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package polymorphichelpers + +import ( + "errors" + "fmt" + + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/kubernetes/pkg/api/legacyscheme" + "k8s.io/kubernetes/pkg/apis/extensions" +) + +// Currently only supports Deployments. +func defaultObjectPauser(obj runtime.Object) ([]byte, error) { + switch obj := obj.(type) { + case *extensions.Deployment: + if obj.Spec.Paused { + return nil, errors.New("is already paused") + } + obj.Spec.Paused = true + return runtime.Encode(internalVersionJSONEncoder(), obj) + default: + return nil, fmt.Errorf("pausing is not supported") + } +} + +func internalVersionJSONEncoder() runtime.Encoder { + encoder := legacyscheme.Codecs.LegacyCodec(legacyscheme.Scheme.PrioritizedVersionsAllGroups()...) + return unstructured.JSONFallbackEncoder{Encoder: encoder} +} diff --git a/pkg/kubectl/polymorphichelpers/objectresumer.go b/pkg/kubectl/polymorphichelpers/objectresumer.go new file mode 100644 index 00000000000..84d8dff91dc --- /dev/null +++ b/pkg/kubectl/polymorphichelpers/objectresumer.go @@ -0,0 +1,38 @@ +/* +Copyright 2018 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package polymorphichelpers + +import ( + "errors" + "fmt" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/kubernetes/pkg/apis/extensions" +) + +func defaultObjectResumer(obj runtime.Object) ([]byte, error) { + switch obj := obj.(type) { + case *extensions.Deployment: + if !obj.Spec.Paused { + return nil, errors.New("is not paused") + } + obj.Spec.Paused = false + return runtime.Encode(internalVersionJSONEncoder(), obj) + default: + return nil, fmt.Errorf("resuming is not supported") + } +}