Merge pull request #64111 from juanvallejo/jvallejo/move-more-helpers

Automatic merge from submit-queue. 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>.

Move CanBeExposed helper from factory_client_access

**Release note**:
```release-note
NONE
```

Moves additional helpers from the "factory_client_access". Continues work from https://github.com/kubernetes/kubernetes/pull/63984 and https://github.com/kubernetes/kubernetes/pull/63884

Moves CanBeExposed from factory_client_access.

cc @soltysh
This commit is contained in:
Kubernetes Submit Queue 2018-05-23 13:50:02 -07:00 committed by GitHub
commit b143093a62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 327 additions and 129 deletions

View File

@ -27,7 +27,6 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/client-go/dynamic"
"k8s.io/kubernetes/pkg/api/legacyscheme"
@ -92,7 +91,7 @@ type ExposeServiceOptions struct {
EnforceNamespace bool
Generators func(string) map[string]kubectl.Generator
CanBeExposed func(kind schema.GroupKind) error
CanBeExposed polymorphichelpers.CanBeExposedFunc
ClientForMapping func(*meta.RESTMapping) (resource.RESTClient, error)
MapBasedSelectorForObject func(runtime.Object) (string, error)
PortsForObject polymorphichelpers.PortsForObjectFunc
@ -191,7 +190,7 @@ func (o *ExposeServiceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) e
o.Generators = f.Generators
o.Builder = f.NewBuilder()
o.CanBeExposed = f.CanBeExposed
o.CanBeExposed = polymorphichelpers.CanBeExposedFn
o.ClientForMapping = f.ClientForMapping
o.MapBasedSelectorForObject = f.MapBasedSelectorForObject
o.PortsForObject = polymorphichelpers.PortsForObjectFn

View File

@ -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

View File

@ -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 {

View File

@ -20,6 +20,7 @@ import (
"io"
"github.com/spf13/cobra"
"k8s.io/kubernetes/pkg/kubectl/polymorphichelpers"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/kubernetes/pkg/api/legacyscheme"
@ -139,7 +140,7 @@ func (o *UndoOptions) CompleteUndo(f cmdutil.Factory, cmd *cobra.Command, out io
if err != nil {
return err
}
rollbacker, err := f.Rollbacker(info.ResourceMapping())
rollbacker, err := polymorphichelpers.RollbackerFn(f, info.ResourceMapping())
if err != nil {
return err
}

View File

@ -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}

View File

@ -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
})

View File

@ -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 {

View File

@ -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 {

View File

@ -201,7 +201,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

View File

@ -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)

View File

@ -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
})

View File

@ -16,7 +16,6 @@ go_library(
visibility = ["//build/visible_to:pkg_kubectl_cmd_util_CONSUMERS"],
deps = [
"//pkg/api/legacyscheme:go_default_library",
"//pkg/apis/apps:go_default_library",
"//pkg/apis/core:go_default_library",
"//pkg/apis/extensions:go_default_library",
"//pkg/client/clientset_generated/internalclientset:go_default_library",

View File

@ -86,23 +86,12 @@ 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.
DefaultNamespace() (string, bool, error)
// Generators returns the generators for the provided command
Generators(cmdName string) map[string]kubectl.Generator
// Check whether the kind of resources could be exposed
CanBeExposed(kind schema.GroupKind) error
}
// ObjectMappingFactory holds the second level of factory methods. These functions depend upon ClientAccessFactory methods.
@ -116,9 +105,6 @@ type ObjectMappingFactory interface {
// Returns a Describer for displaying the specified RESTMapping type or an error.
Describer(mapping *meta.RESTMapping) (printers.Describer, error)
// Returns a Rollbacker for changing the rollback version of the specified RESTMapping type or an error
Rollbacker(mapping *meta.RESTMapping) (kubectl.Rollbacker, error)
// Returns a schema that can validate objects stored on disk.
Validator(validate bool) (validation.Schema, error)
// OpenAPISchema returns the schema openapi schema definition

View File

@ -19,7 +19,6 @@ limitations under the License.
package util
import (
"errors"
"fmt"
"io"
@ -41,7 +40,6 @@ import (
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/apis/apps"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
@ -182,32 +180,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()
}
@ -422,17 +394,6 @@ func (f *ring0Factory) Generators(cmdName string) map[string]kubectl.Generator {
return DefaultGenerators(cmdName)
}
func (f *ring0Factory) CanBeExposed(kind schema.GroupKind) error {
switch kind {
case api.Kind("ReplicationController"), api.Kind("Service"), api.Kind("Pod"),
extensions.Kind("Deployment"), apps.Kind("Deployment"), extensions.Kind("ReplicaSet"), apps.Kind("ReplicaSet"):
// nothing to do here
default:
return fmt.Errorf("cannot expose a %s", kind)
}
return nil
}
// this method exists to help us find the points still relying on internal types.
func InternalVersionDecoder() runtime.Decoder {
return legacyscheme.Codecs.UniversalDecoder()

View File

@ -26,7 +26,6 @@ import (
"k8s.io/client-go/dynamic"
restclient "k8s.io/client-go/rest"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi"
openapivalidation "k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi/validation"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
@ -132,14 +131,6 @@ func genericDescriber(clientAccessFactory ClientAccessFactory, mapping *meta.RES
return printersinternal.GenericDescriberFor(mapping, dynamicClient, eventsClient), nil
}
func (f *ring1Factory) Rollbacker(mapping *meta.RESTMapping) (kubectl.Rollbacker, error) {
external, err := f.clientAccessFactory.KubernetesClientSet()
if err != nil {
return nil, err
}
return kubectl.RollbackerFor(mapping.GroupVersionKind.GroupKind(), external)
}
func (f *ring1Factory) Validator(validate bool) (validation.Schema, error) {
if !validate {
return validation.NullSchema{}, nil

View File

@ -21,7 +21,6 @@ import (
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/kubectl"
@ -66,33 +65,6 @@ func TestProtocolsForObject(t *testing.T) {
}
}
func TestCanBeExposed(t *testing.T) {
factory := NewFactory(genericclioptions.NewTestConfigFlags())
tests := []struct {
kind schema.GroupKind
expectErr bool
}{
{
kind: api.Kind("ReplicationController"),
expectErr: false,
},
{
kind: api.Kind("Node"),
expectErr: true,
},
}
for _, test := range tests {
err := factory.CanBeExposed(test.kind)
if test.expectErr && err == nil {
t.Error("unexpected non-error")
}
if !test.expectErr && err != nil {
t.Errorf("unexpected error: %v", err)
}
}
}
func TestMakePortsString(t *testing.T) {
tests := []struct {
ports []api.ServicePort

View File

@ -5,17 +5,22 @@ go_library(
srcs = [
"attachablepodforobject.go",
"canbeautoscaled.go",
"canbeexposed.go",
"helpers.go",
"historyviewer.go",
"interface.go",
"logsforobject.go",
"objectpauser.go",
"objectresumer.go",
"portsforobject.go",
"rollbacker.go",
"statusviewer.go",
"updatepodspec.go",
],
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",
@ -36,6 +41,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",
@ -48,6 +54,7 @@ go_library(
go_test(
name = "go_default_test",
srcs = [
"canbeexposed_test.go",
"helpers_test.go",
"logsforobject_test.go",
"portsforobject_test.go",

View File

@ -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 (
"fmt"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/kubernetes/pkg/apis/apps"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/apis/extensions"
)
// Check whether the kind of resources could be exposed
func canBeExposed(kind schema.GroupKind) error {
switch kind {
case api.Kind("ReplicationController"), api.Kind("Service"), api.Kind("Pod"),
extensions.Kind("Deployment"), apps.Kind("Deployment"), extensions.Kind("ReplicaSet"), apps.Kind("ReplicaSet"):
// nothing to do here
default:
return fmt.Errorf("cannot expose a %s", kind)
}
return nil
}

View File

@ -0,0 +1,50 @@
/*
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 (
"testing"
"k8s.io/apimachinery/pkg/runtime/schema"
api "k8s.io/kubernetes/pkg/apis/core"
)
func TestCanBeExposed(t *testing.T) {
tests := []struct {
kind schema.GroupKind
expectErr bool
}{
{
kind: api.Kind("ReplicationController"),
expectErr: false,
},
{
kind: api.Kind("Node"),
expectErr: true,
},
}
for _, test := range tests {
err := canBeExposed(test.kind)
if test.expectErr && err == nil {
t.Error("unexpected non-error")
}
if !test.expectErr && err != nil {
t.Errorf("unexpected error: %v", err)
}
}
}

View File

@ -71,3 +71,31 @@ type CanBeAutoscaledFunc func(kind schema.GroupKind) error
// CanBeAutoscaledFn gives a way to easily override the function for unit testing if needed
var CanBeAutoscaledFn CanBeAutoscaledFunc = canBeAutoscaled
// CanBeExposedFunc is a function type that can tell you whether a given GroupKind is capable of being exposed
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
// RollbackerFunc gives a way to change the rollback version of the specified RESTMapping type
type RollbackerFunc func(restClientGetter genericclioptions.RESTClientGetter, mapping *meta.RESTMapping) (kubectl.Rollbacker, error)
// RollbackerFn gives a way to easily override the function for unit testing if needed
var RollbackerFn RollbackerFunc = rollbacker

View File

@ -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}
}

View File

@ -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")
}
}

View File

@ -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 (
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/client-go/kubernetes"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
)
// Returns a Rollbacker for changing the rollback version of the specified RESTMapping type or an error
func rollbacker(restClientGetter genericclioptions.RESTClientGetter, mapping *meta.RESTMapping) (kubectl.Rollbacker, error) {
clientConfig, err := restClientGetter.ToRESTConfig()
if err != nil {
return nil, err
}
external, err := kubernetes.NewForConfig(clientConfig)
if err != nil {
return nil, err
}
return kubectl.RollbackerFor(mapping.GroupVersionKind.GroupKind(), external)
}