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

     1  // +build varlink
     2  
     3  package varlinkapi
     4  
     5  import (
     6  	"encoding/json"
     7  	"fmt"
     8  	"syscall"
     9  
    10  	"github.com/containers/libpod/cmd/podman/shared"
    11  	"github.com/containers/libpod/libpod"
    12  	"github.com/containers/libpod/pkg/adapter/shortcuts"
    13  	iopodman "github.com/containers/libpod/pkg/varlink"
    14  )
    15  
    16  // CreatePod ...
    17  func (i *VarlinkAPI) CreatePod(call iopodman.VarlinkCall, create iopodman.PodCreate) error {
    18  	var options []libpod.PodCreateOption
    19  	if create.Infra {
    20  		options = append(options, libpod.WithInfraContainer())
    21  		nsOptions, err := shared.GetNamespaceOptions(create.Share)
    22  		if err != nil {
    23  			return err
    24  		}
    25  		options = append(options, nsOptions...)
    26  	}
    27  	if create.CgroupParent != "" {
    28  		options = append(options, libpod.WithPodCgroupParent(create.CgroupParent))
    29  	}
    30  	if len(create.Labels) > 0 {
    31  		options = append(options, libpod.WithPodLabels(create.Labels))
    32  	}
    33  	if create.Name != "" {
    34  		options = append(options, libpod.WithPodName(create.Name))
    35  	}
    36  	if len(create.Share) > 0 && !create.Infra {
    37  		return call.ReplyErrorOccurred("You cannot share kernel namespaces on the pod level without an infra container")
    38  	}
    39  	if len(create.Share) == 0 && create.Infra {
    40  		return call.ReplyErrorOccurred("You must share kernel namespaces to run an infra container")
    41  	}
    42  
    43  	if len(create.Publish) > 0 {
    44  		if !create.Infra {
    45  			return call.ReplyErrorOccurred("you must have an infra container to publish port bindings to the host")
    46  		}
    47  		portBindings, err := shared.CreatePortBindings(create.Publish)
    48  		if err != nil {
    49  			return call.ReplyErrorOccurred(err.Error())
    50  		}
    51  		options = append(options, libpod.WithInfraContainerPorts(portBindings))
    52  
    53  	}
    54  	options = append(options, libpod.WithPodCgroups())
    55  
    56  	pod, err := i.Runtime.NewPod(getContext(), options...)
    57  	if err != nil {
    58  		return call.ReplyErrorOccurred(err.Error())
    59  	}
    60  	return call.ReplyCreatePod(pod.ID())
    61  }
    62  
    63  // ListPods ...
    64  func (i *VarlinkAPI) ListPods(call iopodman.VarlinkCall) error {
    65  	var (
    66  		listPods []iopodman.ListPodData
    67  	)
    68  
    69  	pods, err := i.Runtime.GetAllPods()
    70  	if err != nil {
    71  		return call.ReplyErrorOccurred(err.Error())
    72  	}
    73  	opts := shared.PsOptions{}
    74  	for _, pod := range pods {
    75  		listPod, err := makeListPod(pod, opts)
    76  		if err != nil {
    77  			return call.ReplyErrorOccurred(err.Error())
    78  		}
    79  		listPods = append(listPods, listPod)
    80  	}
    81  	return call.ReplyListPods(listPods)
    82  }
    83  
    84  // GetPod ...
    85  func (i *VarlinkAPI) GetPod(call iopodman.VarlinkCall, name string) error {
    86  	pod, err := i.Runtime.LookupPod(name)
    87  	if err != nil {
    88  		return call.ReplyPodNotFound(name, err.Error())
    89  	}
    90  	opts := shared.PsOptions{}
    91  
    92  	listPod, err := makeListPod(pod, opts)
    93  	if err != nil {
    94  		return call.ReplyErrorOccurred(err.Error())
    95  	}
    96  
    97  	return call.ReplyGetPod(listPod)
    98  }
    99  
   100  // GetPodsByStatus returns a slice of pods filtered by a libpod status
   101  func (i *VarlinkAPI) GetPodsByStatus(call iopodman.VarlinkCall, statuses []string) error {
   102  	filterFuncs := func(p *libpod.Pod) bool {
   103  		state, _ := shared.GetPodStatus(p)
   104  		for _, status := range statuses {
   105  			if state == status {
   106  				return true
   107  			}
   108  		}
   109  		return false
   110  	}
   111  	filteredPods, err := i.Runtime.Pods(filterFuncs)
   112  	if err != nil {
   113  		return call.ReplyErrorOccurred(err.Error())
   114  	}
   115  	podIDs := make([]string, 0, len(filteredPods))
   116  	for _, p := range filteredPods {
   117  		podIDs = append(podIDs, p.ID())
   118  	}
   119  	return call.ReplyGetPodsByStatus(podIDs)
   120  }
   121  
   122  // InspectPod ...
   123  func (i *VarlinkAPI) InspectPod(call iopodman.VarlinkCall, name string) error {
   124  	pod, err := i.Runtime.LookupPod(name)
   125  	if err != nil {
   126  		return call.ReplyPodNotFound(name, err.Error())
   127  	}
   128  	inspectData, err := pod.Inspect()
   129  	if err != nil {
   130  		return call.ReplyErrorOccurred(err.Error())
   131  	}
   132  	b, err := json.Marshal(&inspectData)
   133  	if err != nil {
   134  		return call.ReplyErrorOccurred("unable to serialize")
   135  	}
   136  	return call.ReplyInspectPod(string(b))
   137  }
   138  
   139  // StartPod ...
   140  func (i *VarlinkAPI) StartPod(call iopodman.VarlinkCall, name string) error {
   141  	pod, err := i.Runtime.LookupPod(name)
   142  	if err != nil {
   143  		return call.ReplyPodNotFound(name, err.Error())
   144  	}
   145  	ctnrs, err := pod.AllContainers()
   146  	if err != nil {
   147  		return call.ReplyErrorOccurred(err.Error())
   148  	}
   149  	if 0 == len(ctnrs) {
   150  		return call.ReplyNoContainersInPod(name)
   151  	}
   152  	ctrErrs, err := pod.Start(getContext())
   153  	callErr := handlePodCall(call, pod, ctrErrs, err)
   154  	if callErr != nil {
   155  		return err
   156  	}
   157  	return call.ReplyStartPod(pod.ID())
   158  }
   159  
   160  // StopPod ...
   161  func (i *VarlinkAPI) StopPod(call iopodman.VarlinkCall, name string, timeout int64) error {
   162  	pod, err := i.Runtime.LookupPod(name)
   163  	if err != nil {
   164  		return call.ReplyPodNotFound(name, err.Error())
   165  	}
   166  	ctrErrs, err := pod.StopWithTimeout(getContext(), true, int(timeout))
   167  	callErr := handlePodCall(call, pod, ctrErrs, err)
   168  	if callErr != nil {
   169  		return err
   170  	}
   171  	return call.ReplyStopPod(pod.ID())
   172  }
   173  
   174  // RestartPod ...
   175  func (i *VarlinkAPI) RestartPod(call iopodman.VarlinkCall, name string) error {
   176  	pod, err := i.Runtime.LookupPod(name)
   177  	if err != nil {
   178  		return call.ReplyPodNotFound(name, err.Error())
   179  	}
   180  	ctnrs, err := pod.AllContainers()
   181  	if err != nil {
   182  		return call.ReplyErrorOccurred(err.Error())
   183  	}
   184  	if 0 == len(ctnrs) {
   185  		return call.ReplyNoContainersInPod(name)
   186  	}
   187  	ctrErrs, err := pod.Restart(getContext())
   188  	callErr := handlePodCall(call, pod, ctrErrs, err)
   189  	if callErr != nil {
   190  		return err
   191  	}
   192  	return call.ReplyRestartPod(pod.ID())
   193  }
   194  
   195  // KillPod kills the running containers in a pod.  If you want to use the default SIGTERM signal,
   196  // just send a -1 for the signal arg.
   197  func (i *VarlinkAPI) KillPod(call iopodman.VarlinkCall, name string, signal int64) error {
   198  	killSignal := uint(syscall.SIGTERM)
   199  	if signal != -1 {
   200  		killSignal = uint(signal)
   201  	}
   202  
   203  	pod, err := i.Runtime.LookupPod(name)
   204  	if err != nil {
   205  		return call.ReplyPodNotFound(name, err.Error())
   206  	}
   207  	ctrErrs, err := pod.Kill(killSignal)
   208  	callErr := handlePodCall(call, pod, ctrErrs, err)
   209  	if callErr != nil {
   210  		return err
   211  	}
   212  	return call.ReplyKillPod(pod.ID())
   213  }
   214  
   215  // PausePod ...
   216  func (i *VarlinkAPI) PausePod(call iopodman.VarlinkCall, name string) error {
   217  	pod, err := i.Runtime.LookupPod(name)
   218  	if err != nil {
   219  		return call.ReplyPodNotFound(name, err.Error())
   220  	}
   221  	ctrErrs, err := pod.Pause()
   222  	callErr := handlePodCall(call, pod, ctrErrs, err)
   223  	if callErr != nil {
   224  		return err
   225  	}
   226  	return call.ReplyPausePod(pod.ID())
   227  }
   228  
   229  // UnpausePod ...
   230  func (i *VarlinkAPI) UnpausePod(call iopodman.VarlinkCall, name string) error {
   231  	pod, err := i.Runtime.LookupPod(name)
   232  	if err != nil {
   233  		return call.ReplyPodNotFound(name, err.Error())
   234  	}
   235  	ctrErrs, err := pod.Unpause()
   236  	callErr := handlePodCall(call, pod, ctrErrs, err)
   237  	if callErr != nil {
   238  		return err
   239  	}
   240  	return call.ReplyUnpausePod(pod.ID())
   241  }
   242  
   243  // RemovePod ...
   244  func (i *VarlinkAPI) RemovePod(call iopodman.VarlinkCall, name string, force bool) error {
   245  	ctx := getContext()
   246  	pod, err := i.Runtime.LookupPod(name)
   247  	if err != nil {
   248  		return call.ReplyPodNotFound(name, err.Error())
   249  	}
   250  	if err = i.Runtime.RemovePod(ctx, pod, true, force); err != nil {
   251  		return call.ReplyErrorOccurred(err.Error())
   252  	}
   253  
   254  	return call.ReplyRemovePod(pod.ID())
   255  }
   256  
   257  // GetPodStats ...
   258  func (i *VarlinkAPI) GetPodStats(call iopodman.VarlinkCall, name string) error {
   259  	pod, err := i.Runtime.LookupPod(name)
   260  	if err != nil {
   261  		return call.ReplyPodNotFound(name, err.Error())
   262  	}
   263  	prevStats := make(map[string]*libpod.ContainerStats)
   264  	podStats, err := pod.GetPodStats(prevStats)
   265  	if err != nil {
   266  		return call.ReplyErrorOccurred(err.Error())
   267  	}
   268  	if len(podStats) == 0 {
   269  		return call.ReplyNoContainerRunning()
   270  	}
   271  	containersStats := make([]iopodman.ContainerStats, 0)
   272  	for ctrID, containerStats := range podStats {
   273  		cs := iopodman.ContainerStats{
   274  			Id:           ctrID,
   275  			Name:         containerStats.Name,
   276  			Cpu:          containerStats.CPU,
   277  			Cpu_nano:     int64(containerStats.CPUNano),
   278  			System_nano:  int64(containerStats.SystemNano),
   279  			Mem_usage:    int64(containerStats.MemUsage),
   280  			Mem_limit:    int64(containerStats.MemLimit),
   281  			Mem_perc:     containerStats.MemPerc,
   282  			Net_input:    int64(containerStats.NetInput),
   283  			Net_output:   int64(containerStats.NetOutput),
   284  			Block_input:  int64(containerStats.BlockInput),
   285  			Block_output: int64(containerStats.BlockOutput),
   286  			Pids:         int64(containerStats.PIDs),
   287  		}
   288  		containersStats = append(containersStats, cs)
   289  	}
   290  	return call.ReplyGetPodStats(pod.ID(), containersStats)
   291  }
   292  
   293  // GetPodsByContext returns a slice of pod ids based on all, latest, or a list
   294  func (i *VarlinkAPI) GetPodsByContext(call iopodman.VarlinkCall, all, latest bool, input []string) error {
   295  	var podids []string
   296  
   297  	pods, err := shortcuts.GetPodsByContext(all, latest, input, i.Runtime)
   298  	if err != nil {
   299  		return call.ReplyErrorOccurred(err.Error())
   300  	}
   301  	for _, p := range pods {
   302  		podids = append(podids, p.ID())
   303  	}
   304  	return call.ReplyGetPodsByContext(podids)
   305  }
   306  
   307  // PodStateData returns a container's state data in string format
   308  func (i *VarlinkAPI) PodStateData(call iopodman.VarlinkCall, name string) error {
   309  	pod, err := i.Runtime.LookupPod(name)
   310  	if err != nil {
   311  		return call.ReplyErrorOccurred(err.Error())
   312  	}
   313  	data, err := pod.Inspect()
   314  	if err != nil {
   315  		return call.ReplyErrorOccurred("unable to obtain pod state")
   316  	}
   317  	b, err := json.Marshal(data)
   318  	if err != nil {
   319  		return call.ReplyErrorOccurred("unable to serialize pod inspect data")
   320  	}
   321  	return call.ReplyPodStateData(string(b))
   322  }
   323  
   324  // TopPod provides the top stats for a given or latest pod
   325  func (i *VarlinkAPI) TopPod(call iopodman.VarlinkCall, name string, latest bool, descriptors []string) error {
   326  	var (
   327  		pod *libpod.Pod
   328  		err error
   329  	)
   330  	if latest {
   331  		name = "latest"
   332  		pod, err = i.Runtime.GetLatestPod()
   333  	} else {
   334  		pod, err = i.Runtime.LookupPod(name)
   335  	}
   336  	if err != nil {
   337  		return call.ReplyPodNotFound(name, err.Error())
   338  	}
   339  
   340  	podStatus, err := shared.GetPodStatus(pod)
   341  	if err != nil {
   342  		return call.ReplyErrorOccurred(fmt.Sprintf("unable to get status for pod %s", pod.ID()))
   343  	}
   344  	if podStatus != "Running" {
   345  		return call.ReplyErrorOccurred("pod top can only be used on pods with at least one running container")
   346  	}
   347  	reply, err := pod.GetPodPidInformation(descriptors)
   348  	if err != nil {
   349  		return call.ReplyErrorOccurred(err.Error())
   350  	}
   351  	return call.ReplyTopPod(reply)
   352  }