diff options
-rw-r--r-- | cmd/podman/commands.go | 2 | ||||
-rw-r--r-- | cmd/podman/pod.go | 2 | ||||
-rw-r--r-- | cmd/podman/pod_create.go | 77 | ||||
-rw-r--r-- | cmd/podman/pod_ps.go | 46 | ||||
-rw-r--r-- | cmd/podman/shared/pod.go | 4 | ||||
-rw-r--r-- | cmd/podman/utils.go | 2 | ||||
-rw-r--r-- | pkg/adapter/containers_remote.go | 31 | ||||
-rw-r--r-- | pkg/adapter/pods.go | 76 | ||||
-rw-r--r-- | pkg/adapter/pods_remote.go | 159 | ||||
-rw-r--r-- | pkg/varlinkapi/pods.go | 4 |
10 files changed, 315 insertions, 88 deletions
diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go index 53aa62eb9..20eb0f490 100644 --- a/cmd/podman/commands.go +++ b/cmd/podman/commands.go @@ -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, diff --git a/cmd/podman/pod.go b/cmd/podman/pod.go index 4c7c416ce..b4c6ca688 100644 --- a/cmd/podman/pod.go +++ b/cmd/podman/pod.go @@ -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, diff --git a/cmd/podman/pod_create.go b/cmd/podman/pod_create.go index d5ca5e13a..f1bbecb84 100644 --- a/cmd/podman/pod_create.go +++ b/cmd/podman/pod_create.go @@ -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 } diff --git a/cmd/podman/pod_ps.go b/cmd/podman/pod_ps.go index 85467b6ad..70e077651 100644 --- a/cmd/podman/pod_ps.go +++ b/cmd/podman/pod_ps.go @@ -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 } diff --git a/cmd/podman/shared/pod.go b/cmd/podman/shared/pod.go index 30dd14845..5f65c40ac 100644 --- a/cmd/podman/shared/pod.go +++ b/cmd/podman/shared/pod.go @@ -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 diff --git a/cmd/podman/utils.go b/cmd/podman/utils.go index 0fbea417b..4ec0f8a13 100644 --- a/cmd/podman/utils.go +++ b/cmd/podman/utils.go @@ -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") } diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go index 9623304e5..3f43a6905 100644 --- a/pkg/adapter/containers_remote.go +++ b/pkg/adapter/containers_remote.go @@ -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 +} diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go index f2bcbd473..0cb602ecc 100644 --- a/pkg/adapter/pods.go +++ b/pkg/adapter/pods.go @@ -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) +} diff --git a/pkg/adapter/pods_remote.go b/pkg/adapter/pods_remote.go index 04484780a..767043a5f 100644 --- a/pkg/adapter/pods_remote.go +++ b/pkg/adapter/pods_remote.go @@ -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 +} diff --git a/pkg/varlinkapi/pods.go b/pkg/varlinkapi/pods.go index ceeed6681..4ca4c4270 100644 --- a/pkg/varlinkapi/pods.go +++ b/pkg/varlinkapi/pods.go @@ -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)) } |