Merge pull request #2422 from baude/remotepodcreate

podman-remote create|ps
This commit is contained in:
OpenShift Merge Robot
2019-02-25 21:57:42 +01:00
committed by GitHub
10 changed files with 315 additions and 88 deletions

View File

@ -92,9 +92,7 @@ func getContainerSubCommands() []*cobra.Command {
// Commands that the local client implements
func getPodSubCommands() []*cobra.Command {
return []*cobra.Command{
_podCreateCommand,
_podPauseCommand,
_podPsCommand,
_podRestartCommand,
_podStatsCommand,
_podTopCommand,

View File

@ -20,9 +20,11 @@ var podCommand = cliconfig.PodmanCommand{
//podSubCommands are implemented both in local and remote clients
var podSubCommands = []*cobra.Command{
_podCreateCommand,
_podExistsCommand,
_podInspectCommand,
_podKillCommand,
_podPsCommand,
_podRmCommand,
_podStartCommand,
_podStopCommand,

View File

@ -3,12 +3,10 @@ package main
import (
"fmt"
"os"
"strings"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/adapter"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@ -56,20 +54,29 @@ func init() {
}
func podCreateCmd(c *cliconfig.PodCreateValues) error {
var options []libpod.PodCreateOption
var err error
var (
err error
podIdFile *os.File
)
if len(c.InputArgs) > 0 {
return errors.New("podman pod create does not accept any arguments")
}
runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
defer runtime.Shutdown(false)
var podIdFile *os.File
if len(c.Publish) > 0 {
if !c.Infra {
return errors.Errorf("you must have an infra container to publish port bindings to the host")
}
}
if !c.Infra && c.Flag("share").Changed && c.Share != "none" && c.Share != "" {
return errors.Errorf("You cannot share kernel namespaces on the pod level without an infra container")
}
if c.Flag("pod-id-file").Changed && os.Geteuid() == 0 {
podIdFile, err = libpod.OpenExclusiveFile(c.PodIDFile)
if err != nil && os.IsExist(err) {
@ -82,67 +89,21 @@ func podCreateCmd(c *cliconfig.PodCreateValues) error {
defer podIdFile.Sync()
}
if len(c.Publish) > 0 {
if !c.Infra {
return errors.Errorf("you must have an infra container to publish port bindings to the host")
}
}
if !c.Infra && c.Flag("share").Changed && c.Share != "none" && c.Share != "" {
return errors.Errorf("You cannot share kernel namespaces on the pod level without an infra container")
}
if c.Flag("cgroup-parent").Changed {
options = append(options, libpod.WithPodCgroupParent(c.CgroupParent))
}
labels, err := getAllLabels(c.LabelFile, c.Labels)
if err != nil {
return errors.Wrapf(err, "unable to process labels")
}
if len(labels) != 0 {
options = append(options, libpod.WithPodLabels(labels))
}
if c.Flag("name").Changed {
options = append(options, libpod.WithPodName(c.Name))
}
if c.Infra {
options = append(options, libpod.WithInfraContainer())
nsOptions, err := shared.GetNamespaceOptions(strings.Split(c.Share, ","))
if err != nil {
return err
}
options = append(options, nsOptions...)
}
if len(c.Publish) > 0 {
portBindings, err := shared.CreatePortBindings(c.Publish)
if err != nil {
return err
}
options = append(options, libpod.WithInfraContainerPorts(portBindings))
}
// always have containers use pod cgroups
// User Opt out is not yet supported
options = append(options, libpod.WithPodCgroups())
ctx := getContext()
pod, err := runtime.NewPod(ctx, options...)
podID, err := runtime.CreatePod(getContext(), c, labels)
if err != nil {
return err
return errors.Wrapf(err, "unable to create pod")
}
if podIdFile != nil {
_, err = podIdFile.WriteString(pod.ID())
_, err = podIdFile.WriteString(podID)
if err != nil {
logrus.Error(err)
}
}
fmt.Printf("%s\n", pod.ID())
fmt.Printf("%s\n", podID)
return nil
}

View File

@ -10,9 +10,9 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/formats"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/adapter"
"github.com/containers/libpod/pkg/util"
"github.com/docker/go-units"
"github.com/pkg/errors"
@ -29,6 +29,8 @@ const (
NUM_CTR_INFO = 10
)
type PodFilter func(*adapter.Pod) bool
var (
bc_opts shared.PsOptions
)
@ -152,7 +154,7 @@ func podPsCmd(c *cliconfig.PodPsValues) error {
return errors.Wrapf(err, "error with flags passed")
}
runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
runtime, err := adapter.GetRuntime(&c.PodmanCommand)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
@ -173,7 +175,7 @@ func podPsCmd(c *cliconfig.PodPsValues) error {
opts.Format = genPodPsFormat(c)
var filterFuncs []libpod.PodFilter
var filterFuncs []PodFilter
if c.Filter != "" {
filters := strings.Split(c.Filter, ",")
for _, f := range filters {
@ -181,7 +183,7 @@ func podPsCmd(c *cliconfig.PodPsValues) error {
if len(filterSplit) < 2 {
return errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
}
generatedFunc, err := generatePodFilterFuncs(filterSplit[0], filterSplit[1], runtime)
generatedFunc, err := generatePodFilterFuncs(filterSplit[0], filterSplit[1])
if err != nil {
return errors.Wrapf(err, "invalid filter")
}
@ -189,7 +191,7 @@ func podPsCmd(c *cliconfig.PodPsValues) error {
}
}
var pods []*libpod.Pod
var pods []*adapter.Pod
if c.Latest {
pod, err := runtime.GetLatestPod()
if err != nil {
@ -203,7 +205,7 @@ func podPsCmd(c *cliconfig.PodPsValues) error {
}
}
podsFiltered := make([]*libpod.Pod, 0, len(pods))
podsFiltered := make([]*adapter.Pod, 0, len(pods))
for _, pod := range pods {
include := true
for _, filter := range filterFuncs {
@ -215,7 +217,7 @@ func podPsCmd(c *cliconfig.PodPsValues) error {
}
}
return generatePodPsOutput(podsFiltered, opts, runtime)
return generatePodPsOutput(podsFiltered, opts)
}
// podPsCheckFlagsPassed checks if mutually exclusive flags are passed together
@ -234,10 +236,10 @@ func podPsCheckFlagsPassed(c *cliconfig.PodPsValues) error {
return nil
}
func generatePodFilterFuncs(filter, filterValue string, runtime *libpod.Runtime) (func(pod *libpod.Pod) bool, error) {
func generatePodFilterFuncs(filter, filterValue string) (func(pod *adapter.Pod) bool, error) {
switch filter {
case "ctr-ids":
return func(p *libpod.Pod) bool {
return func(p *adapter.Pod) bool {
ctrIds, err := p.AllContainersByID()
if err != nil {
return false
@ -245,7 +247,7 @@ func generatePodFilterFuncs(filter, filterValue string, runtime *libpod.Runtime)
return util.StringInSlice(filterValue, ctrIds)
}, nil
case "ctr-names":
return func(p *libpod.Pod) bool {
return func(p *adapter.Pod) bool {
ctrs, err := p.AllContainers()
if err != nil {
return false
@ -258,7 +260,7 @@ func generatePodFilterFuncs(filter, filterValue string, runtime *libpod.Runtime)
return false
}, nil
case "ctr-number":
return func(p *libpod.Pod) bool {
return func(p *adapter.Pod) bool {
ctrIds, err := p.AllContainersByID()
if err != nil {
return false
@ -274,7 +276,7 @@ func generatePodFilterFuncs(filter, filterValue string, runtime *libpod.Runtime)
if !util.StringInSlice(filterValue, []string{"created", "restarting", "running", "paused", "exited", "unknown"}) {
return nil, errors.Errorf("%s is not a valid status", filterValue)
}
return func(p *libpod.Pod) bool {
return func(p *adapter.Pod) bool {
ctr_statuses, err := p.Status()
if err != nil {
return false
@ -291,19 +293,19 @@ func generatePodFilterFuncs(filter, filterValue string, runtime *libpod.Runtime)
return false
}, nil
case "id":
return func(p *libpod.Pod) bool {
return func(p *adapter.Pod) bool {
return strings.Contains(p.ID(), filterValue)
}, nil
case "name":
return func(p *libpod.Pod) bool {
return func(p *adapter.Pod) bool {
return strings.Contains(p.Name(), filterValue)
}, nil
case "status":
if !util.StringInSlice(filterValue, []string{"stopped", "running", "paused", "exited", "dead", "created"}) {
return nil, errors.Errorf("%s is not a valid pod status", filterValue)
}
return func(p *libpod.Pod) bool {
status, err := shared.GetPodStatus(p)
return func(p *adapter.Pod) bool {
status, err := p.GetPodStatus()
if err != nil {
return false
}
@ -448,7 +450,7 @@ func getPodTemplateOutput(psParams []podPsJSONParams, opts podPsOptions) ([]podP
return psOutput, nil
}
func getNamespaces(pod *libpod.Pod) []string {
func getNamespaces(pod *adapter.Pod) []string {
var shared []string
if pod.SharesPID() {
shared = append(shared, "pid")
@ -475,7 +477,7 @@ func getNamespaces(pod *libpod.Pod) []string {
}
// getAndSortPodJSONOutput returns the container info in its raw, sorted form
func getAndSortPodJSONParams(pods []*libpod.Pod, opts podPsOptions, runtime *libpod.Runtime) ([]podPsJSONParams, error) {
func getAndSortPodJSONParams(pods []*adapter.Pod, opts podPsOptions) ([]podPsJSONParams, error) {
var (
psOutput []podPsJSONParams
)
@ -487,7 +489,7 @@ func getAndSortPodJSONParams(pods []*libpod.Pod, opts podPsOptions, runtime *lib
return nil, err
}
ctrNum := len(ctrs)
status, err := shared.GetPodStatus(pod)
status, err := pod.GetPodStatus()
if err != nil {
return nil, err
}
@ -497,7 +499,7 @@ func getAndSortPodJSONParams(pods []*libpod.Pod, opts podPsOptions, runtime *lib
return nil, err
}
for _, ctr := range ctrs {
batchInfo, err := shared.BatchContainerOp(ctr, bc_opts)
batchInfo, err := adapter.BatchContainerOp(ctr, bc_opts)
if err != nil {
return nil, err
}
@ -539,11 +541,11 @@ func getAndSortPodJSONParams(pods []*libpod.Pod, opts podPsOptions, runtime *lib
return sortPodPsOutput(opts.Sort, psOutput)
}
func generatePodPsOutput(pods []*libpod.Pod, opts podPsOptions, runtime *libpod.Runtime) error {
func generatePodPsOutput(pods []*adapter.Pod, opts podPsOptions) error {
if len(pods) == 0 && opts.Format != formats.JSONString {
return nil
}
psOutput, err := getAndSortPodJSONParams(pods, opts, runtime)
psOutput, err := getAndSortPodJSONParams(pods, opts)
if err != nil {
return err
}

View File

@ -26,6 +26,10 @@ func GetPodStatus(pod *libpod.Pod) (string, error) {
if err != nil {
return errored, err
}
return CreatePodStatusResults(ctrStatuses)
}
func CreatePodStatusResults(ctrStatuses map[string]libpod.ContainerStatus) (string, error) {
ctrNum := len(ctrStatuses)
if ctrNum == 0 {
return created, nil

View File

@ -172,7 +172,7 @@ func getPodsFromContext(c *cliconfig.PodmanCommand, r *libpod.Runtime) ([]*libpo
var err error
if c.Bool("all") {
pods, err = r.Pods()
pods, err = r.GetAllPods()
if err != nil {
return nil, errors.Wrapf(err, "unable to get running pods")
}

View File

@ -4,6 +4,7 @@ package adapter
import (
"encoding/json"
"github.com/containers/libpod/cmd/podman/shared"
iopodman "github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
@ -48,3 +49,33 @@ func (c *Container) Config() *libpod.ContainerConfig {
}
return c.Runtime.Config(c.ID())
}
// Name returns the name of the container
func (c *Container) Name() string {
return c.config.Name
}
// BatchContainerOp is wrapper func to mimic shared's function with a similar name meant for libpod
func BatchContainerOp(ctr *Container, opts shared.PsOptions) (shared.BatchContainerStruct, error) {
// TODO If pod ps ever shows container's sizes, re-enable this code; otherwise it isn't needed
// and would be a perf hit
//data, err := ctr.Inspect(true)
//if err != nil {
// return shared.BatchContainerStruct{}, err
//}
//
//size := new(shared.ContainerSize)
//size.RootFsSize = data.SizeRootFs
//size.RwSize = data.SizeRw
bcs := shared.BatchContainerStruct{
ConConfig: ctr.config,
ConState: ctr.state.State,
ExitCode: ctr.state.ExitCode,
Pid: ctr.state.PID,
StartedTime: ctr.state.StartedTime,
ExitedTime: ctr.state.FinishedTime,
//Size: size,
}
return bcs, nil
}

View File

@ -4,10 +4,12 @@ package adapter
import (
"context"
"github.com/containers/libpod/pkg/adapter/shortcuts"
"strings"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/adapter/shortcuts"
)
// Pod ...
@ -45,6 +47,21 @@ func (r *LocalRuntime) GetLatestPod() (*Pod, error) {
return &pod, err
}
// GetAllPods gets all pods and wraps it in an adapter pod
func (r *LocalRuntime) GetAllPods() ([]*Pod, error) {
var pods []*Pod
allPods, err := r.Runtime.GetAllPods()
if err != nil {
return nil, err
}
for _, p := range allPods {
pod := Pod{}
pod.Pod = p
pods = append(pods, &pod)
}
return pods, nil
}
// LookupPod gets a pod by name or id and wraps it in an adapter pod
func (r *LocalRuntime) LookupPod(nameOrID string) (*Pod, error) {
pod := Pod{}
@ -150,3 +167,60 @@ func (r *LocalRuntime) StartPods(ctx context.Context, cli *cliconfig.PodStartVal
}
return podids, errs
}
// CreatePod is a wrapper for libpod and creating a new pod from the cli context
func (r *LocalRuntime) CreatePod(ctx context.Context, cli *cliconfig.PodCreateValues, labels map[string]string) (string, error) {
var (
options []libpod.PodCreateOption
err error
)
if cli.Flag("cgroup-parent").Changed {
options = append(options, libpod.WithPodCgroupParent(cli.CgroupParent))
}
if len(labels) != 0 {
options = append(options, libpod.WithPodLabels(labels))
}
if cli.Flag("name").Changed {
options = append(options, libpod.WithPodName(cli.Name))
}
if cli.Infra {
options = append(options, libpod.WithInfraContainer())
nsOptions, err := shared.GetNamespaceOptions(strings.Split(cli.Share, ","))
if err != nil {
return "", err
}
options = append(options, nsOptions...)
}
if len(cli.Publish) > 0 {
portBindings, err := shared.CreatePortBindings(cli.Publish)
if err != nil {
return "", err
}
options = append(options, libpod.WithInfraContainerPorts(portBindings))
}
// always have containers use pod cgroups
// User Opt out is not yet supported
options = append(options, libpod.WithPodCgroups())
pod, err := r.NewPod(ctx, options...)
if err != nil {
return "", err
}
return pod.ID(), nil
}
// GetPodStatus is a wrapper to get the status of a local libpod pod
func (p *Pod) GetPodStatus() (string, error) {
return shared.GetPodStatus(p.Pod)
}
// BatchContainerOp is a wrapper for the shared function of the same name
func BatchContainerOp(ctr *libpod.Container, opts shared.PsOptions) (shared.BatchContainerStruct, error) {
return shared.BatchContainerOp(ctr, opts)
}

View File

@ -5,8 +5,11 @@ package adapter
import (
"context"
"encoding/json"
"strings"
"time"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
"github.com/pkg/errors"
@ -168,3 +171,159 @@ func (r *LocalRuntime) StartPods(ctx context.Context, cli *cliconfig.PodStartVal
}
return startPods, startErrs
}
// CreatePod creates a pod for the remote client over a varlink connection
func (r *LocalRuntime) CreatePod(ctx context.Context, cli *cliconfig.PodCreateValues, labels map[string]string) (string, error) {
pc := iopodman.PodCreate{
Name: cli.Name,
CgroupParent: cli.CgroupParent,
Labels: labels,
Share: strings.Split(cli.Share, ","),
Infra: cli.Infra,
InfraCommand: cli.InfraCommand,
InfraImage: cli.InfraCommand,
Publish: cli.Publish,
}
return iopodman.CreatePod().Call(r.Conn, pc)
}
// GetAllPods is a helper function that gets all pods for the remote client
func (r *LocalRuntime) GetAllPods() ([]*Pod, error) {
var pods []*Pod
podIDs, err := iopodman.GetPodsByContext().Call(r.Conn, true, false, []string{})
if err != nil {
return nil, err
}
for _, p := range podIDs {
pod, err := r.LookupPod(p)
if err != nil {
return nil, err
}
pods = append(pods, pod)
}
return pods, nil
}
// ID returns the id of a remote pod
func (p *Pod) ID() string {
return p.config.ID
}
// Name returns the name of the remote pod
func (p *Pod) Name() string {
return p.config.Name
}
// AllContainersByID returns a slice of a pod's container IDs
func (p *Pod) AllContainersByID() ([]string, error) {
var containerIDs []string
for _, ctr := range p.containers {
containerIDs = append(containerIDs, ctr.ID)
}
return containerIDs, nil
}
// AllContainers returns a pods containers
func (p *Pod) AllContainers() ([]*Container, error) {
var containers []*Container
for _, ctr := range p.containers {
container, err := p.Runtime.LookupContainer(ctr.ID)
if err != nil {
return nil, err
}
containers = append(containers, container)
}
return containers, nil
}
// Status ...
func (p *Pod) Status() (map[string]libpod.ContainerStatus, error) {
ctrs := make(map[string]libpod.ContainerStatus)
for _, i := range p.containers {
var status libpod.ContainerStatus
switch i.State {
case "exited":
status = libpod.ContainerStateExited
case "stopped":
status = libpod.ContainerStateStopped
case "running":
status = libpod.ContainerStateRunning
case "paused":
status = libpod.ContainerStatePaused
case "created":
status = libpod.ContainerStateCreated
case "configured":
status = libpod.ContainerStateConfigured
default:
status = libpod.ContainerStateUnknown
}
ctrs[i.ID] = status
}
return ctrs, nil
}
// GetPodStatus is a wrapper to get the string version of the status
func (p *Pod) GetPodStatus() (string, error) {
ctrStatuses, err := p.Status()
if err != nil {
return "", err
}
return shared.CreatePodStatusResults(ctrStatuses)
}
// InfraContainerID returns the ID of the infra container in a pod
func (p *Pod) InfraContainerID() (string, error) {
return p.state.InfraContainerID, nil
}
// CreatedTime returns the time the container was created as a time.Time
func (p *Pod) CreatedTime() time.Time {
return p.config.CreatedTime
}
// SharesPID ....
func (p *Pod) SharesPID() bool {
return p.config.UsePodPID
}
// SharesIPC returns whether containers in pod
// default to use IPC namespace of first container in pod
func (p *Pod) SharesIPC() bool {
return p.config.UsePodIPC
}
// SharesNet returns whether containers in pod
// default to use network namespace of first container in pod
func (p *Pod) SharesNet() bool {
return p.config.UsePodNet
}
// SharesMount returns whether containers in pod
// default to use PID namespace of first container in pod
func (p *Pod) SharesMount() bool {
return p.config.UsePodMount
}
// SharesUser returns whether containers in pod
// default to use user namespace of first container in pod
func (p *Pod) SharesUser() bool {
return p.config.UsePodUser
}
// SharesUTS returns whether containers in pod
// default to use UTS namespace of first container in pod
func (p *Pod) SharesUTS() bool {
return p.config.UsePodUTS
}
// SharesCgroup returns whether containers in the pod will default to this pod's
// cgroup instead of the default libpod parent
func (p *Pod) SharesCgroup() bool {
return p.config.UsePodCgroup
}
// CgroupParent returns the pod's CGroup parent
func (p *Pod) CgroupParent() string {
return p.config.CgroupParent
}

View File

@ -14,10 +14,6 @@ import (
// CreatePod ...
func (i *LibpodAPI) CreatePod(call iopodman.VarlinkCall, create iopodman.PodCreate) error {
var options []libpod.PodCreateOption
if create.InfraCommand != "" || create.InfraImage != "" {
return call.ReplyErrorOccurred("the infra-command and infra-image options are not supported yet")
}
if create.CgroupParent != "" {
options = append(options, libpod.WithPodCgroupParent(create.CgroupParent))
}