github.com/percona/percona-xtradb-cluster-operator@v1.14.0/clientcmd/clientcmd.go (about)

     1  package clientcmd
     2  
     3  import (
     4  	"bufio"
     5  	"context"
     6  	"io"
     7  
     8  	"github.com/pkg/errors"
     9  	corev1 "k8s.io/api/core/v1"
    10  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    11  	"k8s.io/client-go/kubernetes/scheme"
    12  	corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
    13  	restclient "k8s.io/client-go/rest"
    14  	"k8s.io/client-go/tools/clientcmd"
    15  	"k8s.io/client-go/tools/remotecommand"
    16  )
    17  
    18  type Client struct {
    19  	client     corev1client.CoreV1Interface
    20  	restconfig *restclient.Config
    21  }
    22  
    23  func NewClient() (*Client, error) {
    24  	// Instantiate loader for kubeconfig file.
    25  	kubeconfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(
    26  		clientcmd.NewDefaultClientConfigLoadingRules(),
    27  		&clientcmd.ConfigOverrides{
    28  			Timeout: "10s",
    29  		},
    30  	)
    31  
    32  	// Get a rest.Config from the kubeconfig file.  This will be passed into all
    33  	// the client objects we create.
    34  	restconfig, err := kubeconfig.ClientConfig()
    35  	if err != nil {
    36  		return nil, err
    37  	}
    38  
    39  	// Create a Kubernetes core/v1 client.
    40  	cl, err := corev1client.NewForConfig(restconfig)
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  
    45  	return &Client{
    46  		client:     cl,
    47  		restconfig: restconfig,
    48  	}, nil
    49  }
    50  
    51  func (c *Client) PodLogs(namespace, podName string, opts *corev1.PodLogOptions) ([]string, error) {
    52  	logs, err := c.client.Pods(namespace).GetLogs(podName, opts).Stream(context.TODO())
    53  	if err != nil {
    54  		return nil, errors.Wrap(err, "get pod logs stream")
    55  	}
    56  	defer logs.Close()
    57  
    58  	logArr := make([]string, 0)
    59  	sc := bufio.NewScanner(logs)
    60  	for sc.Scan() {
    61  		logArr = append(logArr, sc.Text())
    62  	}
    63  	return logArr, errors.Wrap(sc.Err(), "reading logs stream")
    64  }
    65  
    66  func (c *Client) IsPodRunning(namespace, podName string) (bool, error) {
    67  	pod, err := c.client.Pods(namespace).Get(context.TODO(), podName, metav1.GetOptions{})
    68  	if err != nil {
    69  		return false, err
    70  	}
    71  
    72  	if pod.Status.Phase != corev1.PodRunning {
    73  		return false, nil
    74  	}
    75  
    76  	for _, v := range pod.Status.Conditions {
    77  		if v.Type == corev1.ContainersReady && v.Status == corev1.ConditionTrue {
    78  			return true, nil
    79  		}
    80  	}
    81  	return false, nil
    82  }
    83  
    84  func (c *Client) Exec(pod *corev1.Pod, containerName string, command []string, stdin io.Reader, stdout, stderr io.Writer, tty bool) error {
    85  	// Prepare the API URL used to execute another process within the Pod.  In
    86  	// this case, we'll run a remote shell.
    87  	req := c.client.RESTClient().
    88  		Post().
    89  		Namespace(pod.Namespace).
    90  		Resource("pods").
    91  		Name(pod.Name).
    92  		SubResource("exec").
    93  		VersionedParams(&corev1.PodExecOptions{
    94  			Container: containerName,
    95  			Command:   command,
    96  			Stdin:     stdin != nil,
    97  			Stdout:    stdout != nil,
    98  			Stderr:    stderr != nil,
    99  			TTY:       tty,
   100  		}, scheme.ParameterCodec)
   101  
   102  	exec, err := remotecommand.NewSPDYExecutor(c.restconfig, "POST", req.URL())
   103  	if err != nil {
   104  		return err
   105  	}
   106  
   107  	// Connect this process' std{in,out,err} to the remote shell process.
   108  	return exec.Stream(remotecommand.StreamOptions{
   109  		Stdin:  stdin,
   110  		Stdout: stdout,
   111  		Stderr: stderr,
   112  		Tty:    tty,
   113  	})
   114  }
   115  
   116  func (c *Client) REST() restclient.Interface {
   117  	return c.client.RESTClient()
   118  }