...

Source file src/github.com/redhat-developer/odo/pkg/podman/podman.go

Documentation: github.com/redhat-developer/odo/pkg/podman

     1  package podman
     2  
     3  import (
     4  	"bufio"
     5  	"context"
     6  	"fmt"
     7  	"os/exec"
     8  	"strings"
     9  	"time"
    10  
    11  	envcontext "github.com/redhat-developer/odo/pkg/config/context"
    12  	"github.com/redhat-developer/odo/pkg/platform"
    13  
    14  	corev1 "k8s.io/api/core/v1"
    15  	jsonserializer "k8s.io/apimachinery/pkg/runtime/serializer/json"
    16  	"k8s.io/klog"
    17  	"k8s.io/kubectl/pkg/scheme"
    18  )
    19  
    20  type PodmanCli struct {
    21  	podmanCmd                   string
    22  	podmanCmdInitTimeout        time.Duration
    23  	containerRunGlobalExtraArgs []string
    24  	containerRunExtraArgs       []string
    25  }
    26  
    27  var _ Client = (*PodmanCli)(nil)
    28  var _ platform.Client = (*PodmanCli)(nil)
    29  
    30  // NewPodmanCli returns a new podman client, or nil if the podman command is not accessible in the system
    31  func NewPodmanCli(ctx context.Context) (*PodmanCli, error) {
    32  	// Check if podman is available in the system
    33  	cli := &PodmanCli{
    34  		podmanCmd:                   envcontext.GetEnvConfig(ctx).PodmanCmd,
    35  		podmanCmdInitTimeout:        envcontext.GetEnvConfig(ctx).PodmanCmdInitTimeout,
    36  		containerRunGlobalExtraArgs: envcontext.GetEnvConfig(ctx).OdoContainerBackendGlobalArgs,
    37  		containerRunExtraArgs:       envcontext.GetEnvConfig(ctx).OdoContainerRunArgs,
    38  	}
    39  	version, err := cli.Version(ctx)
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  	if version.Client == nil {
    44  		return nil, fmt.Errorf("executable %q not recognized as podman client", cli.podmanCmd)
    45  	}
    46  
    47  	return cli, nil
    48  }
    49  
    50  func (o *PodmanCli) PlayKube(pod *corev1.Pod) error {
    51  	serializer := jsonserializer.NewSerializerWithOptions(
    52  		jsonserializer.SimpleMetaFactory{},
    53  		scheme.Scheme,
    54  		scheme.Scheme,
    55  		jsonserializer.SerializerOptions{
    56  			Yaml: true,
    57  		},
    58  	)
    59  
    60  	// +3 because of "play kube -"
    61  	args := make([]string, 0, len(o.containerRunGlobalExtraArgs)+len(o.containerRunExtraArgs)+3)
    62  	args = append(args, o.containerRunGlobalExtraArgs...)
    63  	args = append(args, "play", "kube")
    64  	args = append(args, o.containerRunExtraArgs...)
    65  	args = append(args, "-")
    66  
    67  	cmd := exec.Command(o.podmanCmd, args...)
    68  	klog.V(3).Infof("executing %v", cmd.Args)
    69  	stdin, err := cmd.StdinPipe()
    70  	if err != nil {
    71  		return err
    72  	}
    73  
    74  	stdout, err := cmd.StdoutPipe()
    75  	if err != nil {
    76  		return err
    77  	}
    78  	cmd.Stderr = cmd.Stdout
    79  
    80  	if err = cmd.Start(); err != nil {
    81  		return err
    82  	}
    83  
    84  	if klog.V(4) {
    85  		var sb strings.Builder
    86  		_ = serializer.Encode(pod, &sb)
    87  		klog.Infof("Pod spec to play: \n---\n%s\n---\n", sb.String())
    88  	}
    89  
    90  	err = serializer.Encode(pod, stdin)
    91  	if err != nil {
    92  		return err
    93  	}
    94  	stdin.Close()
    95  	var podmanOut string
    96  	go func() {
    97  		for {
    98  			tmp := make([]byte, 1024)
    99  			_, err = stdout.Read(tmp)
   100  			podmanOut += string(tmp)
   101  			klog.V(4).Info(string(tmp))
   102  			if err != nil {
   103  				break
   104  			}
   105  		}
   106  	}()
   107  	if err = cmd.Wait(); err != nil {
   108  		if exiterr, ok := err.(*exec.ExitError); ok {
   109  			err = fmt.Errorf("%s: %s\nComplete Podman output:\n%s", err, string(exiterr.Stderr), podmanOut)
   110  		}
   111  		return err
   112  	}
   113  
   114  	return nil
   115  }
   116  
   117  func (o *PodmanCli) KubeGenerate(name string) (*corev1.Pod, error) {
   118  	serializer := jsonserializer.NewSerializerWithOptions(
   119  		jsonserializer.SimpleMetaFactory{},
   120  		scheme.Scheme,
   121  		scheme.Scheme,
   122  		jsonserializer.SerializerOptions{
   123  			Yaml: true,
   124  		},
   125  	)
   126  
   127  	cmd := exec.Command(o.podmanCmd, append(o.containerRunGlobalExtraArgs, "generate", "kube", name)...)
   128  	klog.V(3).Infof("executing %v", cmd.Args)
   129  	resultBytes, err := cmd.Output()
   130  	if err != nil {
   131  		if exiterr, ok := err.(*exec.ExitError); ok {
   132  			err = fmt.Errorf("%s: %s", err, string(exiterr.Stderr))
   133  		}
   134  		return nil, err
   135  	}
   136  	var pod corev1.Pod
   137  	_, _, err = serializer.Decode(resultBytes, nil, &pod)
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  	return &pod, nil
   142  }
   143  
   144  func (o *PodmanCli) PodStop(podname string) error {
   145  	cmd := exec.Command(o.podmanCmd, append(o.containerRunGlobalExtraArgs, "pod", "stop", podname)...)
   146  	klog.V(3).Infof("executing %v", cmd.Args)
   147  	out, err := cmd.Output()
   148  	if err != nil {
   149  		if exiterr, ok := err.(*exec.ExitError); ok {
   150  			err = fmt.Errorf("%s: %s", err, string(exiterr.Stderr))
   151  		}
   152  		return err
   153  	}
   154  	klog.V(4).Infof("Stopped pod %s", string(out))
   155  	return nil
   156  }
   157  
   158  func (o *PodmanCli) PodRm(podname string) error {
   159  	cmd := exec.Command(o.podmanCmd, append(o.containerRunGlobalExtraArgs, "pod", "rm", podname)...)
   160  	klog.V(3).Infof("executing %v", cmd.Args)
   161  	out, err := cmd.Output()
   162  	if err != nil {
   163  		if exiterr, ok := err.(*exec.ExitError); ok {
   164  			err = fmt.Errorf("%s: %s", err, string(exiterr.Stderr))
   165  		}
   166  		return err
   167  	}
   168  	klog.V(4).Infof("Deleted pod %s", string(out))
   169  	return nil
   170  }
   171  
   172  func (o *PodmanCli) PodLs() (map[string]bool, error) {
   173  	cmd := exec.Command(o.podmanCmd, append(o.containerRunGlobalExtraArgs, "pod", "list", "--format", "{{.Name}}", "--noheading")...)
   174  	klog.V(3).Infof("executing %v", cmd.Args)
   175  	out, err := cmd.Output()
   176  	if err != nil {
   177  		if exiterr, ok := err.(*exec.ExitError); ok {
   178  			err = fmt.Errorf("%s: %s", err, string(exiterr.Stderr))
   179  		}
   180  		return nil, err
   181  	}
   182  	return SplitLinesAsSet(string(out)), nil
   183  }
   184  
   185  func (o *PodmanCli) VolumeRm(volumeName string) error {
   186  	cmd := exec.Command(o.podmanCmd, append(o.containerRunGlobalExtraArgs, "volume", "rm", volumeName)...)
   187  	klog.V(3).Infof("executing %v", cmd.Args)
   188  	out, err := cmd.Output()
   189  	if err != nil {
   190  		if exiterr, ok := err.(*exec.ExitError); ok {
   191  			err = fmt.Errorf("%s: %s", err, string(exiterr.Stderr))
   192  		}
   193  		return err
   194  	}
   195  	klog.V(4).Infof("Deleted volume %s", string(out))
   196  	return nil
   197  }
   198  
   199  func (o *PodmanCli) VolumeLs() (map[string]bool, error) {
   200  	cmd := exec.Command(o.podmanCmd, append(o.containerRunGlobalExtraArgs, "volume", "ls", "--format", "{{.Name}}", "--noheading")...)
   201  	klog.V(3).Infof("executing %v", cmd.Args)
   202  	out, err := cmd.Output()
   203  	if err != nil {
   204  		if exiterr, ok := err.(*exec.ExitError); ok {
   205  			err = fmt.Errorf("%s: %s", err, string(exiterr.Stderr))
   206  		}
   207  		return nil, err
   208  	}
   209  	return SplitLinesAsSet(string(out)), nil
   210  }
   211  
   212  func (o *PodmanCli) CleanupPodResources(pod *corev1.Pod, cleanupVolumes bool) error {
   213  	err := o.PodStop(pod.GetName())
   214  	if err != nil {
   215  		return err
   216  	}
   217  	err = o.PodRm(pod.GetName())
   218  	if err != nil {
   219  		return err
   220  	}
   221  
   222  	if !cleanupVolumes {
   223  		return nil
   224  	}
   225  
   226  	for _, volume := range pod.Spec.Volumes {
   227  		if volume.PersistentVolumeClaim == nil {
   228  			continue
   229  		}
   230  		volumeName := volume.PersistentVolumeClaim.ClaimName
   231  		klog.V(3).Infof("deleting podman volume %q", volumeName)
   232  		err = o.VolumeRm(volumeName)
   233  		if err != nil {
   234  			return err
   235  		}
   236  	}
   237  	return nil
   238  }
   239  
   240  func SplitLinesAsSet(s string) map[string]bool {
   241  	lines := map[string]bool{}
   242  	sc := bufio.NewScanner(strings.NewReader(s))
   243  	for sc.Scan() {
   244  		lines[sc.Text()] = true
   245  	}
   246  	return lines
   247  }
   248  

View as plain text