Skip to content

Commit

Permalink
update debug cmd to use externals
Browse files Browse the repository at this point in the history
  • Loading branch information
juanvallejo committed Jul 25, 2018
1 parent d9d8278 commit e764e2a
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 105 deletions.
193 changes: 103 additions & 90 deletions pkg/oc/cli/debug/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"

Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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,
}
Expand Down Expand Up @@ -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)
}
Expand All @@ -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
}
Expand Down Expand Up @@ -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
Expand All @@ -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" {

Expand Down Expand Up @@ -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,
},
Expand All @@ -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
}
Expand All @@ -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 {
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand All @@ -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
Expand All @@ -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 = ""
Expand All @@ -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
}
Expand All @@ -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]
Expand All @@ -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)
Expand Down Expand Up @@ -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
}
Expand Down
Loading

0 comments on commit e764e2a

Please sign in to comment.