mirror of https://github.com/k3s-io/k3s
start splitting polymorphic functions out of the factory
parent
0db40da909
commit
eabfcfaa2b
|
@ -205,6 +205,7 @@ filegroup(
|
||||||
"//pkg/kubectl/genericclioptions:all-srcs",
|
"//pkg/kubectl/genericclioptions:all-srcs",
|
||||||
"//pkg/kubectl/metricsutil:all-srcs",
|
"//pkg/kubectl/metricsutil:all-srcs",
|
||||||
"//pkg/kubectl/plugins:all-srcs",
|
"//pkg/kubectl/plugins:all-srcs",
|
||||||
|
"//pkg/kubectl/polymorphichelpers:all-srcs",
|
||||||
"//pkg/kubectl/proxy:all-srcs",
|
"//pkg/kubectl/proxy:all-srcs",
|
||||||
"//pkg/kubectl/scheme:all-srcs",
|
"//pkg/kubectl/scheme:all-srcs",
|
||||||
"//pkg/kubectl/util:all-srcs",
|
"//pkg/kubectl/util:all-srcs",
|
||||||
|
|
|
@ -82,6 +82,7 @@ go_library(
|
||||||
"//pkg/kubectl/genericclioptions/resource:go_default_library",
|
"//pkg/kubectl/genericclioptions/resource:go_default_library",
|
||||||
"//pkg/kubectl/metricsutil:go_default_library",
|
"//pkg/kubectl/metricsutil:go_default_library",
|
||||||
"//pkg/kubectl/plugins:go_default_library",
|
"//pkg/kubectl/plugins:go_default_library",
|
||||||
|
"//pkg/kubectl/polymorphichelpers:go_default_library",
|
||||||
"//pkg/kubectl/proxy:go_default_library",
|
"//pkg/kubectl/proxy:go_default_library",
|
||||||
"//pkg/kubectl/scheme:go_default_library",
|
"//pkg/kubectl/scheme:go_default_library",
|
||||||
"//pkg/kubectl/util:go_default_library",
|
"//pkg/kubectl/util:go_default_library",
|
||||||
|
@ -193,6 +194,7 @@ go_test(
|
||||||
"//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",
|
||||||
|
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||||
"//pkg/kubectl:go_default_library",
|
"//pkg/kubectl:go_default_library",
|
||||||
"//pkg/kubectl/cmd/create:go_default_library",
|
"//pkg/kubectl/cmd/create:go_default_library",
|
||||||
"//pkg/kubectl/cmd/testing:go_default_library",
|
"//pkg/kubectl/cmd/testing:go_default_library",
|
||||||
|
@ -201,6 +203,7 @@ go_test(
|
||||||
"//pkg/kubectl/genericclioptions:go_default_library",
|
"//pkg/kubectl/genericclioptions:go_default_library",
|
||||||
"//pkg/kubectl/genericclioptions/resource:go_default_library",
|
"//pkg/kubectl/genericclioptions/resource:go_default_library",
|
||||||
"//pkg/kubectl/plugins:go_default_library",
|
"//pkg/kubectl/plugins:go_default_library",
|
||||||
|
"//pkg/kubectl/polymorphichelpers:go_default_library",
|
||||||
"//pkg/kubectl/scheme:go_default_library",
|
"//pkg/kubectl/scheme:go_default_library",
|
||||||
"//pkg/kubectl/util/i18n:go_default_library",
|
"//pkg/kubectl/util/i18n:go_default_library",
|
||||||
"//pkg/kubectl/util/term:go_default_library",
|
"//pkg/kubectl/util/term:go_default_library",
|
||||||
|
|
|
@ -26,14 +26,13 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
restclient "k8s.io/client-go/rest"
|
|
||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
"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/genericclioptions"
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/polymorphichelpers"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||||
"k8s.io/kubernetes/pkg/printers"
|
"k8s.io/kubernetes/pkg/printers"
|
||||||
)
|
)
|
||||||
|
@ -46,10 +45,11 @@ type ClusterInfoDumpOptions struct {
|
||||||
AllNamespaces bool
|
AllNamespaces bool
|
||||||
Namespaces []string
|
Namespaces []string
|
||||||
|
|
||||||
timeout time.Duration
|
Timeout time.Duration
|
||||||
clientset internalclientset.Interface
|
Clientset internalclientset.Interface
|
||||||
namespace string
|
Namespace string
|
||||||
logsForObject func(object, options runtime.Object, timeout time.Duration) (*restclient.Request, error)
|
RESTClientGetter genericclioptions.RESTClientGetter
|
||||||
|
LogsForObject polymorphichelpers.LogsForObjectFunc
|
||||||
|
|
||||||
genericclioptions.IOStreams
|
genericclioptions.IOStreams
|
||||||
}
|
}
|
||||||
|
@ -126,25 +126,27 @@ func (o *ClusterInfoDumpOptions) Complete(f cmdutil.Factory, cmd *cobra.Command)
|
||||||
o.PrintFlags.OutputFormat = &jsonOutputFmt
|
o.PrintFlags.OutputFormat = &jsonOutputFmt
|
||||||
o.PrintObj = printer.PrintObj
|
o.PrintObj = printer.PrintObj
|
||||||
|
|
||||||
o.timeout, err = cmdutil.GetPodRunningTimeoutFlag(cmd)
|
o.Timeout, err = cmdutil.GetPodRunningTimeoutFlag(cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
o.clientset, err = f.ClientSet()
|
o.Clientset, err = f.ClientSet()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
o.namespace, _, err = f.DefaultNamespace()
|
o.Namespace, _, err = f.DefaultNamespace()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
o.logsForObject = f.LogsForObject
|
// TODO this should eventually just be the completed kubeconfigflag struct
|
||||||
|
o.RESTClientGetter = f
|
||||||
|
o.LogsForObject = polymorphichelpers.LogsForObjectFn
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ClusterInfoDumpOptions) Run() error {
|
func (o *ClusterInfoDumpOptions) Run() error {
|
||||||
nodes, err := o.clientset.Core().Nodes().List(metav1.ListOptions{})
|
nodes, err := o.Clientset.Core().Nodes().List(metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -155,7 +157,7 @@ func (o *ClusterInfoDumpOptions) Run() error {
|
||||||
|
|
||||||
var namespaces []string
|
var namespaces []string
|
||||||
if o.AllNamespaces {
|
if o.AllNamespaces {
|
||||||
namespaceList, err := o.clientset.Core().Namespaces().List(metav1.ListOptions{})
|
namespaceList, err := o.Clientset.Core().Namespaces().List(metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -166,14 +168,14 @@ func (o *ClusterInfoDumpOptions) Run() error {
|
||||||
if len(o.Namespaces) == 0 {
|
if len(o.Namespaces) == 0 {
|
||||||
namespaces = []string{
|
namespaces = []string{
|
||||||
metav1.NamespaceSystem,
|
metav1.NamespaceSystem,
|
||||||
o.namespace,
|
o.Namespace,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, namespace := range namespaces {
|
for _, namespace := range namespaces {
|
||||||
// TODO: this is repetitive in the extreme. Use reflection or
|
// TODO: this is repetitive in the extreme. Use reflection or
|
||||||
// something to make this a for loop.
|
// something to make this a for loop.
|
||||||
events, err := o.clientset.Core().Events(namespace).List(metav1.ListOptions{})
|
events, err := o.Clientset.Core().Events(namespace).List(metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -181,7 +183,7 @@ func (o *ClusterInfoDumpOptions) Run() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
rcs, err := o.clientset.Core().ReplicationControllers(namespace).List(metav1.ListOptions{})
|
rcs, err := o.Clientset.Core().ReplicationControllers(namespace).List(metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -189,7 +191,7 @@ func (o *ClusterInfoDumpOptions) Run() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
svcs, err := o.clientset.Core().Services(namespace).List(metav1.ListOptions{})
|
svcs, err := o.Clientset.Core().Services(namespace).List(metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -197,7 +199,7 @@ func (o *ClusterInfoDumpOptions) Run() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sets, err := o.clientset.Extensions().DaemonSets(namespace).List(metav1.ListOptions{})
|
sets, err := o.Clientset.Extensions().DaemonSets(namespace).List(metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -205,7 +207,7 @@ func (o *ClusterInfoDumpOptions) Run() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
deps, err := o.clientset.Extensions().Deployments(namespace).List(metav1.ListOptions{})
|
deps, err := o.Clientset.Extensions().Deployments(namespace).List(metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -213,7 +215,7 @@ func (o *ClusterInfoDumpOptions) Run() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
rps, err := o.clientset.Extensions().ReplicaSets(namespace).List(metav1.ListOptions{})
|
rps, err := o.Clientset.Extensions().ReplicaSets(namespace).List(metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -221,7 +223,7 @@ func (o *ClusterInfoDumpOptions) Run() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
pods, err := o.clientset.Core().Pods(namespace).List(metav1.ListOptions{})
|
pods, err := o.Clientset.Core().Pods(namespace).List(metav1.ListOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -234,7 +236,7 @@ func (o *ClusterInfoDumpOptions) Run() error {
|
||||||
writer.Write([]byte(fmt.Sprintf("==== START logs for container %s of pod %s/%s ====\n", container.Name, pod.Namespace, pod.Name)))
|
writer.Write([]byte(fmt.Sprintf("==== START logs for container %s of pod %s/%s ====\n", container.Name, pod.Namespace, pod.Name)))
|
||||||
defer writer.Write([]byte(fmt.Sprintf("==== END logs for container %s of pod %s/%s ====\n", container.Name, pod.Namespace, pod.Name)))
|
defer writer.Write([]byte(fmt.Sprintf("==== END logs for container %s of pod %s/%s ====\n", container.Name, pod.Namespace, pod.Name)))
|
||||||
|
|
||||||
request, err := o.logsForObject(pod, &api.PodLogOptions{Container: container.Name}, timeout)
|
request, err := o.LogsForObject(o.RESTClientGetter, pod, &api.PodLogOptions{Container: container.Name}, timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Print error and return.
|
// Print error and return.
|
||||||
writer.Write([]byte(fmt.Sprintf("Create log request error: %s\n", err.Error())))
|
writer.Write([]byte(fmt.Sprintf("Create log request error: %s\n", err.Error())))
|
||||||
|
|
|
@ -399,7 +399,7 @@ func NewDownloader(f cmdutil.Factory) (*Downloader, error) {
|
||||||
var err error
|
var err error
|
||||||
var d Downloader
|
var d Downloader
|
||||||
|
|
||||||
d.mapper, err = f.RESTMapper()
|
d.mapper, err = f.ToRESTMapper()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,16 +26,15 @@ import (
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"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/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
restclient "k8s.io/client-go/rest"
|
|
||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/apis/core/validation"
|
"k8s.io/kubernetes/pkg/apis/core/validation"
|
||||||
"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/genericclioptions"
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/polymorphichelpers"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/util"
|
"k8s.io/kubernetes/pkg/kubectl/util"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||||
)
|
)
|
||||||
|
@ -82,13 +81,10 @@ type LogsOptions struct {
|
||||||
AllContainers bool
|
AllContainers bool
|
||||||
Options runtime.Object
|
Options runtime.Object
|
||||||
|
|
||||||
Mapper meta.RESTMapper
|
Object runtime.Object
|
||||||
Typer runtime.ObjectTyper
|
GetPodTimeout time.Duration
|
||||||
Decoder runtime.Decoder
|
RESTClientGetter genericclioptions.RESTClientGetter
|
||||||
|
LogsForObject polymorphichelpers.LogsForObjectFunc
|
||||||
Object runtime.Object
|
|
||||||
GetPodTimeout time.Duration
|
|
||||||
LogsForObject func(object, options runtime.Object, timeout time.Duration) (*restclient.Request, error)
|
|
||||||
|
|
||||||
genericclioptions.IOStreams
|
genericclioptions.IOStreams
|
||||||
}
|
}
|
||||||
|
@ -196,7 +192,8 @@ func (o *LogsOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []str
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
o.Options = logOptions
|
o.Options = logOptions
|
||||||
o.LogsForObject = f.LogsForObject
|
o.RESTClientGetter = f
|
||||||
|
o.LogsForObject = polymorphichelpers.LogsForObjectFn
|
||||||
|
|
||||||
if len(selector) != 0 {
|
if len(selector) != 0 {
|
||||||
if logOptions.Follow {
|
if logOptions.Follow {
|
||||||
|
@ -286,7 +283,7 @@ func (o LogsOptions) getPodLogs(pod *api.Pod) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o LogsOptions) getLogs(obj runtime.Object) error {
|
func (o LogsOptions) getLogs(obj runtime.Object) error {
|
||||||
req, err := o.LogsForObject(obj, o.Options, o.GetPodTimeout)
|
req, err := o.LogsForObject(o.RESTClientGetter, obj, o.Options, o.GetPodTimeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,19 +18,27 @@ package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"fmt"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
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/legacyscheme"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/polymorphichelpers"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -74,6 +82,16 @@ func TestLog(t *testing.T) {
|
||||||
}
|
}
|
||||||
tf.Namespace = "test"
|
tf.Namespace = "test"
|
||||||
tf.ClientConfigVal = defaultClientConfig()
|
tf.ClientConfigVal = defaultClientConfig()
|
||||||
|
oldLogFn := polymorphichelpers.LogsForObjectFn
|
||||||
|
defer func() {
|
||||||
|
polymorphichelpers.LogsForObjectFn = oldLogFn
|
||||||
|
}()
|
||||||
|
clientset, err := tf.ClientSet()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
polymorphichelpers.LogsForObjectFn = logTestMock{client: clientset}.logsForObject
|
||||||
|
|
||||||
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
streams, _, buf, _ := genericclioptions.NewTestIOStreams()
|
||||||
|
|
||||||
cmd := NewCmdLogs(tf, streams)
|
cmd := NewCmdLogs(tf, streams)
|
||||||
|
@ -221,3 +239,20 @@ func TestLogComplete(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type logTestMock struct {
|
||||||
|
client internalclientset.Interface
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m logTestMock) logsForObject(restClientGetter genericclioptions.RESTClientGetter, object, options runtime.Object, timeout time.Duration) (*restclient.Request, error) {
|
||||||
|
switch t := object.(type) {
|
||||||
|
case *api.Pod:
|
||||||
|
opts, ok := options.(*api.PodLogOptions)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("provided options object is not a PodLogOptions")
|
||||||
|
}
|
||||||
|
return m.client.Core().Pods(t.Namespace).GetLogs(t.Name, opts), nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("cannot get the logs from %T", object)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ import (
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/polymorphichelpers"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||||
"k8s.io/kubernetes/pkg/util/interrupt"
|
"k8s.io/kubernetes/pkg/util/interrupt"
|
||||||
|
@ -525,13 +526,13 @@ func handleAttachPod(f cmdutil.Factory, podClient coreclient.PodsGetter, ns, nam
|
||||||
}
|
}
|
||||||
|
|
||||||
// logOpts logs output from opts to the pods log.
|
// logOpts logs output from opts to the pods log.
|
||||||
func logOpts(f cmdutil.Factory, pod *api.Pod, opts *AttachOptions) error {
|
func logOpts(restClientGetter genericclioptions.RESTClientGetter, pod *api.Pod, opts *AttachOptions) error {
|
||||||
ctrName, err := opts.GetContainerName(pod)
|
ctrName, err := opts.GetContainerName(pod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := f.LogsForObject(pod, &api.PodLogOptions{Container: ctrName}, opts.GetPodTimeout)
|
req, err := polymorphichelpers.LogsForObjectFn(restClientGetter, pod, &api.PodLogOptions{Container: ctrName}, opts.GetPodTimeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ go_library(
|
||||||
visibility = ["//build/visible_to:pkg_kubectl_cmd_testing_CONSUMERS"],
|
visibility = ["//build/visible_to:pkg_kubectl_cmd_testing_CONSUMERS"],
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/api/legacyscheme:go_default_library",
|
"//pkg/api/legacyscheme:go_default_library",
|
||||||
"//pkg/apis/core:go_default_library",
|
|
||||||
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
"//pkg/client/clientset_generated/internalclientset:go_default_library",
|
||||||
"//pkg/kubectl:go_default_library",
|
"//pkg/kubectl:go_default_library",
|
||||||
"//pkg/kubectl/cmd/util:go_default_library",
|
"//pkg/kubectl/cmd/util:go_default_library",
|
||||||
|
|
|
@ -44,7 +44,6 @@ import (
|
||||||
"k8s.io/client-go/tools/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
"k8s.io/kubernetes/pkg/kubectl"
|
"k8s.io/kubernetes/pkg/kubectl"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
|
@ -446,24 +445,6 @@ func testRESTMapper() meta.RESTMapper {
|
||||||
return expander
|
return expander
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *TestFactory) LogsForObject(object, options runtime.Object, timeout time.Duration) (*restclient.Request, error) {
|
|
||||||
c, err := f.ClientSet()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch t := object.(type) {
|
|
||||||
case *api.Pod:
|
|
||||||
opts, ok := options.(*api.PodLogOptions)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("provided options object is not a PodLogOptions")
|
|
||||||
}
|
|
||||||
return c.Core().Pods(f.Namespace).GetLogs(t.Name, opts), nil
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("cannot get the logs from %T", object)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *TestFactory) ScaleClient() (scaleclient.ScalesGetter, error) {
|
func (f *TestFactory) ScaleClient() (scaleclient.ScalesGetter, error) {
|
||||||
return f.ScaleGetter, nil
|
return f.ScaleGetter, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,13 +22,14 @@ go_library(
|
||||||
"//pkg/apis/core/v1:go_default_library",
|
"//pkg/apis/core/v1:go_default_library",
|
||||||
"//pkg/apis/extensions:go_default_library",
|
"//pkg/apis/extensions:go_default_library",
|
||||||
"//pkg/client/clientset_generated/internalclientset:go_default_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/controller:go_default_library",
|
||||||
"//pkg/kubectl:go_default_library",
|
"//pkg/kubectl:go_default_library",
|
||||||
"//pkg/kubectl/cmd/templates:go_default_library",
|
"//pkg/kubectl/cmd/templates:go_default_library",
|
||||||
"//pkg/kubectl/cmd/util/openapi:go_default_library",
|
"//pkg/kubectl/cmd/util/openapi:go_default_library",
|
||||||
"//pkg/kubectl/cmd/util/openapi/validation: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/genericclioptions/resource:go_default_library",
|
||||||
|
"//pkg/kubectl/polymorphichelpers:go_default_library",
|
||||||
"//pkg/kubectl/validation:go_default_library",
|
"//pkg/kubectl/validation:go_default_library",
|
||||||
"//pkg/printers:go_default_library",
|
"//pkg/printers:go_default_library",
|
||||||
"//pkg/printers/internalversion:go_default_library",
|
"//pkg/printers/internalversion:go_default_library",
|
||||||
|
@ -49,13 +50,11 @@ go_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",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/labels: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",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/util/errors: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/apimachinery/pkg/util/yaml:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/util/yaml:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
|
||||||
"//vendor/k8s.io/client-go/discovery:go_default_library",
|
"//vendor/k8s.io/client-go/discovery:go_default_library",
|
||||||
"//vendor/k8s.io/client-go/dynamic:go_default_library",
|
"//vendor/k8s.io/client-go/dynamic:go_default_library",
|
||||||
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
|
||||||
|
@ -69,7 +68,6 @@ go_library(
|
||||||
go_test(
|
go_test(
|
||||||
name = "go_default_test",
|
name = "go_default_test",
|
||||||
srcs = [
|
srcs = [
|
||||||
"factory_object_mapping_test.go",
|
|
||||||
"factory_test.go",
|
"factory_test.go",
|
||||||
"helpers_test.go",
|
"helpers_test.go",
|
||||||
],
|
],
|
||||||
|
@ -77,28 +75,17 @@ go_test(
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/api/testapi:go_default_library",
|
"//pkg/api/testapi:go_default_library",
|
||||||
"//pkg/api/testing:go_default_library",
|
"//pkg/api/testing:go_default_library",
|
||||||
"//pkg/apis/apps: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/client/clientset_generated/internalclientset:go_default_library",
|
|
||||||
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
|
|
||||||
"//pkg/controller:go_default_library",
|
|
||||||
"//pkg/kubectl:go_default_library",
|
"//pkg/kubectl:go_default_library",
|
||||||
"//pkg/kubectl/genericclioptions:go_default_library",
|
"//pkg/kubectl/genericclioptions:go_default_library",
|
||||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
|
||||||
"//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/api/equality: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",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/labels: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",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/util/diff: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/apimachinery/pkg/util/validation/field:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
|
||||||
"//vendor/k8s.io/client-go/testing:go_default_library",
|
|
||||||
"//vendor/k8s.io/utils/exec:go_default_library",
|
"//vendor/k8s.io/utils/exec:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -18,7 +18,6 @@ package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
@ -27,21 +26,17 @@ import (
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
"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"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apimachinery/pkg/watch"
|
|
||||||
"k8s.io/client-go/discovery"
|
|
||||||
"k8s.io/client-go/dynamic"
|
"k8s.io/client-go/dynamic"
|
||||||
"k8s.io/client-go/kubernetes"
|
"k8s.io/client-go/kubernetes"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
scaleclient "k8s.io/client-go/scale"
|
scaleclient "k8s.io/client-go/scale"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
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/client/clientset_generated/internalclientset"
|
||||||
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
|
||||||
"k8s.io/kubernetes/pkg/kubectl"
|
"k8s.io/kubernetes/pkg/kubectl"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/validation"
|
"k8s.io/kubernetes/pkg/kubectl/validation"
|
||||||
"k8s.io/kubernetes/pkg/printers"
|
"k8s.io/kubernetes/pkg/printers"
|
||||||
|
@ -67,14 +62,7 @@ type Factory interface {
|
||||||
// Generally provides discovery, negotiation, and no-dep calls.
|
// Generally provides discovery, negotiation, and no-dep calls.
|
||||||
// TODO The polymorphic calls probably deserve their own interface.
|
// TODO The polymorphic calls probably deserve their own interface.
|
||||||
type ClientAccessFactory interface {
|
type ClientAccessFactory interface {
|
||||||
// Returns a client.Config for accessing the Kubernetes server.
|
genericclioptions.RESTClientGetter
|
||||||
ToRESTConfig() (*restclient.Config, error)
|
|
||||||
// Returns interfaces for dealing with arbitrary runtime.Objects.
|
|
||||||
ToRESTMapper() (meta.RESTMapper, error)
|
|
||||||
// Returns a discovery client
|
|
||||||
ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error)
|
|
||||||
// Returns kubeconfig loader
|
|
||||||
ToRawKubeConfigLoader() clientcmd.ClientConfig
|
|
||||||
|
|
||||||
// ClientSet gives you back an internal, generated clientset
|
// ClientSet gives you back an internal, generated clientset
|
||||||
ClientSet() (internalclientset.Interface, error)
|
ClientSet() (internalclientset.Interface, error)
|
||||||
|
@ -151,8 +139,6 @@ type ObjectMappingFactory interface {
|
||||||
// Returns a Describer for displaying the specified RESTMapping type or an error.
|
// Returns a Describer for displaying the specified RESTMapping type or an error.
|
||||||
Describer(mapping *meta.RESTMapping) (printers.Describer, error)
|
Describer(mapping *meta.RESTMapping) (printers.Describer, error)
|
||||||
|
|
||||||
// LogsForObject returns a request for the logs associated with the provided object
|
|
||||||
LogsForObject(object, options runtime.Object, timeout time.Duration) (*restclient.Request, error)
|
|
||||||
// Returns a HistoryViewer for viewing change history
|
// Returns a HistoryViewer for viewing change history
|
||||||
HistoryViewer(mapping *meta.RESTMapping) (kubectl.HistoryViewer, error)
|
HistoryViewer(mapping *meta.RESTMapping) (kubectl.HistoryViewer, error)
|
||||||
// Returns a Rollbacker for changing the rollback version of the specified RESTMapping type or an error
|
// Returns a Rollbacker for changing the rollback version of the specified RESTMapping type or an error
|
||||||
|
@ -191,7 +177,7 @@ type factory struct {
|
||||||
|
|
||||||
// NewFactory creates a factory with the default Kubernetes resources defined
|
// NewFactory creates a factory with the default Kubernetes resources defined
|
||||||
// Receives a clientGetter capable of providing a discovery client and a REST client configuration.
|
// Receives a clientGetter capable of providing a discovery client and a REST client configuration.
|
||||||
func NewFactory(clientGetter RESTClientGetter) Factory {
|
func NewFactory(clientGetter genericclioptions.RESTClientGetter) Factory {
|
||||||
clientAccessFactory := NewClientAccessFactory(clientGetter)
|
clientAccessFactory := NewClientAccessFactory(clientGetter)
|
||||||
objectMappingFactory := NewObjectMappingFactory(clientAccessFactory)
|
objectMappingFactory := NewObjectMappingFactory(clientAccessFactory)
|
||||||
builderFactory := NewBuilderFactory(clientAccessFactory, objectMappingFactory)
|
builderFactory := NewBuilderFactory(clientAccessFactory, objectMappingFactory)
|
||||||
|
@ -203,51 +189,6 @@ func NewFactory(clientGetter RESTClientGetter) Factory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFirstPod returns a pod matching the namespace and label selector
|
|
||||||
// and the number of all pods that match the label selector.
|
|
||||||
func GetFirstPod(client coreclient.PodsGetter, namespace string, selector string, timeout time.Duration, sortBy func([]*v1.Pod) sort.Interface) (*api.Pod, int, error) {
|
|
||||||
options := metav1.ListOptions{LabelSelector: selector}
|
|
||||||
|
|
||||||
podList, err := client.Pods(namespace).List(options)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
pods := []*v1.Pod{}
|
|
||||||
for i := range podList.Items {
|
|
||||||
pod := podList.Items[i]
|
|
||||||
externalPod := &v1.Pod{}
|
|
||||||
apiv1.Convert_core_Pod_To_v1_Pod(&pod, externalPod, nil)
|
|
||||||
pods = append(pods, externalPod)
|
|
||||||
}
|
|
||||||
if len(pods) > 0 {
|
|
||||||
sort.Sort(sortBy(pods))
|
|
||||||
internalPod := &api.Pod{}
|
|
||||||
apiv1.Convert_v1_Pod_To_core_Pod(pods[0], internalPod, nil)
|
|
||||||
return internalPod, len(podList.Items), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Watch until we observe a pod
|
|
||||||
options.ResourceVersion = podList.ResourceVersion
|
|
||||||
w, err := client.Pods(namespace).Watch(options)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
defer w.Stop()
|
|
||||||
|
|
||||||
condition := func(event watch.Event) (bool, error) {
|
|
||||||
return event.Type == watch.Added || event.Type == watch.Modified, nil
|
|
||||||
}
|
|
||||||
event, err := watch.Until(timeout, w, condition)
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
pod, ok := event.Object.(*api.Pod)
|
|
||||||
if !ok {
|
|
||||||
return nil, 0, fmt.Errorf("%#v is not a pod event", event)
|
|
||||||
}
|
|
||||||
return pod, 1, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func makePortsString(ports []api.ServicePort, useNodePort bool) string {
|
func makePortsString(ports []api.ServicePort, useNodePort bool) string {
|
||||||
pieces := make([]string, len(ports))
|
pieces := make([]string, len(ports))
|
||||||
for ix := range ports {
|
for ix := range ports {
|
||||||
|
|
|
@ -55,21 +55,15 @@ import (
|
||||||
"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"
|
||||||
"k8s.io/kubernetes/pkg/kubectl"
|
"k8s.io/kubernetes/pkg/kubectl"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RESTClientGetter interface {
|
|
||||||
ToRESTConfig() (*restclient.Config, error)
|
|
||||||
ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error)
|
|
||||||
ToRESTMapper() (meta.RESTMapper, error)
|
|
||||||
ToRawKubeConfigLoader() clientcmd.ClientConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
type ring0Factory struct {
|
type ring0Factory struct {
|
||||||
clientGetter RESTClientGetter
|
clientGetter genericclioptions.RESTClientGetter
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewClientAccessFactory(clientGetter RESTClientGetter) ClientAccessFactory {
|
func NewClientAccessFactory(clientGetter genericclioptions.RESTClientGetter) ClientAccessFactory {
|
||||||
if clientGetter == nil {
|
if clientGetter == nil {
|
||||||
panic("attempt to instantiate client_access_factory with nil clientGetter")
|
panic("attempt to instantiate client_access_factory with nil clientGetter")
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,28 +19,18 @@ limitations under the License.
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
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"
|
"k8s.io/api/core/v1"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/client-go/dynamic"
|
"k8s.io/client-go/dynamic"
|
||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
"k8s.io/kubernetes/pkg/apis/apps"
|
|
||||||
"k8s.io/kubernetes/pkg/apis/batch"
|
"k8s.io/kubernetes/pkg/apis/batch"
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
apiv1 "k8s.io/kubernetes/pkg/apis/core/v1"
|
apiv1 "k8s.io/kubernetes/pkg/apis/core/v1"
|
||||||
|
@ -50,6 +40,7 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi"
|
||||||
openapivalidation "k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi/validation"
|
openapivalidation "k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi/validation"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/polymorphichelpers"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/validation"
|
"k8s.io/kubernetes/pkg/kubectl/validation"
|
||||||
"k8s.io/kubernetes/pkg/printers"
|
"k8s.io/kubernetes/pkg/printers"
|
||||||
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
printersinternal "k8s.io/kubernetes/pkg/printers/internalversion"
|
||||||
|
@ -152,186 +143,6 @@ func genericDescriber(clientAccessFactory ClientAccessFactory, mapping *meta.RES
|
||||||
return printersinternal.GenericDescriberFor(mapping, dynamicClient, eventsClient), nil
|
return printersinternal.GenericDescriberFor(mapping, dynamicClient, eventsClient), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *ring1Factory) LogsForObject(object, options runtime.Object, timeout time.Duration) (*restclient.Request, error) {
|
|
||||||
clientset, err := f.clientAccessFactory.ClientSet()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
opts, ok := options.(*api.PodLogOptions)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("provided options object is not a PodLogOptions")
|
|
||||||
}
|
|
||||||
|
|
||||||
switch t := object.(type) {
|
|
||||||
case *api.Pod:
|
|
||||||
return clientset.Core().Pods(t.Namespace).GetLogs(t.Name, opts), nil
|
|
||||||
case *corev1.Pod:
|
|
||||||
return clientset.Core().Pods(t.Namespace).GetLogs(t.Name, opts), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace, selector, err := selectorsForObject(object)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("cannot get the logs from %T: %v", object, err)
|
|
||||||
}
|
|
||||||
sortBy := func(pods []*v1.Pod) sort.Interface { return controller.ByLogging(pods) }
|
|
||||||
pod, numPods, err := GetFirstPod(clientset.Core(), namespace, selector.String(), timeout, sortBy)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if numPods > 1 {
|
|
||||||
fmt.Fprintf(os.Stderr, "Found %v pods, using pod/%v\n", numPods, pod.Name)
|
|
||||||
}
|
|
||||||
return clientset.Core().Pods(pod.Namespace).GetLogs(pod.Name, opts), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func selectorsForObject(object runtime.Object) (namespace string, selector labels.Selector, err error) {
|
|
||||||
switch t := object.(type) {
|
|
||||||
case *extensions.ReplicaSet:
|
|
||||||
namespace = t.Namespace
|
|
||||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
|
||||||
}
|
|
||||||
case *extensionsv1beta1.ReplicaSet:
|
|
||||||
namespace = t.Namespace
|
|
||||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
|
||||||
}
|
|
||||||
case *appsv1.ReplicaSet:
|
|
||||||
namespace = t.Namespace
|
|
||||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
|
||||||
}
|
|
||||||
case *appsv1beta2.ReplicaSet:
|
|
||||||
namespace = t.Namespace
|
|
||||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
case *api.ReplicationController:
|
|
||||||
namespace = t.Namespace
|
|
||||||
selector = labels.SelectorFromSet(t.Spec.Selector)
|
|
||||||
case *corev1.ReplicationController:
|
|
||||||
namespace = t.Namespace
|
|
||||||
selector = labels.SelectorFromSet(t.Spec.Selector)
|
|
||||||
|
|
||||||
case *apps.StatefulSet:
|
|
||||||
namespace = t.Namespace
|
|
||||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
|
||||||
}
|
|
||||||
case *appsv1.StatefulSet:
|
|
||||||
namespace = t.Namespace
|
|
||||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
|
||||||
}
|
|
||||||
case *appsv1beta1.StatefulSet:
|
|
||||||
namespace = t.Namespace
|
|
||||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
|
||||||
}
|
|
||||||
case *appsv1beta2.StatefulSet:
|
|
||||||
namespace = t.Namespace
|
|
||||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
case *extensions.DaemonSet:
|
|
||||||
namespace = t.Namespace
|
|
||||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
|
||||||
}
|
|
||||||
case *extensionsv1beta1.DaemonSet:
|
|
||||||
namespace = t.Namespace
|
|
||||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
|
||||||
}
|
|
||||||
case *appsv1.DaemonSet:
|
|
||||||
namespace = t.Namespace
|
|
||||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
|
||||||
}
|
|
||||||
case *appsv1beta2.DaemonSet:
|
|
||||||
namespace = t.Namespace
|
|
||||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
case *extensions.Deployment:
|
|
||||||
namespace = t.Namespace
|
|
||||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
|
||||||
}
|
|
||||||
case *extensionsv1beta1.Deployment:
|
|
||||||
namespace = t.Namespace
|
|
||||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
|
||||||
}
|
|
||||||
case *appsv1.Deployment:
|
|
||||||
namespace = t.Namespace
|
|
||||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
|
||||||
}
|
|
||||||
case *appsv1beta1.Deployment:
|
|
||||||
namespace = t.Namespace
|
|
||||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
|
||||||
}
|
|
||||||
case *appsv1beta2.Deployment:
|
|
||||||
namespace = t.Namespace
|
|
||||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
case *batch.Job:
|
|
||||||
namespace = t.Namespace
|
|
||||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
|
||||||
}
|
|
||||||
case *batchv1.Job:
|
|
||||||
namespace = t.Namespace
|
|
||||||
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
|
||||||
if err != nil {
|
|
||||||
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
case *api.Service:
|
|
||||||
namespace = t.Namespace
|
|
||||||
if t.Spec.Selector == nil || len(t.Spec.Selector) == 0 {
|
|
||||||
return "", nil, fmt.Errorf("invalid service '%s': Service is defined without a selector", t.Name)
|
|
||||||
}
|
|
||||||
selector = labels.SelectorFromSet(t.Spec.Selector)
|
|
||||||
case *corev1.Service:
|
|
||||||
namespace = t.Namespace
|
|
||||||
if t.Spec.Selector == nil || len(t.Spec.Selector) == 0 {
|
|
||||||
return "", nil, fmt.Errorf("invalid service '%s': Service is defined without a selector", t.Name)
|
|
||||||
}
|
|
||||||
selector = labels.SelectorFromSet(t.Spec.Selector)
|
|
||||||
|
|
||||||
default:
|
|
||||||
return "", nil, fmt.Errorf("selector for %T not implemented", object)
|
|
||||||
}
|
|
||||||
|
|
||||||
return namespace, selector, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *ring1Factory) HistoryViewer(mapping *meta.RESTMapping) (kubectl.HistoryViewer, error) {
|
func (f *ring1Factory) HistoryViewer(mapping *meta.RESTMapping) (kubectl.HistoryViewer, error) {
|
||||||
external, err := f.clientAccessFactory.KubernetesClientSet()
|
external, err := f.clientAccessFactory.KubernetesClientSet()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -394,12 +205,12 @@ func (f *ring1Factory) AttachablePodForObject(object runtime.Object, timeout tim
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace, selector, err := selectorsForObject(object)
|
namespace, selector, err := polymorphichelpers.SelectorsForObject(object)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("cannot attach to %T: %v", object, err)
|
return nil, fmt.Errorf("cannot attach to %T: %v", object, err)
|
||||||
}
|
}
|
||||||
sortBy := func(pods []*v1.Pod) sort.Interface { return sort.Reverse(controller.ActivePods(pods)) }
|
sortBy := func(pods []*v1.Pod) sort.Interface { return sort.Reverse(controller.ActivePods(pods)) }
|
||||||
pod, _, err := GetFirstPod(clientset.Core(), namespace, selector.String(), timeout, sortBy)
|
pod, _, err := polymorphichelpers.GetFirstPod(clientset.Core(), namespace, selector.String(), timeout, sortBy)
|
||||||
return pod, err
|
return pod, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,25 +17,14 @@ limitations under the License.
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"k8s.io/api/core/v1"
|
|
||||||
|
|
||||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apimachinery/pkg/watch"
|
|
||||||
testcore "k8s.io/client-go/testing"
|
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
|
|
||||||
"k8s.io/kubernetes/pkg/controller"
|
|
||||||
"k8s.io/kubernetes/pkg/kubectl"
|
"k8s.io/kubernetes/pkg/kubectl"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
)
|
)
|
||||||
|
@ -187,200 +176,6 @@ func TestCanBeExposed(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPodList(count, isUnready, isUnhealthy int, labels map[string]string) *api.PodList {
|
|
||||||
pods := []api.Pod{}
|
|
||||||
for i := 0; i < count; i++ {
|
|
||||||
newPod := api.Pod{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: fmt.Sprintf("pod-%d", i+1),
|
|
||||||
Namespace: metav1.NamespaceDefault,
|
|
||||||
CreationTimestamp: metav1.Date(2016, time.April, 1, 1, 0, i, 0, time.UTC),
|
|
||||||
Labels: labels,
|
|
||||||
},
|
|
||||||
Status: api.PodStatus{
|
|
||||||
Conditions: []api.PodCondition{
|
|
||||||
{
|
|
||||||
Status: api.ConditionTrue,
|
|
||||||
Type: api.PodReady,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
pods = append(pods, newPod)
|
|
||||||
}
|
|
||||||
if isUnready > -1 && isUnready < count {
|
|
||||||
pods[isUnready].Status.Conditions[0].Status = api.ConditionFalse
|
|
||||||
}
|
|
||||||
if isUnhealthy > -1 && isUnhealthy < count {
|
|
||||||
pods[isUnhealthy].Status.ContainerStatuses = []api.ContainerStatus{{RestartCount: 5}}
|
|
||||||
}
|
|
||||||
return &api.PodList{
|
|
||||||
Items: pods,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestGetFirstPod(t *testing.T) {
|
|
||||||
labelSet := map[string]string{"test": "selector"}
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
|
|
||||||
podList *api.PodList
|
|
||||||
watching []watch.Event
|
|
||||||
sortBy func([]*v1.Pod) sort.Interface
|
|
||||||
|
|
||||||
expected *api.Pod
|
|
||||||
expectedNum int
|
|
||||||
expectedErr bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "kubectl logs - two ready pods",
|
|
||||||
podList: newPodList(2, -1, -1, labelSet),
|
|
||||||
sortBy: func(pods []*v1.Pod) sort.Interface { return controller.ByLogging(pods) },
|
|
||||||
expected: &api.Pod{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: "pod-1",
|
|
||||||
Namespace: metav1.NamespaceDefault,
|
|
||||||
CreationTimestamp: metav1.Date(2016, time.April, 1, 1, 0, 0, 0, time.UTC),
|
|
||||||
Labels: map[string]string{"test": "selector"},
|
|
||||||
},
|
|
||||||
Status: api.PodStatus{
|
|
||||||
Conditions: []api.PodCondition{
|
|
||||||
{
|
|
||||||
Status: api.ConditionTrue,
|
|
||||||
Type: api.PodReady,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedNum: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "kubectl logs - one unhealthy, one healthy",
|
|
||||||
podList: newPodList(2, -1, 1, labelSet),
|
|
||||||
sortBy: func(pods []*v1.Pod) sort.Interface { return controller.ByLogging(pods) },
|
|
||||||
expected: &api.Pod{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: "pod-2",
|
|
||||||
Namespace: metav1.NamespaceDefault,
|
|
||||||
CreationTimestamp: metav1.Date(2016, time.April, 1, 1, 0, 1, 0, time.UTC),
|
|
||||||
Labels: map[string]string{"test": "selector"},
|
|
||||||
},
|
|
||||||
Status: api.PodStatus{
|
|
||||||
Conditions: []api.PodCondition{
|
|
||||||
{
|
|
||||||
Status: api.ConditionTrue,
|
|
||||||
Type: api.PodReady,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
ContainerStatuses: []api.ContainerStatus{{RestartCount: 5}},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedNum: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "kubectl attach - two ready pods",
|
|
||||||
podList: newPodList(2, -1, -1, labelSet),
|
|
||||||
sortBy: func(pods []*v1.Pod) sort.Interface { return sort.Reverse(controller.ActivePods(pods)) },
|
|
||||||
expected: &api.Pod{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: "pod-1",
|
|
||||||
Namespace: metav1.NamespaceDefault,
|
|
||||||
CreationTimestamp: metav1.Date(2016, time.April, 1, 1, 0, 0, 0, time.UTC),
|
|
||||||
Labels: map[string]string{"test": "selector"},
|
|
||||||
},
|
|
||||||
Status: api.PodStatus{
|
|
||||||
Conditions: []api.PodCondition{
|
|
||||||
{
|
|
||||||
Status: api.ConditionTrue,
|
|
||||||
Type: api.PodReady,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedNum: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "kubectl attach - wait for ready pod",
|
|
||||||
podList: newPodList(1, 1, -1, labelSet),
|
|
||||||
watching: []watch.Event{
|
|
||||||
{
|
|
||||||
Type: watch.Modified,
|
|
||||||
Object: &api.Pod{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: "pod-1",
|
|
||||||
Namespace: metav1.NamespaceDefault,
|
|
||||||
CreationTimestamp: metav1.Date(2016, time.April, 1, 1, 0, 0, 0, time.UTC),
|
|
||||||
Labels: map[string]string{"test": "selector"},
|
|
||||||
},
|
|
||||||
Status: api.PodStatus{
|
|
||||||
Conditions: []api.PodCondition{
|
|
||||||
{
|
|
||||||
Status: api.ConditionTrue,
|
|
||||||
Type: api.PodReady,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
sortBy: func(pods []*v1.Pod) sort.Interface { return sort.Reverse(controller.ActivePods(pods)) },
|
|
||||||
expected: &api.Pod{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: "pod-1",
|
|
||||||
Namespace: metav1.NamespaceDefault,
|
|
||||||
CreationTimestamp: metav1.Date(2016, time.April, 1, 1, 0, 0, 0, time.UTC),
|
|
||||||
Labels: map[string]string{"test": "selector"},
|
|
||||||
},
|
|
||||||
Status: api.PodStatus{
|
|
||||||
Conditions: []api.PodCondition{
|
|
||||||
{
|
|
||||||
Status: api.ConditionTrue,
|
|
||||||
Type: api.PodReady,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expectedNum: 1,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range tests {
|
|
||||||
test := tests[i]
|
|
||||||
fake := fake.NewSimpleClientset(test.podList)
|
|
||||||
if len(test.watching) > 0 {
|
|
||||||
watcher := watch.NewFake()
|
|
||||||
for _, event := range test.watching {
|
|
||||||
switch event.Type {
|
|
||||||
case watch.Added:
|
|
||||||
go watcher.Add(event.Object)
|
|
||||||
case watch.Modified:
|
|
||||||
go watcher.Modify(event.Object)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fake.PrependWatchReactor("pods", testcore.DefaultWatchReactor(watcher, nil))
|
|
||||||
}
|
|
||||||
selector := labels.Set(labelSet).AsSelector()
|
|
||||||
|
|
||||||
pod, numPods, err := GetFirstPod(fake.Core(), metav1.NamespaceDefault, selector.String(), 1*time.Minute, test.sortBy)
|
|
||||||
pod.Spec.SecurityContext = nil
|
|
||||||
if !test.expectedErr && err != nil {
|
|
||||||
t.Errorf("%s: unexpected error: %v", test.name, err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if test.expectedErr && err == nil {
|
|
||||||
t.Errorf("%s: expected an error", test.name)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if test.expectedNum != numPods {
|
|
||||||
t.Errorf("%s: expected %d pods, got %d", test.name, test.expectedNum, numPods)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !apiequality.Semantic.DeepEqual(test.expected, pod) {
|
|
||||||
t.Errorf("%s:\nexpected pod:\n%#v\ngot:\n%#v\n\n", test.name, test.expected, pod)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMakePortsString(t *testing.T) {
|
func TestMakePortsString(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
ports []api.ServicePort
|
ports []api.ServicePort
|
||||||
|
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"k8s.io/client-go/tools/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
"k8s.io/kubernetes/pkg/version"
|
"k8s.io/kubernetes/pkg/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -37,14 +38,14 @@ const (
|
||||||
|
|
||||||
// MatchVersionFlags is for setting the "match server version" function.
|
// MatchVersionFlags is for setting the "match server version" function.
|
||||||
type MatchVersionFlags struct {
|
type MatchVersionFlags struct {
|
||||||
Delegate RESTClientGetter
|
Delegate genericclioptions.RESTClientGetter
|
||||||
|
|
||||||
RequireMatchedServerVersion bool
|
RequireMatchedServerVersion bool
|
||||||
checkServerVersion sync.Once
|
checkServerVersion sync.Once
|
||||||
matchesServerVersionErr error
|
matchesServerVersionErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ RESTClientGetter = &MatchVersionFlags{}
|
var _ genericclioptions.RESTClientGetter = &MatchVersionFlags{}
|
||||||
|
|
||||||
func (f *MatchVersionFlags) checkMatchingServerVersion() error {
|
func (f *MatchVersionFlags) checkMatchingServerVersion() error {
|
||||||
f.checkServerVersion.Do(func() {
|
f.checkServerVersion.Do(func() {
|
||||||
|
@ -102,7 +103,7 @@ func (f *MatchVersionFlags) AddFlags(flags *pflag.FlagSet) {
|
||||||
flags.BoolVar(&f.RequireMatchedServerVersion, flagMatchBinaryVersion, f.RequireMatchedServerVersion, "Require server version to match client version")
|
flags.BoolVar(&f.RequireMatchedServerVersion, flagMatchBinaryVersion, f.RequireMatchedServerVersion, "Require server version to match client version")
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMatchVersionFlags(delegate RESTClientGetter) *MatchVersionFlags {
|
func NewMatchVersionFlags(delegate genericclioptions.RESTClientGetter) *MatchVersionFlags {
|
||||||
return &MatchVersionFlags{
|
return &MatchVersionFlags{
|
||||||
Delegate: delegate,
|
Delegate: delegate,
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,22 @@ const (
|
||||||
|
|
||||||
var defaultCacheDir = filepath.Join(homedir.HomeDir(), ".kube", "http-cache")
|
var defaultCacheDir = filepath.Join(homedir.HomeDir(), ".kube", "http-cache")
|
||||||
|
|
||||||
|
// RESTClientGetter is an interface that the ConfigFlags describe to provide an easier way to mock for commands
|
||||||
|
// and eliminate the direct coupling to a struct type. Users may wish to duplicate this type in their own packages
|
||||||
|
// as per the golang type overlapping.
|
||||||
|
type RESTClientGetter interface {
|
||||||
|
// ToRESTConfig returns restconfig
|
||||||
|
ToRESTConfig() (*rest.Config, error)
|
||||||
|
// ToDiscoveryClient returns discovery client
|
||||||
|
ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error)
|
||||||
|
// ToRESTMapper returns a restmapper
|
||||||
|
ToRESTMapper() (meta.RESTMapper, error)
|
||||||
|
// ToRawKubeConfigLoader return kubeconfig loader as-is
|
||||||
|
ToRawKubeConfigLoader() clientcmd.ClientConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ RESTClientGetter = &ConfigFlags{}
|
||||||
|
|
||||||
// ConfigFlags composes the set of values necessary
|
// ConfigFlags composes the set of values necessary
|
||||||
// for obtaining a REST client config
|
// for obtaining a REST client config
|
||||||
type ConfigFlags struct {
|
type ConfigFlags struct {
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = [
|
||||||
|
"helpers.go",
|
||||||
|
"interface.go",
|
||||||
|
"logsforobject.go",
|
||||||
|
],
|
||||||
|
importpath = "k8s.io/kubernetes/pkg/kubectl/polymorphichelpers",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = [
|
||||||
|
"//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/client/clientset_generated/internalclientset/typed/core/internalversion:go_default_library",
|
||||||
|
"//pkg/controller: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",
|
||||||
|
"//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/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/rest:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
go_test(
|
||||||
|
name = "go_default_test",
|
||||||
|
srcs = [
|
||||||
|
"helpers_test.go",
|
||||||
|
"logsforobject_test.go",
|
||||||
|
],
|
||||||
|
embed = [":go_default_library"],
|
||||||
|
deps = [
|
||||||
|
"//pkg/apis/apps:go_default_library",
|
||||||
|
"//pkg/apis/batch:go_default_library",
|
||||||
|
"//pkg/apis/core:go_default_library",
|
||||||
|
"//pkg/apis/extensions:go_default_library",
|
||||||
|
"//pkg/client/clientset_generated/internalclientset/fake:go_default_library",
|
||||||
|
"//pkg/controller:go_default_library",
|
||||||
|
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||||
|
"//vendor/k8s.io/apimachinery/pkg/api/equality: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/runtime/schema:go_default_library",
|
||||||
|
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||||
|
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||||
|
"//vendor/k8s.io/client-go/testing:go_default_library",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "package-srcs",
|
||||||
|
srcs = glob(["**"]),
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:private"],
|
||||||
|
)
|
||||||
|
|
||||||
|
filegroup(
|
||||||
|
name = "all-srcs",
|
||||||
|
srcs = [":package-srcs"],
|
||||||
|
tags = ["automanaged"],
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
|
@ -0,0 +1,235 @@
|
||||||
|
/*
|
||||||
|
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"
|
||||||
|
|
||||||
|
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"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/watch"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/apps"
|
||||||
|
"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"
|
||||||
|
coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetFirstPod returns a pod matching the namespace and label selector
|
||||||
|
// and the number of all pods that match the label selector.
|
||||||
|
func GetFirstPod(client coreclient.PodsGetter, namespace string, selector string, timeout time.Duration, sortBy func([]*v1.Pod) sort.Interface) (*api.Pod, int, error) {
|
||||||
|
options := metav1.ListOptions{LabelSelector: selector}
|
||||||
|
|
||||||
|
podList, err := client.Pods(namespace).List(options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
pods := []*v1.Pod{}
|
||||||
|
for i := range podList.Items {
|
||||||
|
pod := podList.Items[i]
|
||||||
|
externalPod := &v1.Pod{}
|
||||||
|
apiv1.Convert_core_Pod_To_v1_Pod(&pod, externalPod, nil)
|
||||||
|
pods = append(pods, externalPod)
|
||||||
|
}
|
||||||
|
if len(pods) > 0 {
|
||||||
|
sort.Sort(sortBy(pods))
|
||||||
|
internalPod := &api.Pod{}
|
||||||
|
apiv1.Convert_v1_Pod_To_core_Pod(pods[0], internalPod, nil)
|
||||||
|
return internalPod, len(podList.Items), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch until we observe a pod
|
||||||
|
options.ResourceVersion = podList.ResourceVersion
|
||||||
|
w, err := client.Pods(namespace).Watch(options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
defer w.Stop()
|
||||||
|
|
||||||
|
condition := func(event watch.Event) (bool, error) {
|
||||||
|
return event.Type == watch.Added || event.Type == watch.Modified, nil
|
||||||
|
}
|
||||||
|
event, err := watch.Until(timeout, w, condition)
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
pod, ok := event.Object.(*api.Pod)
|
||||||
|
if !ok {
|
||||||
|
return nil, 0, fmt.Errorf("%#v is not a pod event", event)
|
||||||
|
}
|
||||||
|
return pod, 1, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectorsForObject returns the pod label selector for a given object
|
||||||
|
func SelectorsForObject(object runtime.Object) (namespace string, selector labels.Selector, err error) {
|
||||||
|
switch t := object.(type) {
|
||||||
|
case *extensions.ReplicaSet:
|
||||||
|
namespace = t.Namespace
|
||||||
|
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
||||||
|
}
|
||||||
|
case *extensionsv1beta1.ReplicaSet:
|
||||||
|
namespace = t.Namespace
|
||||||
|
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
||||||
|
}
|
||||||
|
case *appsv1.ReplicaSet:
|
||||||
|
namespace = t.Namespace
|
||||||
|
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
||||||
|
}
|
||||||
|
case *appsv1beta2.ReplicaSet:
|
||||||
|
namespace = t.Namespace
|
||||||
|
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case *api.ReplicationController:
|
||||||
|
namespace = t.Namespace
|
||||||
|
selector = labels.SelectorFromSet(t.Spec.Selector)
|
||||||
|
case *corev1.ReplicationController:
|
||||||
|
namespace = t.Namespace
|
||||||
|
selector = labels.SelectorFromSet(t.Spec.Selector)
|
||||||
|
|
||||||
|
case *apps.StatefulSet:
|
||||||
|
namespace = t.Namespace
|
||||||
|
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
||||||
|
}
|
||||||
|
case *appsv1.StatefulSet:
|
||||||
|
namespace = t.Namespace
|
||||||
|
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
||||||
|
}
|
||||||
|
case *appsv1beta1.StatefulSet:
|
||||||
|
namespace = t.Namespace
|
||||||
|
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
||||||
|
}
|
||||||
|
case *appsv1beta2.StatefulSet:
|
||||||
|
namespace = t.Namespace
|
||||||
|
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case *extensions.DaemonSet:
|
||||||
|
namespace = t.Namespace
|
||||||
|
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
||||||
|
}
|
||||||
|
case *extensionsv1beta1.DaemonSet:
|
||||||
|
namespace = t.Namespace
|
||||||
|
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
||||||
|
}
|
||||||
|
case *appsv1.DaemonSet:
|
||||||
|
namespace = t.Namespace
|
||||||
|
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
||||||
|
}
|
||||||
|
case *appsv1beta2.DaemonSet:
|
||||||
|
namespace = t.Namespace
|
||||||
|
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case *extensions.Deployment:
|
||||||
|
namespace = t.Namespace
|
||||||
|
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
||||||
|
}
|
||||||
|
case *extensionsv1beta1.Deployment:
|
||||||
|
namespace = t.Namespace
|
||||||
|
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
||||||
|
}
|
||||||
|
case *appsv1.Deployment:
|
||||||
|
namespace = t.Namespace
|
||||||
|
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
||||||
|
}
|
||||||
|
case *appsv1beta1.Deployment:
|
||||||
|
namespace = t.Namespace
|
||||||
|
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
||||||
|
}
|
||||||
|
case *appsv1beta2.Deployment:
|
||||||
|
namespace = t.Namespace
|
||||||
|
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case *batch.Job:
|
||||||
|
namespace = t.Namespace
|
||||||
|
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
||||||
|
}
|
||||||
|
case *batchv1.Job:
|
||||||
|
namespace = t.Namespace
|
||||||
|
selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, fmt.Errorf("invalid label selector: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
case *api.Service:
|
||||||
|
namespace = t.Namespace
|
||||||
|
if t.Spec.Selector == nil || len(t.Spec.Selector) == 0 {
|
||||||
|
return "", nil, fmt.Errorf("invalid service '%s': Service is defined without a selector", t.Name)
|
||||||
|
}
|
||||||
|
selector = labels.SelectorFromSet(t.Spec.Selector)
|
||||||
|
case *corev1.Service:
|
||||||
|
namespace = t.Namespace
|
||||||
|
if t.Spec.Selector == nil || len(t.Spec.Selector) == 0 {
|
||||||
|
return "", nil, fmt.Errorf("invalid service '%s': Service is defined without a selector", t.Name)
|
||||||
|
}
|
||||||
|
selector = labels.SelectorFromSet(t.Spec.Selector)
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "", nil, fmt.Errorf("selector for %T not implemented", object)
|
||||||
|
}
|
||||||
|
|
||||||
|
return namespace, selector, nil
|
||||||
|
}
|
|
@ -0,0 +1,229 @@
|
||||||
|
/*
|
||||||
|
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"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
|
|
||||||
|
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
|
"k8s.io/apimachinery/pkg/watch"
|
||||||
|
testcore "k8s.io/client-go/testing"
|
||||||
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
|
||||||
|
"k8s.io/kubernetes/pkg/controller"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetFirstPod(t *testing.T) {
|
||||||
|
labelSet := map[string]string{"test": "selector"}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
|
||||||
|
podList *api.PodList
|
||||||
|
watching []watch.Event
|
||||||
|
sortBy func([]*v1.Pod) sort.Interface
|
||||||
|
|
||||||
|
expected *api.Pod
|
||||||
|
expectedNum int
|
||||||
|
expectedErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "kubectl logs - two ready pods",
|
||||||
|
podList: newPodList(2, -1, -1, labelSet),
|
||||||
|
sortBy: func(pods []*v1.Pod) sort.Interface { return controller.ByLogging(pods) },
|
||||||
|
expected: &api.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pod-1",
|
||||||
|
Namespace: metav1.NamespaceDefault,
|
||||||
|
CreationTimestamp: metav1.Date(2016, time.April, 1, 1, 0, 0, 0, time.UTC),
|
||||||
|
Labels: map[string]string{"test": "selector"},
|
||||||
|
},
|
||||||
|
Status: api.PodStatus{
|
||||||
|
Conditions: []api.PodCondition{
|
||||||
|
{
|
||||||
|
Status: api.ConditionTrue,
|
||||||
|
Type: api.PodReady,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedNum: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "kubectl logs - one unhealthy, one healthy",
|
||||||
|
podList: newPodList(2, -1, 1, labelSet),
|
||||||
|
sortBy: func(pods []*v1.Pod) sort.Interface { return controller.ByLogging(pods) },
|
||||||
|
expected: &api.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pod-2",
|
||||||
|
Namespace: metav1.NamespaceDefault,
|
||||||
|
CreationTimestamp: metav1.Date(2016, time.April, 1, 1, 0, 1, 0, time.UTC),
|
||||||
|
Labels: map[string]string{"test": "selector"},
|
||||||
|
},
|
||||||
|
Status: api.PodStatus{
|
||||||
|
Conditions: []api.PodCondition{
|
||||||
|
{
|
||||||
|
Status: api.ConditionTrue,
|
||||||
|
Type: api.PodReady,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ContainerStatuses: []api.ContainerStatus{{RestartCount: 5}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedNum: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "kubectl attach - two ready pods",
|
||||||
|
podList: newPodList(2, -1, -1, labelSet),
|
||||||
|
sortBy: func(pods []*v1.Pod) sort.Interface { return sort.Reverse(controller.ActivePods(pods)) },
|
||||||
|
expected: &api.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pod-1",
|
||||||
|
Namespace: metav1.NamespaceDefault,
|
||||||
|
CreationTimestamp: metav1.Date(2016, time.April, 1, 1, 0, 0, 0, time.UTC),
|
||||||
|
Labels: map[string]string{"test": "selector"},
|
||||||
|
},
|
||||||
|
Status: api.PodStatus{
|
||||||
|
Conditions: []api.PodCondition{
|
||||||
|
{
|
||||||
|
Status: api.ConditionTrue,
|
||||||
|
Type: api.PodReady,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedNum: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "kubectl attach - wait for ready pod",
|
||||||
|
podList: newPodList(1, 1, -1, labelSet),
|
||||||
|
watching: []watch.Event{
|
||||||
|
{
|
||||||
|
Type: watch.Modified,
|
||||||
|
Object: &api.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pod-1",
|
||||||
|
Namespace: metav1.NamespaceDefault,
|
||||||
|
CreationTimestamp: metav1.Date(2016, time.April, 1, 1, 0, 0, 0, time.UTC),
|
||||||
|
Labels: map[string]string{"test": "selector"},
|
||||||
|
},
|
||||||
|
Status: api.PodStatus{
|
||||||
|
Conditions: []api.PodCondition{
|
||||||
|
{
|
||||||
|
Status: api.ConditionTrue,
|
||||||
|
Type: api.PodReady,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
sortBy: func(pods []*v1.Pod) sort.Interface { return sort.Reverse(controller.ActivePods(pods)) },
|
||||||
|
expected: &api.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "pod-1",
|
||||||
|
Namespace: metav1.NamespaceDefault,
|
||||||
|
CreationTimestamp: metav1.Date(2016, time.April, 1, 1, 0, 0, 0, time.UTC),
|
||||||
|
Labels: map[string]string{"test": "selector"},
|
||||||
|
},
|
||||||
|
Status: api.PodStatus{
|
||||||
|
Conditions: []api.PodCondition{
|
||||||
|
{
|
||||||
|
Status: api.ConditionTrue,
|
||||||
|
Type: api.PodReady,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedNum: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range tests {
|
||||||
|
test := tests[i]
|
||||||
|
fake := fake.NewSimpleClientset(test.podList)
|
||||||
|
if len(test.watching) > 0 {
|
||||||
|
watcher := watch.NewFake()
|
||||||
|
for _, event := range test.watching {
|
||||||
|
switch event.Type {
|
||||||
|
case watch.Added:
|
||||||
|
go watcher.Add(event.Object)
|
||||||
|
case watch.Modified:
|
||||||
|
go watcher.Modify(event.Object)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fake.PrependWatchReactor("pods", testcore.DefaultWatchReactor(watcher, nil))
|
||||||
|
}
|
||||||
|
selector := labels.Set(labelSet).AsSelector()
|
||||||
|
|
||||||
|
pod, numPods, err := GetFirstPod(fake.Core(), metav1.NamespaceDefault, selector.String(), 1*time.Minute, test.sortBy)
|
||||||
|
pod.Spec.SecurityContext = nil
|
||||||
|
if !test.expectedErr && err != nil {
|
||||||
|
t.Errorf("%s: unexpected error: %v", test.name, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if test.expectedErr && err == nil {
|
||||||
|
t.Errorf("%s: expected an error", test.name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if test.expectedNum != numPods {
|
||||||
|
t.Errorf("%s: expected %d pods, got %d", test.name, test.expectedNum, numPods)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !apiequality.Semantic.DeepEqual(test.expected, pod) {
|
||||||
|
t.Errorf("%s:\nexpected pod:\n%#v\ngot:\n%#v\n\n", test.name, test.expected, pod)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPodList(count, isUnready, isUnhealthy int, labels map[string]string) *api.PodList {
|
||||||
|
pods := []api.Pod{}
|
||||||
|
for i := 0; i < count; i++ {
|
||||||
|
newPod := api.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: fmt.Sprintf("pod-%d", i+1),
|
||||||
|
Namespace: metav1.NamespaceDefault,
|
||||||
|
CreationTimestamp: metav1.Date(2016, time.April, 1, 1, 0, i, 0, time.UTC),
|
||||||
|
Labels: labels,
|
||||||
|
},
|
||||||
|
Status: api.PodStatus{
|
||||||
|
Conditions: []api.PodCondition{
|
||||||
|
{
|
||||||
|
Status: api.ConditionTrue,
|
||||||
|
Type: api.PodReady,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
pods = append(pods, newPod)
|
||||||
|
}
|
||||||
|
if isUnready > -1 && isUnready < count {
|
||||||
|
pods[isUnready].Status.Conditions[0].Status = api.ConditionFalse
|
||||||
|
}
|
||||||
|
if isUnhealthy > -1 && isUnhealthy < count {
|
||||||
|
pods[isUnhealthy].Status.ContainerStatuses = []api.ContainerStatus{{RestartCount: 5}}
|
||||||
|
}
|
||||||
|
return &api.PodList{
|
||||||
|
Items: pods,
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
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 (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/client-go/rest"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LogsForObjectFunc is a function type that can tell you how to get logs for a runtime.object
|
||||||
|
type LogsForObjectFunc func(restClientGetter genericclioptions.RESTClientGetter, object, options runtime.Object, timeout time.Duration) (*rest.Request, error)
|
||||||
|
|
||||||
|
// LogsForObjectFn gives a way to easily override the function for unit testing if needed.
|
||||||
|
var LogsForObjectFn LogsForObjectFunc = logsForObject
|
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
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"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/client-go/rest"
|
||||||
|
coreinternal "k8s.io/kubernetes/pkg/apis/core"
|
||||||
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
|
||||||
|
"k8s.io/kubernetes/pkg/controller"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||||
|
)
|
||||||
|
|
||||||
|
func logsForObject(restClientGetter genericclioptions.RESTClientGetter, object, options runtime.Object, timeout time.Duration) (*rest.Request, error) {
|
||||||
|
clientConfig, err := restClientGetter.ToRESTConfig()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
clientset, err := internalclientset.NewForConfig(clientConfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return logsForObjectWithClient(clientset, object, options, timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is split for easy test-ability
|
||||||
|
func logsForObjectWithClient(clientset internalclientset.Interface, object, options runtime.Object, timeout time.Duration) (*rest.Request, error) {
|
||||||
|
opts, ok := options.(*coreinternal.PodLogOptions)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("provided options object is not a PodLogOptions")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch t := object.(type) {
|
||||||
|
case *coreinternal.Pod:
|
||||||
|
return clientset.Core().Pods(t.Namespace).GetLogs(t.Name, opts), nil
|
||||||
|
case *corev1.Pod:
|
||||||
|
return clientset.Core().Pods(t.Namespace).GetLogs(t.Name, opts), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace, selector, err := SelectorsForObject(object)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("cannot get the logs from %T: %v", object, err)
|
||||||
|
}
|
||||||
|
sortBy := func(pods []*v1.Pod) sort.Interface { return controller.ByLogging(pods) }
|
||||||
|
pod, numPods, err := GetFirstPod(clientset.Core(), namespace, selector.String(), timeout, sortBy)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if numPods > 1 {
|
||||||
|
fmt.Fprintf(os.Stderr, "Found %v pods, using pod/%v\n", numPods, pod.Name)
|
||||||
|
}
|
||||||
|
return clientset.Core().Pods(pod.Namespace).GetLogs(pod.Name, opts), nil
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package util
|
package polymorphichelpers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -30,26 +30,9 @@ import (
|
||||||
"k8s.io/kubernetes/pkg/apis/batch"
|
"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/fake"
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake"
|
||||||
)
|
)
|
||||||
|
|
||||||
type fakeClientAccessFactory struct {
|
|
||||||
ClientAccessFactory
|
|
||||||
|
|
||||||
fakeClientset *fake.Clientset
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *fakeClientAccessFactory) ClientSet() (internalclientset.Interface, error) {
|
|
||||||
return f.fakeClientset, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func newFakeClientAccessFactory(objs []runtime.Object) *fakeClientAccessFactory {
|
|
||||||
return &fakeClientAccessFactory{
|
|
||||||
fakeClientset: fake.NewSimpleClientset(objs...),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
podsResource = schema.GroupVersionResource{Resource: "pods"}
|
podsResource = schema.GroupVersionResource{Resource: "pods"}
|
||||||
podsKind = schema.GroupVersionKind{Kind: "Pod"}
|
podsKind = schema.GroupVersionKind{Kind: "Pod"}
|
||||||
|
@ -146,20 +129,19 @@ func TestLogsForObject(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
caf := newFakeClientAccessFactory(test.pods)
|
fakeClientset := fake.NewSimpleClientset(test.pods...)
|
||||||
omf := NewObjectMappingFactory(caf)
|
_, err := logsForObjectWithClient(fakeClientset, test.obj, test.opts, 20*time.Second)
|
||||||
_, err := omf.LogsForObject(test.obj, test.opts, 20*time.Second)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%s: unexpected error: %v", test.name, err)
|
t.Errorf("%s: unexpected error: %v", test.name, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for i := range test.actions {
|
for i := range test.actions {
|
||||||
if len(caf.fakeClientset.Actions()) < i {
|
if len(fakeClientset.Actions()) < i {
|
||||||
t.Errorf("%s: action %d does not exists in actual actions: %#v",
|
t.Errorf("%s: action %d does not exists in actual actions: %#v",
|
||||||
test.name, i, caf.fakeClientset.Actions())
|
test.name, i, fakeClientset.Actions())
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
got := caf.fakeClientset.Actions()[i]
|
got := fakeClientset.Actions()[i]
|
||||||
want := test.actions[i]
|
want := test.actions[i]
|
||||||
if !reflect.DeepEqual(got, want) {
|
if !reflect.DeepEqual(got, want) {
|
||||||
t.Errorf("%s: unexpected action: %s", test.name, diff.ObjectDiff(got, want))
|
t.Errorf("%s: unexpected action: %s", test.name, diff.ObjectDiff(got, want))
|
|
@ -15,7 +15,7 @@ go_library(
|
||||||
importpath = "k8s.io/kubernetes/test/e2e/kubectl",
|
importpath = "k8s.io/kubernetes/test/e2e/kubectl",
|
||||||
deps = [
|
deps = [
|
||||||
"//pkg/controller:go_default_library",
|
"//pkg/controller:go_default_library",
|
||||||
"//pkg/kubectl/cmd/util:go_default_library",
|
"//pkg/kubectl/polymorphichelpers:go_default_library",
|
||||||
"//test/e2e/framework:go_default_library",
|
"//test/e2e/framework:go_default_library",
|
||||||
"//test/e2e/generated:go_default_library",
|
"//test/e2e/generated:go_default_library",
|
||||||
"//test/e2e/scheduling:go_default_library",
|
"//test/e2e/scheduling:go_default_library",
|
||||||
|
|
|
@ -58,7 +58,6 @@ import (
|
||||||
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/kubernetes/pkg/controller"
|
"k8s.io/kubernetes/pkg/controller"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
|
||||||
"k8s.io/kubernetes/test/e2e/framework"
|
"k8s.io/kubernetes/test/e2e/framework"
|
||||||
"k8s.io/kubernetes/test/e2e/generated"
|
"k8s.io/kubernetes/test/e2e/generated"
|
||||||
"k8s.io/kubernetes/test/e2e/scheduling"
|
"k8s.io/kubernetes/test/e2e/scheduling"
|
||||||
|
@ -67,6 +66,7 @@ import (
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo"
|
. "github.com/onsi/ginkgo"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
"k8s.io/kubernetes/pkg/kubectl/polymorphichelpers"
|
||||||
imageutils "k8s.io/kubernetes/test/utils/image"
|
imageutils "k8s.io/kubernetes/test/utils/image"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -529,7 +529,7 @@ var _ = SIGDescribe("Kubectl client", func() {
|
||||||
ExecOrDie()
|
ExecOrDie()
|
||||||
Expect(runOutput).ToNot(ContainSubstring("stdin closed"))
|
Expect(runOutput).ToNot(ContainSubstring("stdin closed"))
|
||||||
g := func(pods []*v1.Pod) sort.Interface { return sort.Reverse(controller.ActivePods(pods)) }
|
g := func(pods []*v1.Pod) sort.Interface { return sort.Reverse(controller.ActivePods(pods)) }
|
||||||
runTestPod, _, err := util.GetFirstPod(f.InternalClientset.Core(), ns, "run=run-test-3", 1*time.Minute, g)
|
runTestPod, _, err := polymorphichelpers.GetFirstPod(f.InternalClientset.Core(), ns, "run=run-test-3", 1*time.Minute, g)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue