github.com/alibaba/sealer@v0.8.6-0.20220430115802-37a2bdaa8173/pkg/debug/node.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  	"github.com/spf13/cobra"
    23  	corev1 "k8s.io/api/core/v1"
    24  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    25  	utilrand "k8s.io/apimachinery/pkg/util/rand"
    26  
    27  	"github.com/alibaba/sealer/common"
    28  )
    29  
    30  func NewDebugNodeCommand(options *DebuggerOptions) *cobra.Command {
    31  	cmd := &cobra.Command{
    32  		Use:   "node",
    33  		Short: "Debug node",
    34  		Args:  cobra.MinimumNArgs(1),
    35  		RunE: func(cmd *cobra.Command, args []string) error {
    36  			debugger := NewDebugger(options)
    37  			debugger.AdminKubeConfigPath = common.KubeAdminConf
    38  			debugger.Type = TypeDebugNode
    39  			debugger.Motd = SealerDebugMotd
    40  
    41  			imager := NewDebugImagesManager()
    42  
    43  			if err := debugger.CompleteAndVerifyOptions(cmd, args, imager); err != nil {
    44  				return err
    45  			}
    46  			str, err := debugger.Run()
    47  			if err != nil {
    48  				return err
    49  			}
    50  			if len(str) != 0 {
    51  				fmt.Println("The debug ID:", str)
    52  			}
    53  
    54  			return nil
    55  		},
    56  	}
    57  
    58  	return cmd
    59  }
    60  
    61  // DebugNode can debug a node.
    62  func (debugger *Debugger) DebugNode(ctx context.Context) (*corev1.Pod, error) {
    63  	// get the target node object
    64  	targetNode, err := debugger.kubeClientCorev1.Nodes().Get(ctx, debugger.TargetName, metav1.GetOptions{})
    65  	if err != nil {
    66  		return nil, errors.Wrapf(err, "failed to find the target node %s", debugger.TargetName)
    67  	}
    68  
    69  	if err := debugger.addClusterInfoIntoEnv(ctx); err != nil {
    70  		return nil, err
    71  	}
    72  
    73  	// add a pod into target node
    74  	debugPod, err := debugger.debugNodeByPod(ctx, targetNode)
    75  	if err != nil {
    76  		return nil, errors.Wrapf(err, "failed to add a pod into node: %s", targetNode.Name)
    77  	}
    78  
    79  	return debugPod, nil
    80  }
    81  
    82  // debugNodeByPod runs a pod in target node and use as a debug pod.
    83  func (debugger *Debugger) debugNodeByPod(ctx context.Context, node *corev1.Node) (*corev1.Pod, error) {
    84  	pods := debugger.kubeClientCorev1.Pods(debugger.Namespace)
    85  
    86  	debugPod, err := pods.Create(ctx, debugger.generateDebugPod(node.Name), metav1.CreateOptions{})
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  
    91  	return debugPod, nil
    92  }
    93  
    94  // generateDebugPod generates a debug pod that schedules on the specified node.
    95  // The generated pod will run in the host PID, Network & IPC namespace, and it will
    96  // have the node's filesystem mounted at /hostfs.
    97  func (debugger *Debugger) generateDebugPod(nodeName string) *corev1.Pod {
    98  	cn := PodDebugPrefix
    99  	if len(debugger.DebugContainerName) > 0 {
   100  		cn = debugger.DebugContainerName
   101  	} else {
   102  		debugger.DebugContainerName = cn
   103  	}
   104  
   105  	pn := fmt.Sprintf("%s-%s-%s", NodeDebugPrefix, nodeName, utilrand.String(7))
   106  
   107  	pod := &corev1.Pod{
   108  		ObjectMeta: metav1.ObjectMeta{
   109  			Name: pn,
   110  		},
   111  		Spec: corev1.PodSpec{
   112  			Containers: []corev1.Container{
   113  				{
   114  					Name:                     cn,
   115  					Env:                      debugger.Env,
   116  					Image:                    debugger.Image,
   117  					ImagePullPolicy:          corev1.PullPolicy(debugger.PullPolicy),
   118  					Stdin:                    true,
   119  					TTY:                      true,
   120  					TerminationMessagePolicy: corev1.TerminationMessageReadFile,
   121  					VolumeMounts: []corev1.VolumeMount{
   122  						{
   123  							MountPath: "/hostfs",
   124  							Name:      "host-root",
   125  						},
   126  					},
   127  				},
   128  			},
   129  			HostIPC:       true,
   130  			HostNetwork:   true,
   131  			HostPID:       true,
   132  			NodeName:      nodeName,
   133  			RestartPolicy: corev1.RestartPolicyNever,
   134  			Volumes: []corev1.Volume{
   135  				{
   136  					Name: "host-root",
   137  					VolumeSource: corev1.VolumeSource{
   138  						HostPath: &corev1.HostPathVolumeSource{Path: "/"},
   139  					},
   140  				},
   141  			},
   142  		},
   143  	}
   144  
   145  	return pod
   146  }