From e764e2aee680a55bfc89a06cf175991b7605d803 Mon Sep 17 00:00:00 2001 From: juanvallejo Date: Mon, 23 Jul 2018 16:51:40 -0400 Subject: [PATCH] update debug cmd to use externals --- pkg/oc/cli/debug/debug.go | 193 ++++++++++-------- pkg/oc/cli/rsh/rsh.go | 69 ++++++- .../attachablepodforobject.go | 9 +- 3 files changed, 166 insertions(+), 105 deletions(-) diff --git a/pkg/oc/cli/debug/debug.go b/pkg/oc/cli/debug/debug.go index d3f98b60e6bd..d06f9c9916f7 100644 --- a/pkg/oc/cli/debug/debug.go +++ b/pkg/oc/cli/debug/debug.go @@ -26,7 +26,7 @@ import ( corev1client "k8s.io/client-go/kubernetes/typed/core/v1" "k8s.io/kubernetes/pkg/api/legacyscheme" kapi "k8s.io/kubernetes/pkg/apis/core" - coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" + kapiv1 "k8s.io/kubernetes/pkg/apis/core/v1" "k8s.io/kubernetes/pkg/kubectl" kcmd "k8s.io/kubernetes/pkg/kubectl/cmd" "k8s.io/kubernetes/pkg/kubectl/cmd/templates" @@ -38,63 +38,22 @@ import ( "k8s.io/kubernetes/pkg/kubectl/util/term" "k8s.io/kubernetes/pkg/util/interrupt" + appsapiv1 "github.com/openshift/api/apps/v1" appsv1 "github.com/openshift/api/apps/v1" + imageapiv1 "github.com/openshift/api/image/v1" imagev1 "github.com/openshift/api/image/v1" + appsclientv1 "github.com/openshift/client-go/apps/clientset/versioned/typed/apps/v1" + imageclientv1 "github.com/openshift/client-go/image/clientset/versioned/typed/image/v1" appsapi "github.com/openshift/origin/pkg/apps/apis/apps" - appsclientinternal "github.com/openshift/origin/pkg/apps/generated/internalclientset" - appsclient "github.com/openshift/origin/pkg/apps/generated/internalclientset/typed/apps/internalversion" appsutil "github.com/openshift/origin/pkg/apps/util" imageapi "github.com/openshift/origin/pkg/image/apis/image" - imageclientinternal "github.com/openshift/origin/pkg/image/generated/internalclientset" - imageclient "github.com/openshift/origin/pkg/image/generated/internalclientset/typed/image/internalversion" + internalimage "github.com/openshift/origin/pkg/image/apis/image" + oapiv1 "github.com/openshift/origin/pkg/image/apis/image/v1" generateapp "github.com/openshift/origin/pkg/oc/lib/newapp/app" utilenv "github.com/openshift/origin/pkg/oc/util/env" "github.com/openshift/origin/pkg/oc/util/ocscheme" ) -type DebugOptions struct { - PrintFlags *genericclioptions.PrintFlags - - Attach kcmd.AttachOptions - - CoreClient coreclient.CoreInterface - CoreV1Client corev1client.CoreV1Interface - AppsClient appsclient.AppsInterface - ImageClient imageclient.ImageInterface - - Printer printers.ResourcePrinter - LogsForObject polymorphichelpers.LogsForObjectFunc - - NoStdin bool - ForceTTY bool - DisableTTY bool - Timeout time.Duration - - Command []string - Annotations map[string]string - AsRoot bool - AsNonRoot bool - AsUser int64 - KeepLabels bool // TODO: evaluate selecting the right labels automatically - KeepAnnotations bool - KeepLiveness bool - KeepReadiness bool - KeepInitContainers bool - OneContainer bool - NodeName string - AddEnv []kapi.EnvVar - RemoveEnv []string - Resources []string - Builder func() *resource.Builder - Namespace string - ExplicitNamespace bool - DryRun bool - FullCmdName string - - resource.FilenameOptions - genericclioptions.IOStreams -} - const ( debugPodLabelName = "debug.openshift.io/name" @@ -139,6 +98,48 @@ var ( %[1]s dc/test -o yaml`) ) +type DebugOptions struct { + PrintFlags *genericclioptions.PrintFlags + + Attach kcmd.AttachOptions + + CoreClient corev1client.CoreV1Interface + AppsClient appsclientv1.AppsV1Interface + ImageClient imageclientv1.ImageV1Interface + + Printer printers.ResourcePrinter + LogsForObject polymorphichelpers.LogsForObjectFunc + + NoStdin bool + ForceTTY bool + DisableTTY bool + Timeout time.Duration + + Command []string + Annotations map[string]string + AsRoot bool + AsNonRoot bool + AsUser int64 + KeepLabels bool // TODO: evaluate selecting the right labels automatically + KeepAnnotations bool + KeepLiveness bool + KeepReadiness bool + KeepInitContainers bool + OneContainer bool + NodeName string + AddEnv []corev1.EnvVar + RemoveEnv []string + Resources []string + Builder func() *resource.Builder + Namespace string + ExplicitNamespace bool + DryRun bool + FullCmdName string + + resource.FilenameOptions + genericclioptions.IOStreams +} + func NewDebugOptions(streams genericclioptions.IOStreams) *DebugOptions { return &DebugOptions{ PrintFlags: genericclioptions.NewPrintFlags("").WithTypeSetter(ocscheme.PrintingInternalScheme), @@ -256,11 +257,24 @@ func (o *DebugOptions) Complete(cmd *cobra.Command, f kcmdutil.Factory, args []s o.Builder = f.NewBuilder - o.AddEnv, o.RemoveEnv, err = utilenv.ParseEnv(envArgs, nil) + // TODO: not sure what to do with this helper - new duplicate for external versions? + internalAddEnv, removeEnv, err := utilenv.ParseEnv(envArgs, nil) if err != nil { return err } + // convert EnvVars that we should add, from internal to external + for _, internal := range internalAddEnv { + external := corev1.EnvVar{} + if err := kapiv1.Convert_core_EnvVar_To_v1_EnvVar(&internal, &external, nil); err != nil { + return err + } + + o.AddEnv = append(o.AddEnv, external) + } + + o.RemoveEnv = removeEnv + cmdParent := cmd.Parent() if cmdParent != nil && len(cmdParent.CommandPath()) > 0 && kcmdutil.IsSiblingCommandExists(cmd, "describe") { o.FullCmdName = cmdParent.CommandPath() @@ -290,29 +304,20 @@ func (o *DebugOptions) Complete(cmd *cobra.Command, f kcmdutil.Factory, args []s } o.Attach.Config = config - kc, err := f.ClientSet() + o.CoreClient, err = corev1client.NewForConfig(config) if err != nil { return err } - o.Attach.PodClient = kc.Core() - o.CoreClient = kc.Core() - o.CoreV1Client, err = corev1client.NewForConfig(config) + o.AppsClient, err = appsclientv1.NewForConfig(config) if err != nil { return err } - appsClient, err := appsclientinternal.NewForConfig(config) + o.ImageClient, err = imageclientv1.NewForConfig(config) if err != nil { return err } - o.AppsClient = appsClient.Apps() - - imageClient, err := imageclientinternal.NewForConfig(config) - if err != nil { - return err - } - o.ImageClient = imageClient.Image() return nil } @@ -351,11 +356,11 @@ func (o *DebugOptions) RunDebug() error { if err != nil { glog.V(4).Infof("Unable to get exact template, but continuing with fallback: %v", err) } - template := &kapi.PodTemplateSpec{} + template := &corev1.PodTemplateSpec{} if err := legacyscheme.Scheme.Convert(templateV1, template, nil); err != nil { return err } - pod := &kapi.Pod{ + pod := &corev1.Pod{ ObjectMeta: template.ObjectMeta, Spec: template.Spec, } @@ -416,7 +421,7 @@ func (o *DebugOptions) RunDebug() error { stderr = os.Stderr } fmt.Fprintf(stderr, "\nRemoving debug pod ...\n") - if err := o.Attach.PodClient.Pods(pod.Namespace).Delete(pod.Name, metav1.NewDeleteOptions(0)); err != nil { + if err := o.CoreClient.Pods(pod.Namespace).Delete(pod.Name, metav1.NewDeleteOptions(0)); err != nil { if !kapierrors.IsNotFound(err) { fmt.Fprintf(stderr, "error: unable to delete the debug pod %q: %v\n", pod.Name, err) } @@ -426,7 +431,7 @@ func (o *DebugOptions) RunDebug() error { glog.V(5).Infof("Created attach arguments: %#v", o.Attach) return o.Attach.InterruptParent.Run(func() error { - w, err := o.Attach.PodClient.Pods(pod.Namespace).Watch(metav1.SingleObject(pod.ObjectMeta)) + w, err := o.CoreClient.Pods(pod.Namespace).Watch(metav1.SingleObject(pod.ObjectMeta)) if err != nil { return err } @@ -471,7 +476,7 @@ func (o *DebugOptions) RunDebug() error { // (via the "openshift.io/deployment-config.name" annotation), then tries to // find the ImageStream from which the DeploymentConfig is deploying, then tries // to find a match for the Container's image in the ImageStream's Images. -func (o *DebugOptions) getContainerImageViaDeploymentConfig(pod *kapi.Pod, container *kapi.Container) (*imageapi.Image, error) { +func (o *DebugOptions) getContainerImageViaDeploymentConfig(pod *corev1.Pod, container *corev1.Container) (*imageapiv1.Image, error) { ref, err := imageapi.ParseDockerImageReference(container.Image) if err != nil { return nil, err @@ -492,7 +497,7 @@ func (o *DebugOptions) getContainerImageViaDeploymentConfig(pod *kapi.Pod, conta } for _, trigger := range dc.Spec.Triggers { - if trigger.Type == appsapi.DeploymentTriggerOnImageChange && + if trigger.Type == appsapiv1.DeploymentTriggerOnImageChange && trigger.ImageChangeParams != nil && trigger.ImageChangeParams.From.Kind == "ImageStreamTag" { @@ -523,15 +528,15 @@ func (o *DebugOptions) getContainerImageViaDeploymentConfig(pod *kapi.Pod, conta // set to false. The request will not succeed if the backing repository // requires Insecure to be set to true, which cannot be hard-coded for security // reasons. -func (o *DebugOptions) getContainerImageViaImageStreamImport(container *kapi.Container) (*imageapi.Image, error) { - isi := &imageapi.ImageStreamImport{ +func (o *DebugOptions) getContainerImageViaImageStreamImport(container *corev1.Container) (*imageapiv1.Image, error) { + isi := &imageapiv1.ImageStreamImport{ ObjectMeta: metav1.ObjectMeta{ Name: "oc-debug", }, - Spec: imageapi.ImageStreamImportSpec{ - Images: []imageapi.ImageImportSpec{ + Spec: imageapiv1.ImageStreamImportSpec{ + Images: []imageapiv1.ImageImportSpec{ { - From: kapi.ObjectReference{ + From: corev1.ObjectReference{ Kind: "DockerImage", Name: container.Image, }, @@ -552,7 +557,7 @@ func (o *DebugOptions) getContainerImageViaImageStreamImport(container *kapi.Con return nil, nil } -func (o *DebugOptions) getContainerImageCommand(pod *kapi.Pod, container *kapi.Container) ([]string, error) { +func (o *DebugOptions) getContainerImageCommand(pod *corev1.Pod, container *corev1.Container) ([]string, error) { if len(container.Command) > 0 { return container.Command, nil } @@ -562,16 +567,24 @@ func (o *DebugOptions) getContainerImageCommand(pod *kapi.Pod, container *kapi.C image, _ = o.getContainerImageViaImageStreamImport(container) } - if image == nil || image.DockerImageMetadata.Config == nil { + // TODO: find a way to do this with the external api + // convert image to internal in order to extract its imagemetadata config + internalImage := &internalimage.Image{} + if err := oapiv1.Convert_v1_Image_To_image_Image(image, internalImage, nil); err != nil { + return nil, err + } + + // TODO: DockerImageMetadata is a RawExtension in the external api - how to access config? + if internalImage == nil || internalImage.DockerImageMetadata.Config == nil { return nil, errors.New("error: no usable image found") } - config := image.DockerImageMetadata.Config + config := internalImage.DockerImageMetadata.Config return append(config.Entrypoint, config.Cmd...), nil } // transformPodForDebug alters the input pod to be debuggable -func (o *DebugOptions) transformPodForDebug(annotations map[string]string) (*kapi.Pod, []string) { +func (o *DebugOptions) transformPodForDebug(annotations map[string]string) (*corev1.Pod, []string) { pod := o.Attach.Pod if !o.KeepInitContainers { @@ -600,7 +613,7 @@ func (o *DebugOptions) transformPodForDebug(annotations map[string]string) (*kap container.LivenessProbe = nil } - var newEnv []kapi.EnvVar + var newEnv []corev1.EnvVar if len(o.RemoveEnv) > 0 { for i := range container.Env { skip := false @@ -624,7 +637,7 @@ func (o *DebugOptions) transformPodForDebug(annotations map[string]string) (*kap container.Env = newEnv if container.SecurityContext == nil { - container.SecurityContext = &kapi.SecurityContext{} + container.SecurityContext = &corev1.SecurityContext{} } switch { case o.AsNonRoot: @@ -640,7 +653,7 @@ func (o *DebugOptions) transformPodForDebug(annotations map[string]string) (*kap } if o.OneContainer { - pod.Spec.Containers = []kapi.Container{*container} + pod.Spec.Containers = []corev1.Container{*container} } // reset the pod @@ -661,9 +674,9 @@ func (o *DebugOptions) transformPodForDebug(annotations map[string]string) (*kap pod.Spec.NodeName = o.NodeName pod.ResourceVersion = "" - pod.Spec.RestartPolicy = kapi.RestartPolicyNever + pod.Spec.RestartPolicy = corev1.RestartPolicyNever - pod.Status = kapi.PodStatus{} + pod.Status = corev1.PodStatus{} pod.UID = "" pod.CreationTimestamp = metav1.Time{} pod.SelfLink = "" @@ -676,17 +689,17 @@ func (o *DebugOptions) transformPodForDebug(annotations map[string]string) (*kap // createPod creates the debug pod, and will attempt to delete an existing debug // pod with the same name, but will return an error in any other case. -func (o *DebugOptions) createPod(pod *kapi.Pod) (*kapi.Pod, error) { +func (o *DebugOptions) createPod(pod *corev1.Pod) (*corev1.Pod, error) { namespace, name := pod.Namespace, pod.Name // create the pod - created, err := o.Attach.PodClient.Pods(namespace).Create(pod) + created, err := o.CoreClient.Pods(namespace).Create(pod) if err == nil || !kapierrors.IsAlreadyExists(err) { return created, err } // only continue if the pod has the right annotations - existing, err := o.Attach.PodClient.Pods(namespace).Get(name, metav1.GetOptions{}) + existing, err := o.CoreClient.Pods(namespace).Get(name, metav1.GetOptions{}) if err != nil { return nil, err } @@ -695,13 +708,13 @@ func (o *DebugOptions) createPod(pod *kapi.Pod) (*kapi.Pod, error) { } // delete the existing pod - if err := o.Attach.PodClient.Pods(namespace).Delete(name, metav1.NewDeleteOptions(0)); err != nil && !kapierrors.IsNotFound(err) { + if err := o.CoreClient.Pods(namespace).Delete(name, metav1.NewDeleteOptions(0)); err != nil && !kapierrors.IsNotFound(err) { return nil, fmt.Errorf("unable to delete existing debug pod %q: %v", name, err) } - return o.Attach.PodClient.Pods(namespace).Create(pod) + return o.CoreClient.Pods(namespace).Create(pod) } -func containerForName(pod *kapi.Pod, name string) *kapi.Container { +func containerForName(pod *corev1.Pod, name string) *corev1.Container { for i, c := range pod.Spec.Containers { if c.Name == name { return &pod.Spec.Containers[i] @@ -715,7 +728,7 @@ func containerForName(pod *kapi.Pod, name string) *kapi.Container { return nil } -func containerNames(pod *kapi.Pod) []string { +func containerNames(pod *corev1.Pod) []string { var names []string for _, c := range pod.Spec.Containers { names = append(names, c.Name) @@ -751,14 +764,14 @@ func (o *DebugOptions) approximatePodTemplateForObject(object runtime.Object) (* fallback := t.Spec.Template latestDeploymentName := appsutil.LatestDeploymentNameForConfigV1(t) - deployment, err := o.CoreV1Client.ReplicationControllers(t.Namespace).Get(latestDeploymentName, metav1.GetOptions{}) + deployment, err := o.CoreClient.ReplicationControllers(t.Namespace).Get(latestDeploymentName, metav1.GetOptions{}) if err != nil { return fallback, err } fallback = deployment.Spec.Template - pods, err := o.CoreV1Client.Pods(deployment.Namespace).List(metav1.ListOptions{LabelSelector: labels.SelectorFromSet(deployment.Spec.Selector).String()}) + pods, err := o.CoreClient.Pods(deployment.Namespace).List(metav1.ListOptions{LabelSelector: labels.SelectorFromSet(deployment.Spec.Selector).String()}) if err != nil { return fallback, err } diff --git a/pkg/oc/cli/rsh/rsh.go b/pkg/oc/cli/rsh/rsh.go index 339745cc0d20..13b4088fbea8 100644 --- a/pkg/oc/cli/rsh/rsh.go +++ b/pkg/oc/cli/rsh/rsh.go @@ -6,9 +6,11 @@ import ( "time" "github.com/spf13/cobra" + "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" + coreclientv1 "k8s.io/client-go/kubernetes/typed/core/v1" "k8s.io/kubernetes/pkg/apis/apps" "k8s.io/kubernetes/pkg/apis/batch" kapi "k8s.io/kubernetes/pkg/apis/core" @@ -210,16 +212,20 @@ func podForResource(f kcmdutil.Factory, resource string, timeout time.Duration) case kapi.Resource("pods"): return name, nil case kapi.Resource("replicationcontrollers"): - kc, err := f.ClientSet() + config, err := f.ToRESTConfig() + if err != nil { + return "", err + } + kc, err := coreclientv1.NewForConfig(config) if err != nil { return "", err } - rc, err := kc.Core().ReplicationControllers(namespace).Get(name, metav1.GetOptions{}) + rc, err := kc.ReplicationControllers(namespace).Get(name, metav1.GetOptions{}) if err != nil { return "", err } selector := labels.SelectorFromSet(rc.Spec.Selector) - pod, _, err := polymorphichelpers.GetFirstPod(kc.Core(), namespace, selector.String(), timeout, sortBy) + pod, _, err := polymorphichelpers.GetFirstPod(kc, namespace, selector.String(), timeout, sortBy) if err != nil { return "", err } @@ -247,7 +253,16 @@ func podForResource(f kcmdutil.Factory, resource string, timeout time.Duration) if err != nil { return "", err } - pod, _, err := polymorphichelpers.GetFirstPod(kc.Core(), namespace, selector.String(), timeout, sortBy) + config, err := f.ToRESTConfig() + if err != nil { + return "", err + } + coreclient, err := coreclientv1.NewForConfig(config) + if err != nil { + return "", err + } + + pod, _, err := polymorphichelpers.GetFirstPod(coreclient, namespace, selector.String(), timeout, sortBy) if err != nil { return "", err } @@ -265,7 +280,15 @@ func podForResource(f kcmdutil.Factory, resource string, timeout time.Duration) if err != nil { return "", err } - pod, _, err := polymorphichelpers.GetFirstPod(kc.Core(), namespace, selector.String(), timeout, sortBy) + config, err := f.ToRESTConfig() + if err != nil { + return "", err + } + coreclient, err := coreclientv1.NewForConfig(config) + if err != nil { + return "", err + } + pod, _, err := polymorphichelpers.GetFirstPod(coreclient, namespace, selector.String(), timeout, sortBy) if err != nil { return "", err } @@ -283,7 +306,15 @@ func podForResource(f kcmdutil.Factory, resource string, timeout time.Duration) if err != nil { return "", err } - pod, _, err := polymorphichelpers.GetFirstPod(kc.Core(), namespace, selector.String(), timeout, sortBy) + config, err := f.ToRESTConfig() + if err != nil { + return "", err + } + coreclient, err := coreclientv1.NewForConfig(config) + if err != nil { + return "", err + } + pod, _, err := polymorphichelpers.GetFirstPod(coreclient, namespace, selector.String(), timeout, sortBy) if err != nil { return "", err } @@ -301,7 +332,15 @@ func podForResource(f kcmdutil.Factory, resource string, timeout time.Duration) if err != nil { return "", err } - pod, _, err := polymorphichelpers.GetFirstPod(kc.Core(), namespace, selector.String(), timeout, sortBy) + config, err := f.ToRESTConfig() + if err != nil { + return "", err + } + coreclient, err := coreclientv1.NewForConfig(config) + if err != nil { + return "", err + } + pod, _, err := polymorphichelpers.GetFirstPod(coreclient, namespace, selector.String(), timeout, sortBy) if err != nil { return "", err } @@ -315,18 +354,28 @@ func podForResource(f kcmdutil.Factory, resource string, timeout time.Duration) if err != nil { return "", err } - return podNameForJob(job, kc, timeout, sortBy) + config, err := f.ToRESTConfig() + if err != nil { + return "", err + } + coreclient, err := coreclientv1.NewForConfig(config) + if err != nil { + return "", err + } + + return podNameForJob(job, coreclient, timeout, sortBy) default: return "", fmt.Errorf("remote shell for %s is not supported", resourceType) } } -func podNameForJob(job *batch.Job, kc kclientset.Interface, timeout time.Duration, sortBy func(pods []*v1.Pod) sort.Interface) (string, error) { +func podNameForJob(job *batch.Job, kc coreclientv1.CoreV1Interface, timeout time.Duration, sortBy func(pods []*v1.Pod) sort.Interface) (string, error) { selector, err := metav1.LabelSelectorAsSelector(job.Spec.Selector) if err != nil { return "", err } - pod, _, err := polymorphichelpers.GetFirstPod(kc.Core(), job.Namespace, selector.String(), timeout, sortBy) + + pod, _, err := polymorphichelpers.GetFirstPod(kc, job.Namespace, selector.String(), timeout, sortBy) if err != nil { return "", err } diff --git a/pkg/oc/originpolymorphichelpers/attachablepodforobject.go b/pkg/oc/originpolymorphichelpers/attachablepodforobject.go index 9dba29d3a5ea..525af779bb8d 100644 --- a/pkg/oc/originpolymorphichelpers/attachablepodforobject.go +++ b/pkg/oc/originpolymorphichelpers/attachablepodforobject.go @@ -7,8 +7,7 @@ import ( "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" - api "k8s.io/kubernetes/pkg/apis/core" - kinternalclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" + "k8s.io/client-go/kubernetes" "k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/kubectl/genericclioptions" "k8s.io/kubernetes/pkg/kubectl/polymorphichelpers" @@ -17,14 +16,14 @@ import ( ) func NewAttachablePodForObjectFn(delegate polymorphichelpers.AttachableLogsForObjectFunc) polymorphichelpers.AttachableLogsForObjectFunc { - return func(restClientGetter genericclioptions.RESTClientGetter, object runtime.Object, timeout time.Duration) (*api.Pod, error) { + return func(restClientGetter genericclioptions.RESTClientGetter, object runtime.Object, timeout time.Duration) (*v1.Pod, error) { switch t := object.(type) { case *appsapi.DeploymentConfig: config, err := restClientGetter.ToRESTConfig() if err != nil { return nil, err } - coreClient, err := kinternalclient.NewForConfig(config) + coreClient, err := kubernetes.NewForConfig(config) if err != nil { return nil, err } @@ -33,7 +32,7 @@ func NewAttachablePodForObjectFn(delegate polymorphichelpers.AttachableLogsForOb f := func(pods []*v1.Pod) sort.Interface { return sort.Reverse(controller.ActivePods(pods)) } - pod, _, err := polymorphichelpers.GetFirstPod(coreClient.Core(), t.Namespace, selector.String(), 1*time.Minute, f) + pod, _, err := polymorphichelpers.GetFirstPod(coreClient.CoreV1(), t.Namespace, selector.String(), 1*time.Minute, f) return pod, err default: