diff --git a/pkg/kubectl/cmd/attach.go b/pkg/kubectl/cmd/attach.go index 5608bb7c9c1..2195eee1ced 100644 --- a/pkg/kubectl/cmd/attach.go +++ b/pkg/kubectl/cmd/attach.go @@ -36,6 +36,7 @@ import ( "k8s.io/kubernetes/pkg/kubectl/cmd/templates" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/genericclioptions" + "k8s.io/kubernetes/pkg/kubectl/polymorphichelpers" "k8s.io/kubernetes/pkg/kubectl/util/i18n" ) @@ -160,7 +161,7 @@ func (p *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn [ return err } - attachablePod, err := f.AttachablePodForObject(obj, p.GetPodTimeout) + attachablePod, err := polymorphichelpers.AttachablePodForObjectFn(f, obj, p.GetPodTimeout) if err != nil { return err } @@ -187,6 +188,7 @@ func (p *AttachOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn [ if err != nil { return err } + p.PodClient = clientset.Core() if p.CommandName == "" { diff --git a/pkg/kubectl/cmd/portforward.go b/pkg/kubectl/cmd/portforward.go index ec2e2c07d13..b6f73348e26 100644 --- a/pkg/kubectl/cmd/portforward.go +++ b/pkg/kubectl/cmd/portforward.go @@ -38,6 +38,7 @@ import ( "k8s.io/kubernetes/pkg/kubectl/cmd/templates" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/genericclioptions" + "k8s.io/kubernetes/pkg/kubectl/polymorphichelpers" "k8s.io/kubernetes/pkg/kubectl/util" "k8s.io/kubernetes/pkg/kubectl/util/i18n" ) @@ -196,7 +197,7 @@ func (o *PortForwardOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, arg return err } - forwardablePod, err := f.AttachablePodForObject(obj, getPodTimeout) + forwardablePod, err := polymorphichelpers.AttachablePodForObjectFn(f, obj, getPodTimeout) if err != nil { return err } @@ -218,6 +219,7 @@ func (o *PortForwardOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, arg if err != nil { return err } + o.PodClient = clientset.Core() o.Config, err = f.ToRESTConfig() diff --git a/pkg/kubectl/cmd/rollout/BUILD b/pkg/kubectl/cmd/rollout/BUILD index 6bbdbf1f8f7..f87d5c9a1e6 100644 --- a/pkg/kubectl/cmd/rollout/BUILD +++ b/pkg/kubectl/cmd/rollout/BUILD @@ -26,6 +26,7 @@ go_library( "//pkg/kubectl/cmd/util:go_default_library", "//pkg/kubectl/genericclioptions:go_default_library", "//pkg/kubectl/genericclioptions/resource:go_default_library", + "//pkg/kubectl/polymorphichelpers:go_default_library", "//pkg/kubectl/scheme:go_default_library", "//pkg/kubectl/util/i18n:go_default_library", "//pkg/printers:go_default_library", diff --git a/pkg/kubectl/cmd/rollout/rollout_history.go b/pkg/kubectl/cmd/rollout/rollout_history.go index 7e381ef583c..5ace22c993f 100644 --- a/pkg/kubectl/cmd/rollout/rollout_history.go +++ b/pkg/kubectl/cmd/rollout/rollout_history.go @@ -24,6 +24,7 @@ import ( "k8s.io/kubernetes/pkg/kubectl/cmd/templates" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource" + "k8s.io/kubernetes/pkg/kubectl/polymorphichelpers" "k8s.io/kubernetes/pkg/kubectl/util/i18n" "github.com/spf13/cobra" @@ -97,7 +98,7 @@ func RunHistory(f cmdutil.Factory, cmd *cobra.Command, out io.Writer, args []str return err } mapping := info.ResourceMapping() - historyViewer, err := f.HistoryViewer(mapping) + historyViewer, err := polymorphichelpers.HistoryViewerFn(f, mapping) if err != nil { return err } diff --git a/pkg/kubectl/cmd/rollout/rollout_status.go b/pkg/kubectl/cmd/rollout/rollout_status.go index 930c85a587e..3182c4a8f37 100644 --- a/pkg/kubectl/cmd/rollout/rollout_status.go +++ b/pkg/kubectl/cmd/rollout/rollout_status.go @@ -19,6 +19,8 @@ package rollout import ( "fmt" + "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/watch" "k8s.io/kubernetes/pkg/api/legacyscheme" @@ -27,10 +29,9 @@ import ( cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/genericclioptions" "k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource" + "k8s.io/kubernetes/pkg/kubectl/polymorphichelpers" "k8s.io/kubernetes/pkg/kubectl/util/i18n" "k8s.io/kubernetes/pkg/util/interrupt" - - "github.com/spf13/cobra" ) var ( @@ -109,7 +110,9 @@ func (o *RolloutStatusOptions) Complete(f cmdutil.Factory, args []string) error } o.BuilderArgs = args - o.StatusViewer = f.StatusViewer + o.StatusViewer = func(mapping *meta.RESTMapping) (kubectl.StatusViewer, error) { + return polymorphichelpers.StatusViewerFn(f, mapping) + } return nil } diff --git a/pkg/kubectl/cmd/run.go b/pkg/kubectl/cmd/run.go index b824d2273a1..75b46b9f1c9 100644 --- a/pkg/kubectl/cmd/run.go +++ b/pkg/kubectl/cmd/run.go @@ -387,7 +387,7 @@ func (o *RunOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []string) e } opts.PodClient = clientset.Core() - attachablePod, err := f.AttachablePodForObject(runObject.Object, opts.GetPodTimeout) + attachablePod, err := polymorphichelpers.AttachablePodForObjectFn(f, runObject.Object, opts.GetPodTimeout) if err != nil { return err } diff --git a/pkg/kubectl/cmd/util/BUILD b/pkg/kubectl/cmd/util/BUILD index 694c9589e4f..eca56bc1cbb 100644 --- a/pkg/kubectl/cmd/util/BUILD +++ b/pkg/kubectl/cmd/util/BUILD @@ -17,19 +17,15 @@ go_library( 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", - "//pkg/apis/core/v1:go_default_library", "//pkg/apis/extensions:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library", - "//pkg/controller:go_default_library", "//pkg/kubectl:go_default_library", "//pkg/kubectl/cmd/templates:go_default_library", "//pkg/kubectl/cmd/util/openapi:go_default_library", "//pkg/kubectl/cmd/util/openapi/validation:go_default_library", "//pkg/kubectl/genericclioptions:go_default_library", "//pkg/kubectl/genericclioptions/resource:go_default_library", - "//pkg/kubectl/polymorphichelpers:go_default_library", "//pkg/kubectl/validation:go_default_library", "//pkg/printers:go_default_library", "//pkg/printers/internalversion:go_default_library", diff --git a/pkg/kubectl/cmd/util/factory.go b/pkg/kubectl/cmd/util/factory.go index 8d655dae538..8f867553028 100644 --- a/pkg/kubectl/cmd/util/factory.go +++ b/pkg/kubectl/cmd/util/factory.go @@ -20,7 +20,6 @@ import ( "fmt" "strconv" "strings" - "time" "github.com/spf13/cobra" @@ -139,20 +138,8 @@ type ObjectMappingFactory interface { // Returns a Describer for displaying the specified RESTMapping type or an error. Describer(mapping *meta.RESTMapping) (printers.Describer, error) - // Returns a HistoryViewer for viewing change history - HistoryViewer(mapping *meta.RESTMapping) (kubectl.HistoryViewer, 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 StatusViewer for printing rollout status. - StatusViewer(mapping *meta.RESTMapping) (kubectl.StatusViewer, error) - - // AttachablePodForObject returns the pod to which to attach given an object. - AttachablePodForObject(object runtime.Object, timeout time.Duration) (*api.Pod, error) - - // ApproximatePodTemplateForObject returns a pod template object for the provided source. - // It may return both an error and a object. It attempt to return the best possible template - // available at the current time. - ApproximatePodTemplateForObject(runtime.Object) (*api.PodTemplateSpec, error) // Returns a schema that can validate objects stored on disk. Validator(validate bool) (validation.Schema, error) diff --git a/pkg/kubectl/cmd/util/factory_object_mapping.go b/pkg/kubectl/cmd/util/factory_object_mapping.go index 802353fed32..496f6d10e6d 100644 --- a/pkg/kubectl/cmd/util/factory_object_mapping.go +++ b/pkg/kubectl/cmd/util/factory_object_mapping.go @@ -20,27 +20,16 @@ package util import ( "fmt" - "reflect" - "sort" "sync" - "time" - "k8s.io/api/core/v1" - corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/dynamic" restclient "k8s.io/client-go/rest" - "k8s.io/kubernetes/pkg/apis/batch" api "k8s.io/kubernetes/pkg/apis/core" - apiv1 "k8s.io/kubernetes/pkg/apis/core/v1" - "k8s.io/kubernetes/pkg/apis/extensions" - "k8s.io/kubernetes/pkg/controller" "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" - "k8s.io/kubernetes/pkg/kubectl/polymorphichelpers" "k8s.io/kubernetes/pkg/kubectl/validation" "k8s.io/kubernetes/pkg/printers" printersinternal "k8s.io/kubernetes/pkg/printers/internalversion" @@ -143,14 +132,6 @@ func genericDescriber(clientAccessFactory ClientAccessFactory, mapping *meta.RES return printersinternal.GenericDescriberFor(mapping, dynamicClient, eventsClient), nil } -func (f *ring1Factory) HistoryViewer(mapping *meta.RESTMapping) (kubectl.HistoryViewer, error) { - external, err := f.clientAccessFactory.KubernetesClientSet() - if err != nil { - return nil, err - } - return kubectl.HistoryViewerFor(mapping.GroupVersionKind.GroupKind(), external) -} - func (f *ring1Factory) Rollbacker(mapping *meta.RESTMapping) (kubectl.Rollbacker, error) { external, err := f.clientAccessFactory.KubernetesClientSet() if err != nil { @@ -159,61 +140,6 @@ func (f *ring1Factory) Rollbacker(mapping *meta.RESTMapping) (kubectl.Rollbacker return kubectl.RollbackerFor(mapping.GroupVersionKind.GroupKind(), external) } -func (f *ring1Factory) StatusViewer(mapping *meta.RESTMapping) (kubectl.StatusViewer, error) { - clientset, err := f.clientAccessFactory.KubernetesClientSet() - if err != nil { - return nil, err - } - return kubectl.StatusViewerFor(mapping.GroupVersionKind.GroupKind(), clientset) -} - -func (f *ring1Factory) ApproximatePodTemplateForObject(object runtime.Object) (*api.PodTemplateSpec, error) { - switch t := object.(type) { - case *api.Pod: - return &api.PodTemplateSpec{ - ObjectMeta: t.ObjectMeta, - Spec: t.Spec, - }, nil - case *api.ReplicationController: - return t.Spec.Template, nil - case *extensions.ReplicaSet: - return &t.Spec.Template, nil - case *extensions.DaemonSet: - return &t.Spec.Template, nil - case *extensions.Deployment: - return &t.Spec.Template, nil - case *batch.Job: - return &t.Spec.Template, nil - } - - return nil, fmt.Errorf("unable to extract pod template from type %v", reflect.TypeOf(object)) -} - -func (f *ring1Factory) AttachablePodForObject(object runtime.Object, timeout time.Duration) (*api.Pod, error) { - clientset, err := f.clientAccessFactory.ClientSet() - if err != nil { - return nil, err - } - - switch t := object.(type) { - case *api.Pod: - return t, nil - case *corev1.Pod: - internalPod := &api.Pod{} - err := apiv1.Convert_v1_Pod_To_core_Pod(t, internalPod, nil) - return internalPod, err - - } - - namespace, selector, err := polymorphichelpers.SelectorsForObject(object) - if err != nil { - return nil, fmt.Errorf("cannot attach to %T: %v", object, err) - } - sortBy := func(pods []*v1.Pod) sort.Interface { return sort.Reverse(controller.ActivePods(pods)) } - pod, _, err := polymorphichelpers.GetFirstPod(clientset.Core(), namespace, selector.String(), timeout, sortBy) - return pod, err -} - func (f *ring1Factory) Validator(validate bool) (validation.Schema, error) { if !validate { return validation.NullSchema{}, nil diff --git a/pkg/kubectl/polymorphichelpers/BUILD b/pkg/kubectl/polymorphichelpers/BUILD index 1b8fad5e891..cf624a54558 100644 --- a/pkg/kubectl/polymorphichelpers/BUILD +++ b/pkg/kubectl/polymorphichelpers/BUILD @@ -3,9 +3,12 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", srcs = [ + "attachablepodforobject.go", "helpers.go", + "historyviewer.go", "interface.go", "logsforobject.go", + "statusviewer.go", ], importpath = "k8s.io/kubernetes/pkg/kubectl/polymorphichelpers", visibility = ["//visibility:public"], @@ -18,6 +21,7 @@ go_library( "//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library", "//pkg/controller:go_default_library", + "//pkg/kubectl:go_default_library", "//pkg/kubectl/genericclioptions:go_default_library", "//vendor/k8s.io/api/apps/v1:go_default_library", "//vendor/k8s.io/api/apps/v1beta1:go_default_library", @@ -25,10 +29,12 @@ go_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/api/meta:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1: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/watch:go_default_library", + "//vendor/k8s.io/client-go/kubernetes:go_default_library", "//vendor/k8s.io/client-go/rest:go_default_library", ], ) diff --git a/pkg/kubectl/polymorphichelpers/attachablepodforobject.go b/pkg/kubectl/polymorphichelpers/attachablepodforobject.go new file mode 100644 index 00000000000..5e8b7f1850e --- /dev/null +++ b/pkg/kubectl/polymorphichelpers/attachablepodforobject.go @@ -0,0 +1,62 @@ +/* +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" + "sort" + "time" + + "k8s.io/api/core/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + api "k8s.io/kubernetes/pkg/apis/core" + apiv1 "k8s.io/kubernetes/pkg/apis/core/v1" + "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" + "k8s.io/kubernetes/pkg/controller" + "k8s.io/kubernetes/pkg/kubectl/genericclioptions" +) + +// attachablePodForObject returns the pod to which to attach given an object. +func attachablePodForObject(restClientGetter genericclioptions.RESTClientGetter, object runtime.Object, timeout time.Duration) (*api.Pod, error) { + switch t := object.(type) { + case *api.Pod: + return t, nil + case *corev1.Pod: + internalPod := &api.Pod{} + err := apiv1.Convert_v1_Pod_To_core_Pod(t, internalPod, nil) + return internalPod, err + + } + + clientConfig, err := restClientGetter.ToRESTConfig() + if err != nil { + return nil, err + } + clientset, err := internalclientset.NewForConfig(clientConfig) + if err != nil { + return nil, err + } + + namespace, selector, err := SelectorsForObject(object) + if err != nil { + return nil, fmt.Errorf("cannot attach to %T: %v", object, err) + } + sortBy := func(pods []*v1.Pod) sort.Interface { return sort.Reverse(controller.ActivePods(pods)) } + pod, _, err := GetFirstPod(clientset.Core(), namespace, selector.String(), timeout, sortBy) + return pod, err +} diff --git a/pkg/kubectl/polymorphichelpers/historyviewer.go b/pkg/kubectl/polymorphichelpers/historyviewer.go new file mode 100644 index 00000000000..b2742d84363 --- /dev/null +++ b/pkg/kubectl/polymorphichelpers/historyviewer.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 ( + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/client-go/kubernetes" + "k8s.io/kubernetes/pkg/kubectl" + "k8s.io/kubernetes/pkg/kubectl/genericclioptions" +) + +// historyViewer Returns a HistoryViewer for viewing change history +func historyViewer(restClientGetter genericclioptions.RESTClientGetter, mapping *meta.RESTMapping) (kubectl.HistoryViewer, error) { + clientConfig, err := restClientGetter.ToRESTConfig() + if err != nil { + return nil, err + } + + external, err := kubernetes.NewForConfig(clientConfig) + if err != nil { + return nil, err + } + return kubectl.HistoryViewerFor(mapping.GroupVersionKind.GroupKind(), external) +} diff --git a/pkg/kubectl/polymorphichelpers/interface.go b/pkg/kubectl/polymorphichelpers/interface.go index 88da4ae9e66..63e1006318a 100644 --- a/pkg/kubectl/polymorphichelpers/interface.go +++ b/pkg/kubectl/polymorphichelpers/interface.go @@ -19,8 +19,11 @@ package polymorphichelpers import ( "time" + "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/rest" + api "k8s.io/kubernetes/pkg/apis/core" + "k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl/genericclioptions" ) @@ -29,3 +32,21 @@ type LogsForObjectFunc func(restClientGetter genericclioptions.RESTClientGetter, // LogsForObjectFn gives a way to easily override the function for unit testing if needed. var LogsForObjectFn LogsForObjectFunc = logsForObject + +// AttachableLogsForObjectFunc is a function type that can tell you how to get the pod for which to attach a given object +type AttachableLogsForObjectFunc func(restClientGetter genericclioptions.RESTClientGetter, object runtime.Object, timeout time.Duration) (*api.Pod, error) + +// AttachablePodForObjectFn gives a way to easily override the function for unit testing if needed. +var AttachablePodForObjectFn AttachableLogsForObjectFunc = attachablePodForObject + +// HistoryViewerFunc is a function type that can tell you how to view change history +type HistoryViewerFunc func(restClientGetter genericclioptions.RESTClientGetter, mapping *meta.RESTMapping) (kubectl.HistoryViewer, error) + +// HistoryViewerFn gives a way to easily override the function for unit testing if needed +var HistoryViewerFn HistoryViewerFunc = historyViewer + +// StatusViewerFunc is a function type that can tell you how to print rollout status +type StatusViewerFunc func(restClientGetter genericclioptions.RESTClientGetter, mapping *meta.RESTMapping) (kubectl.StatusViewer, error) + +// StatusViewerFn gives a way to easily override the function for unit testing if needed +var StatusViewerFn StatusViewerFunc = statusViewer diff --git a/pkg/kubectl/polymorphichelpers/statusviewer.go b/pkg/kubectl/polymorphichelpers/statusviewer.go new file mode 100644 index 00000000000..043d1e31cdf --- /dev/null +++ b/pkg/kubectl/polymorphichelpers/statusviewer.go @@ -0,0 +1,37 @@ +/* +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" +) + +// statusViewer returns a StatusViewer for printing rollout status. +func statusViewer(restClientGetter genericclioptions.RESTClientGetter, mapping *meta.RESTMapping) (kubectl.StatusViewer, error) { + clientConfig, err := restClientGetter.ToRESTConfig() + if err != nil { + return nil, err + } + clientset, err := kubernetes.NewForConfig(clientConfig) + if err != nil { + return nil, err + } + return kubectl.StatusViewerFor(mapping.GroupVersionKind.GroupKind(), clientset) +}