github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/pkg/varlinkapi/util.go (about)

     1  // +build varlink
     2  
     3  package varlinkapi
     4  
     5  import (
     6  	"context"
     7  	"strconv"
     8  	"strings"
     9  	"time"
    10  
    11  	"github.com/containers/buildah"
    12  	"github.com/containers/libpod/cmd/podman/shared"
    13  	"github.com/containers/libpod/libpod"
    14  	"github.com/containers/libpod/libpod/define"
    15  	"github.com/containers/libpod/pkg/channelwriter"
    16  	iopodman "github.com/containers/libpod/pkg/varlink"
    17  	"github.com/containers/storage/pkg/archive"
    18  )
    19  
    20  // getContext returns a non-nil, empty context
    21  func getContext() context.Context {
    22  	return context.TODO()
    23  }
    24  
    25  func makeListContainer(containerID string, batchInfo shared.BatchContainerStruct) iopodman.Container {
    26  	var (
    27  		mounts []iopodman.ContainerMount
    28  		ports  []iopodman.ContainerPortMappings
    29  	)
    30  	ns := shared.GetNamespaces(batchInfo.Pid)
    31  
    32  	for _, mount := range batchInfo.ConConfig.Spec.Mounts {
    33  		m := iopodman.ContainerMount{
    34  			Destination: mount.Destination,
    35  			Type:        mount.Type,
    36  			Source:      mount.Source,
    37  			Options:     mount.Options,
    38  		}
    39  		mounts = append(mounts, m)
    40  	}
    41  
    42  	for _, pm := range batchInfo.ConConfig.PortMappings {
    43  		p := iopodman.ContainerPortMappings{
    44  			Host_port:      strconv.Itoa(int(pm.HostPort)),
    45  			Host_ip:        pm.HostIP,
    46  			Protocol:       pm.Protocol,
    47  			Container_port: strconv.Itoa(int(pm.ContainerPort)),
    48  		}
    49  		ports = append(ports, p)
    50  
    51  	}
    52  
    53  	// If we find this needs to be done for other container endpoints, we should
    54  	// convert this to a separate function or a generic map from struct function.
    55  	namespace := iopodman.ContainerNameSpace{
    56  		User:   ns.User,
    57  		Uts:    ns.UTS,
    58  		Pidns:  ns.PIDNS,
    59  		Pid:    ns.PID,
    60  		Cgroup: ns.Cgroup,
    61  		Net:    ns.NET,
    62  		Mnt:    ns.MNT,
    63  		Ipc:    ns.IPC,
    64  	}
    65  
    66  	lc := iopodman.Container{
    67  		Id:               containerID,
    68  		Image:            batchInfo.ConConfig.RootfsImageName,
    69  		Imageid:          batchInfo.ConConfig.RootfsImageID,
    70  		Command:          batchInfo.ConConfig.Spec.Process.Args,
    71  		Createdat:        batchInfo.ConConfig.CreatedTime.Format(time.RFC3339),
    72  		Runningfor:       time.Since(batchInfo.ConConfig.CreatedTime).String(),
    73  		Status:           batchInfo.ConState.String(),
    74  		Ports:            ports,
    75  		Names:            batchInfo.ConConfig.Name,
    76  		Labels:           batchInfo.ConConfig.Labels,
    77  		Mounts:           mounts,
    78  		Containerrunning: batchInfo.ConState == define.ContainerStateRunning,
    79  		Namespaces:       namespace,
    80  	}
    81  	if batchInfo.Size != nil {
    82  		lc.Rootfssize = batchInfo.Size.RootFsSize
    83  		lc.Rwsize = batchInfo.Size.RwSize
    84  	}
    85  	return lc
    86  }
    87  
    88  func makeListPodContainers(containerID string, batchInfo shared.BatchContainerStruct) iopodman.ListPodContainerInfo {
    89  	lc := iopodman.ListPodContainerInfo{
    90  		Id:     containerID,
    91  		Status: batchInfo.ConState.String(),
    92  		Name:   batchInfo.ConConfig.Name,
    93  	}
    94  	return lc
    95  }
    96  
    97  func makeListPod(pod *libpod.Pod, batchInfo shared.PsOptions) (iopodman.ListPodData, error) {
    98  	var listPodsContainers []iopodman.ListPodContainerInfo
    99  	var errPodData = iopodman.ListPodData{}
   100  	status, err := shared.GetPodStatus(pod)
   101  	if err != nil {
   102  		return errPodData, err
   103  	}
   104  	containers, err := pod.AllContainers()
   105  	if err != nil {
   106  		return errPodData, err
   107  	}
   108  	for _, ctr := range containers {
   109  		batchInfo, err := shared.BatchContainerOp(ctr, batchInfo)
   110  		if err != nil {
   111  			return errPodData, err
   112  		}
   113  
   114  		listPodsContainers = append(listPodsContainers, makeListPodContainers(ctr.ID(), batchInfo))
   115  	}
   116  	listPod := iopodman.ListPodData{
   117  		Createdat:          pod.CreatedTime().Format(time.RFC3339),
   118  		Id:                 pod.ID(),
   119  		Name:               pod.Name(),
   120  		Status:             status,
   121  		Cgroup:             pod.CgroupParent(),
   122  		Numberofcontainers: strconv.Itoa(len(listPodsContainers)),
   123  		Containersinfo:     listPodsContainers,
   124  	}
   125  	return listPod, nil
   126  }
   127  
   128  func handlePodCall(call iopodman.VarlinkCall, pod *libpod.Pod, ctrErrs map[string]error, err error) error {
   129  	if err != nil && ctrErrs == nil {
   130  		return call.ReplyErrorOccurred(err.Error())
   131  	}
   132  	if ctrErrs != nil {
   133  		containerErrs := make([]iopodman.PodContainerErrorData, len(ctrErrs))
   134  		for ctr, reason := range ctrErrs {
   135  			ctrErr := iopodman.PodContainerErrorData{Containerid: ctr, Reason: reason.Error()}
   136  			containerErrs = append(containerErrs, ctrErr)
   137  		}
   138  		return call.ReplyPodContainerError(pod.ID(), containerErrs)
   139  	}
   140  
   141  	return nil
   142  }
   143  
   144  func stringCompressionToArchiveType(s string) archive.Compression {
   145  	switch strings.ToUpper(s) {
   146  	case "BZIP2":
   147  		return archive.Bzip2
   148  	case "GZIP":
   149  		return archive.Gzip
   150  	case "XZ":
   151  		return archive.Xz
   152  	}
   153  	return archive.Uncompressed
   154  }
   155  
   156  func stringPullPolicyToType(s string) buildah.PullPolicy {
   157  	switch strings.ToUpper(s) {
   158  	case "PULLIFMISSING":
   159  		return buildah.PullIfMissing
   160  	case "PULLALWAYS":
   161  		return buildah.PullAlways
   162  	case "PULLNEVER":
   163  		return buildah.PullNever
   164  	}
   165  	return buildah.PullIfMissing
   166  }
   167  
   168  func derefBool(inBool *bool) bool {
   169  	if inBool == nil {
   170  		return false
   171  	}
   172  	return *inBool
   173  }
   174  
   175  func derefString(in *string) string {
   176  	if in == nil {
   177  		return ""
   178  	}
   179  	return *in
   180  }
   181  
   182  func makePsOpts(inOpts iopodman.PsOpts) shared.PsOptions {
   183  	last := 0
   184  	if inOpts.Last != nil {
   185  		lastT := *inOpts.Last
   186  		last = int(lastT)
   187  	}
   188  	return shared.PsOptions{
   189  		All:       inOpts.All,
   190  		Last:      last,
   191  		Latest:    derefBool(inOpts.Latest),
   192  		NoTrunc:   derefBool(inOpts.NoTrunc),
   193  		Pod:       derefBool(inOpts.Pod),
   194  		Size:      derefBool(inOpts.Size),
   195  		Sort:      derefString(inOpts.Sort),
   196  		Namespace: true,
   197  		Sync:      derefBool(inOpts.Sync),
   198  	}
   199  }
   200  
   201  // forwardOutput is a helper method for varlink endpoints that employ both more and without
   202  // more.  it is capable of sending updates as the output writer gets them or append them
   203  // all to a log.  the chan error is the error from the libpod call so we can honor
   204  // and error event in that case.
   205  func forwardOutput(log []string, c chan error, wantsMore bool, output *channelwriter.Writer, reply func(br iopodman.MoreResponse) error) ([]string, error) {
   206  	done := false
   207  	for {
   208  		select {
   209  		// We need to check if the libpod func being called has returned an
   210  		// error yet
   211  		case err := <-c:
   212  			if err != nil {
   213  				return nil, err
   214  			}
   215  			done = true
   216  		// if no error is found, we pull what we can from the log writer and
   217  		// append it to log string slice
   218  		case line := <-output.ByteChannel:
   219  			log = append(log, string(line))
   220  			// If the end point is being used in more mode, send what we have
   221  			if wantsMore {
   222  				br := iopodman.MoreResponse{
   223  					Logs: log,
   224  				}
   225  				if err := reply(br); err != nil {
   226  					return nil, err
   227  				}
   228  				// "reset" the log to empty because we are sending what we
   229  				// get as we get it
   230  				log = []string{}
   231  			}
   232  		}
   233  		if done {
   234  			break
   235  		}
   236  	}
   237  	return log, nil
   238  }