github.com/sealerio/sealer@v0.11.1-0.20240507115618-f4f89c5853ae/pkg/debug/pod.go (about)

     1  // Copyright © 2021 Alibaba Group Holding Ltd.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package debug
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  
    21  	"github.com/pkg/errors"
    22  	corev1 "k8s.io/api/core/v1"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  	utilrand "k8s.io/apimachinery/pkg/util/rand"
    25  )
    26  
    27  func (debugger *Debugger) DebugPod(ctx context.Context) (*corev1.Pod, error) {
    28  	// get the target pod object
    29  	targetPod, err := debugger.kubeClientCorev1.Pods(debugger.Namespace).Get(ctx, debugger.TargetName, metav1.GetOptions{})
    30  	if err != nil {
    31  		return nil, errors.Wrapf(err, "failed to get the target pod %s", debugger.TargetName)
    32  	}
    33  
    34  	if err := debugger.addPodInfoIntoEnv(targetPod); err != nil {
    35  		return nil, err
    36  	}
    37  	if err := debugger.addClusterInfoIntoEnv(ctx); err != nil {
    38  		return nil, err
    39  	}
    40  
    41  	// add an ephemeral container into target pod and used as a debug container
    42  	debugPod, err := debugger.debugPodByEphemeralContainer(ctx, targetPod)
    43  	if err != nil {
    44  		return nil, errors.Wrapf(err, "failed to add an ephemeral container into pod: %s", targetPod.Name)
    45  	}
    46  
    47  	return debugPod, nil
    48  }
    49  
    50  // debugPodByEphemeralContainer runs an ephemeral container in target pod and use as a debug container.
    51  func (debugger *Debugger) debugPodByEphemeralContainer(ctx context.Context, pod *corev1.Pod) (*corev1.Pod, error) {
    52  	// get ephemeral containers
    53  	pods := debugger.kubeClientCorev1.Pods(pod.Namespace)
    54  
    55  	ephemeralContainers := pod.Spec.EphemeralContainers
    56  
    57  	// generate an ephemeral container
    58  	debugContainer := debugger.generateDebugContainer(pod)
    59  
    60  	// add the ephemeral container and update the pod
    61  	pod.Spec.EphemeralContainers = append(ephemeralContainers, *debugContainer)
    62  	if _, err := pods.UpdateEphemeralContainers(ctx, pod.Name, pod, metav1.UpdateOptions{}); err != nil {
    63  		return nil, errors.Wrapf(err, "error updating ephermeral containers")
    64  	}
    65  
    66  	return pod, nil
    67  }
    68  
    69  // generateDebugContainer returns an ephemeral container suitable for use as a debug container in the given pod.
    70  func (debugger *Debugger) generateDebugContainer(pod *corev1.Pod) *corev1.EphemeralContainer {
    71  	debugContainerName := debugger.getDebugContainerName(pod)
    72  	debugger.DebugContainerName = debugContainerName
    73  
    74  	if len(debugger.TargetContainer) == 0 {
    75  		debugger.TargetContainer = pod.Spec.Containers[0].Name
    76  	}
    77  
    78  	ec := &corev1.EphemeralContainer{
    79  		EphemeralContainerCommon: corev1.EphemeralContainerCommon{
    80  			Name:                     debugContainerName,
    81  			Env:                      debugger.Env,
    82  			Image:                    debugger.Image,
    83  			ImagePullPolicy:          corev1.PullPolicy(debugger.PullPolicy),
    84  			Stdin:                    true,
    85  			TerminationMessagePolicy: corev1.TerminationMessageReadFile,
    86  			TTY:                      true,
    87  		},
    88  		TargetContainerName: debugger.TargetContainer,
    89  	}
    90  
    91  	return ec
    92  }
    93  
    94  // getDebugContainerName generates and returns the debug container name.
    95  func (debugger *Debugger) getDebugContainerName(pod *corev1.Pod) string {
    96  	if len(debugger.DebugContainerName) > 0 {
    97  		return debugger.DebugContainerName
    98  	}
    99  
   100  	name := debugger.DebugContainerName
   101  	containerByName := ContainerNameToRef(pod)
   102  	for len(name) == 0 || containerByName[name] != nil {
   103  		name = fmt.Sprintf("%s-%s", PodDebugPrefix, utilrand.String(5))
   104  	}
   105  
   106  	return name
   107  }
   108  
   109  // addPodInfoIntoEnv adds pod info into env
   110  func (debugger *Debugger) addPodInfoIntoEnv(pod *corev1.Pod) error {
   111  	if pod == nil {
   112  		return fmt.Errorf("pod must not nil")
   113  	}
   114  
   115  	debugger.Env = append(debugger.Env,
   116  		corev1.EnvVar{
   117  			Name:  "POD_NAME",
   118  			Value: pod.Name,
   119  		},
   120  		corev1.EnvVar{
   121  			Name:  "POD_IP",
   122  			Value: pod.Status.PodIP,
   123  		},
   124  	)
   125  
   126  	return nil
   127  }