aboutsummaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/adapter/client.go47
-rw-r--r--pkg/adapter/containers_remote.go81
-rw-r--r--pkg/adapter/images_remote.go24
-rw-r--r--pkg/adapter/info_remote.go56
-rw-r--r--pkg/adapter/pods.go323
-rw-r--r--pkg/adapter/pods_remote.go401
-rw-r--r--pkg/adapter/runtime.go335
-rw-r--r--pkg/adapter/runtime_remote.go798
-rw-r--r--pkg/adapter/shortcuts/shortcuts.go27
-rw-r--r--pkg/adapter/volumes_remote.go33
-rw-r--r--pkg/registries/registries.go16
-rw-r--r--pkg/rootless/rootless_linux.c63
-rw-r--r--pkg/spec/createconfig.go72
-rw-r--r--pkg/spec/spec.go58
-rw-r--r--pkg/tracing/tracing.go28
-rw-r--r--pkg/util/utils.go10
-rw-r--r--pkg/varlinkapi/config.go9
-rw-r--r--pkg/varlinkapi/containers.go77
-rw-r--r--pkg/varlinkapi/containers_create.go7
-rw-r--r--pkg/varlinkapi/images.go635
-rw-r--r--pkg/varlinkapi/pods.go56
-rw-r--r--pkg/varlinkapi/system.go25
-rw-r--r--pkg/varlinkapi/transfers.go2
-rw-r--r--pkg/varlinkapi/util.go35
-rw-r--r--pkg/varlinkapi/volumes.go90
25 files changed, 3011 insertions, 297 deletions
diff --git a/pkg/adapter/client.go b/pkg/adapter/client.go
new file mode 100644
index 000000000..6512a5952
--- /dev/null
+++ b/pkg/adapter/client.go
@@ -0,0 +1,47 @@
+// +build remoteclient
+
+package adapter
+
+import (
+ "os"
+
+ "github.com/sirupsen/logrus"
+ "github.com/varlink/go/varlink"
+)
+
+// DefaultAddress is the default address of the varlink socket
+const DefaultAddress = "unix:/run/podman/io.podman"
+
+// Connect provides a varlink connection
+func (r RemoteRuntime) Connect() (*varlink.Connection, error) {
+ var err error
+ var connection *varlink.Connection
+ if bridge := os.Getenv("PODMAN_VARLINK_BRIDGE"); bridge != "" {
+ logrus.Infof("Connecting with varlink bridge")
+ logrus.Debugf("%s", bridge)
+ connection, err = varlink.NewBridge(bridge)
+ } else {
+ address := os.Getenv("PODMAN_VARLINK_ADDRESS")
+ if address == "" {
+ address = DefaultAddress
+ }
+ logrus.Infof("Connecting with varlink address")
+ logrus.Debugf("%s", address)
+ connection, err = varlink.NewConnection(address)
+ }
+ if err != nil {
+ return nil, err
+ }
+ return connection, nil
+}
+
+// RefreshConnection is used to replace the current r.Conn after things like
+// using an upgraded varlink connection
+func (r RemoteRuntime) RefreshConnection() error {
+ newConn, err := r.Connect()
+ if err != nil {
+ return err
+ }
+ r.Conn = newConn
+ return nil
+}
diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go
new file mode 100644
index 000000000..3f43a6905
--- /dev/null
+++ b/pkg/adapter/containers_remote.go
@@ -0,0 +1,81 @@
+// +build remoteclient
+
+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"
+ "github.com/containers/libpod/pkg/inspect"
+)
+
+// Inspect returns an inspect struct from varlink
+func (c *Container) Inspect(size bool) (*inspect.ContainerInspectData, error) {
+ reply, err := iopodman.ContainerInspectData().Call(c.Runtime.Conn, c.ID())
+ if err != nil {
+ return nil, err
+ }
+ data := inspect.ContainerInspectData{}
+ if err := json.Unmarshal([]byte(reply), &data); err != nil {
+ return nil, err
+ }
+ return &data, err
+}
+
+// ID returns the ID of the container
+func (c *Container) ID() string {
+ return c.config.ID
+}
+
+// GetArtifact returns a container's artifacts
+func (c *Container) GetArtifact(name string) ([]byte, error) {
+ var data []byte
+ reply, err := iopodman.ContainerArtifacts().Call(c.Runtime.Conn, c.ID(), name)
+ if err != nil {
+ return nil, err
+ }
+ if err := json.Unmarshal([]byte(reply), &data); err != nil {
+ return nil, err
+ }
+ return data, err
+}
+
+// Config returns a container's Config ... same as ctr.Config()
+func (c *Container) Config() *libpod.ContainerConfig {
+ if c.config != nil {
+ return c.config
+ }
+ 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/images_remote.go b/pkg/adapter/images_remote.go
new file mode 100644
index 000000000..e7b38dccc
--- /dev/null
+++ b/pkg/adapter/images_remote.go
@@ -0,0 +1,24 @@
+// +build remoteclient
+
+package adapter
+
+import (
+ "context"
+ "encoding/json"
+
+ iopodman "github.com/containers/libpod/cmd/podman/varlink"
+ "github.com/containers/libpod/pkg/inspect"
+)
+
+// Inspect returns returns an ImageData struct from over a varlink connection
+func (i *ContainerImage) Inspect(ctx context.Context) (*inspect.ImageData, error) {
+ reply, err := iopodman.InspectImage().Call(i.Runtime.Conn, i.ID())
+ if err != nil {
+ return nil, err
+ }
+ data := inspect.ImageData{}
+ if err := json.Unmarshal([]byte(reply), &data); err != nil {
+ return nil, err
+ }
+ return &data, nil
+}
diff --git a/pkg/adapter/info_remote.go b/pkg/adapter/info_remote.go
new file mode 100644
index 000000000..3b691ed17
--- /dev/null
+++ b/pkg/adapter/info_remote.go
@@ -0,0 +1,56 @@
+// +build remoteclient
+
+package adapter
+
+import (
+ "encoding/json"
+
+ "github.com/containers/libpod/cmd/podman/varlink"
+ "github.com/containers/libpod/libpod"
+)
+
+// Info returns information for the host system and its components
+func (r RemoteRuntime) Info() ([]libpod.InfoData, error) {
+ // TODO the varlink implementation for info should be updated to match the output for regular info
+ var (
+ reply []libpod.InfoData
+ hostInfo map[string]interface{}
+ store map[string]interface{}
+ )
+
+ registries := make(map[string]interface{})
+ insecureRegistries := make(map[string]interface{})
+ conn, err := r.Connect()
+ if err != nil {
+ return nil, err
+ }
+ defer conn.Close()
+ info, err := iopodman.GetInfo().Call(conn)
+ if err != nil {
+ return nil, err
+ }
+
+ // info.host -> map[string]interface{}
+ h, err := json.Marshal(info.Host)
+ if err != nil {
+ return nil, err
+ }
+ json.Unmarshal(h, &hostInfo)
+
+ // info.store -> map[string]interface{}
+ s, err := json.Marshal(info.Store)
+ if err != nil {
+ return nil, err
+ }
+ json.Unmarshal(s, &store)
+
+ registries["registries"] = info.Registries
+ insecureRegistries["registries"] = info.Insecure_registries
+
+ // Add everything to the reply
+ reply = append(reply, libpod.InfoData{Type: "host", Data: hostInfo})
+ reply = append(reply, libpod.InfoData{Type: "registries", Data: registries})
+ reply = append(reply, libpod.InfoData{Type: "insecure registries", Data: insecureRegistries})
+ reply = append(reply, libpod.InfoData{Type: "store", Data: store})
+ return reply, nil
+}
diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go
new file mode 100644
index 000000000..706a8fe96
--- /dev/null
+++ b/pkg/adapter/pods.go
@@ -0,0 +1,323 @@
+// +build !remoteclient
+
+package adapter
+
+import (
+ "context"
+ "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 ...
+type Pod struct {
+ *libpod.Pod
+}
+
+// RemovePods ...
+func (r *LocalRuntime) RemovePods(ctx context.Context, cli *cliconfig.PodRmValues) ([]string, []error) {
+ var (
+ errs []error
+ podids []string
+ )
+ pods, err := shortcuts.GetPodsByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime)
+ if err != nil {
+ errs = append(errs, err)
+ return nil, errs
+ }
+
+ for _, p := range pods {
+ if err := r.RemovePod(ctx, p, cli.Force, cli.Force); err != nil {
+ errs = append(errs, err)
+ } else {
+ podids = append(podids, p.ID())
+ }
+ }
+ return podids, errs
+}
+
+// GetLatestPod gets the latest pod and wraps it in an adapter pod
+func (r *LocalRuntime) GetLatestPod() (*Pod, error) {
+ pod := Pod{}
+ p, err := r.Runtime.GetLatestPod()
+ pod.Pod = p
+ 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{}
+ p, err := r.Runtime.LookupPod(nameOrID)
+ pod.Pod = p
+ return &pod, err
+}
+
+// StopPods is a wrapper to libpod to stop pods based on a cli context
+func (r *LocalRuntime) StopPods(ctx context.Context, cli *cliconfig.PodStopValues) ([]string, []error) {
+ timeout := -1
+ if cli.Flags().Changed("timeout") {
+ timeout = int(cli.Timeout)
+ }
+ var (
+ errs []error
+ podids []string
+ )
+ pods, err := shortcuts.GetPodsByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime)
+ if err != nil {
+ errs = append(errs, err)
+ return nil, errs
+ }
+
+ for _, p := range pods {
+ stopped := true
+ conErrs, stopErr := p.StopWithTimeout(ctx, true, int(timeout))
+ if stopErr != nil {
+ errs = append(errs, stopErr)
+ stopped = false
+ }
+ if conErrs != nil {
+ stopped = false
+ for _, err := range conErrs {
+ errs = append(errs, err)
+ }
+ }
+ if stopped {
+ podids = append(podids, p.ID())
+ }
+ }
+ return podids, errs
+}
+
+// KillPods is a wrapper to libpod to start pods based on the cli context
+func (r *LocalRuntime) KillPods(ctx context.Context, cli *cliconfig.PodKillValues, signal uint) ([]string, []error) {
+ var (
+ errs []error
+ podids []string
+ )
+ pods, err := shortcuts.GetPodsByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime)
+ if err != nil {
+ errs = append(errs, err)
+ return nil, errs
+ }
+ for _, p := range pods {
+ killed := true
+ conErrs, killErr := p.Kill(signal)
+ if killErr != nil {
+ errs = append(errs, killErr)
+ killed = false
+ }
+ if conErrs != nil {
+ killed = false
+ for _, err := range conErrs {
+ errs = append(errs, err)
+ }
+ }
+ if killed {
+ podids = append(podids, p.ID())
+ }
+ }
+ return podids, errs
+}
+
+// StartPods is a wrapper to start pods based on the cli context
+func (r *LocalRuntime) StartPods(ctx context.Context, cli *cliconfig.PodStartValues) ([]string, []error) {
+ var (
+ errs []error
+ podids []string
+ )
+ pods, err := shortcuts.GetPodsByContext(cli.All, cli.Latest, cli.InputArgs, r.Runtime)
+ if err != nil {
+ errs = append(errs, err)
+ return nil, errs
+ }
+ for _, p := range pods {
+ started := true
+ conErrs, startErr := p.Start(ctx)
+ if startErr != nil {
+ errs = append(errs, startErr)
+ started = false
+ }
+ if conErrs != nil {
+ started = false
+ for _, err := range conErrs {
+ errs = append(errs, err)
+ }
+ }
+ if started {
+ podids = append(podids, p.ID())
+ }
+ }
+ 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)
+}
+
+// PausePods is a wrapper for pausing pods via libpod
+func (r *LocalRuntime) PausePods(c *cliconfig.PodPauseValues) ([]string, map[string]error, []error) {
+ var (
+ pauseIDs []string
+ pauseErrors []error
+ )
+ containerErrors := make(map[string]error)
+
+ pods, err := shortcuts.GetPodsByContext(c.All, c.Latest, c.InputArgs, r.Runtime)
+ if err != nil {
+ pauseErrors = append(pauseErrors, err)
+ return nil, containerErrors, pauseErrors
+ }
+
+ for _, pod := range pods {
+ ctrErrs, err := pod.Pause()
+ if err != nil {
+ pauseErrors = append(pauseErrors, err)
+ continue
+ }
+ if ctrErrs != nil {
+ for ctr, err := range ctrErrs {
+ containerErrors[ctr] = err
+ }
+ continue
+ }
+ pauseIDs = append(pauseIDs, pod.ID())
+
+ }
+ return pauseIDs, containerErrors, pauseErrors
+}
+
+// UnpausePods is a wrapper for unpausing pods via libpod
+func (r *LocalRuntime) UnpausePods(c *cliconfig.PodUnpauseValues) ([]string, map[string]error, []error) {
+ var (
+ unpauseIDs []string
+ unpauseErrors []error
+ )
+ containerErrors := make(map[string]error)
+
+ pods, err := shortcuts.GetPodsByContext(c.All, c.Latest, c.InputArgs, r.Runtime)
+ if err != nil {
+ unpauseErrors = append(unpauseErrors, err)
+ return nil, containerErrors, unpauseErrors
+ }
+
+ for _, pod := range pods {
+ ctrErrs, err := pod.Unpause()
+ if err != nil {
+ unpauseErrors = append(unpauseErrors, err)
+ continue
+ }
+ if ctrErrs != nil {
+ for ctr, err := range ctrErrs {
+ containerErrors[ctr] = err
+ }
+ continue
+ }
+ unpauseIDs = append(unpauseIDs, pod.ID())
+
+ }
+ return unpauseIDs, containerErrors, unpauseErrors
+}
+
+// RestartPods is a wrapper to restart pods via libpod
+func (r *LocalRuntime) RestartPods(ctx context.Context, c *cliconfig.PodRestartValues) ([]string, map[string]error, []error) {
+ var (
+ restartIDs []string
+ restartErrors []error
+ )
+ containerErrors := make(map[string]error)
+
+ pods, err := shortcuts.GetPodsByContext(c.All, c.Latest, c.InputArgs, r.Runtime)
+ if err != nil {
+ restartErrors = append(restartErrors, err)
+ return nil, containerErrors, restartErrors
+ }
+
+ for _, pod := range pods {
+ ctrErrs, err := pod.Restart(ctx)
+ if err != nil {
+ restartErrors = append(restartErrors, err)
+ continue
+ }
+ if ctrErrs != nil {
+ for ctr, err := range ctrErrs {
+ containerErrors[ctr] = err
+ }
+ continue
+ }
+ restartIDs = append(restartIDs, pod.ID())
+
+ }
+ return restartIDs, containerErrors, restartErrors
+
+}
diff --git a/pkg/adapter/pods_remote.go b/pkg/adapter/pods_remote.go
new file mode 100644
index 000000000..220f7163f
--- /dev/null
+++ b/pkg/adapter/pods_remote.go
@@ -0,0 +1,401 @@
+// +build remoteclient
+
+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"
+ "github.com/ulule/deepcopier"
+)
+
+// Pod ...
+type Pod struct {
+ remotepod
+}
+
+type remotepod struct {
+ config *libpod.PodConfig
+ state *libpod.PodInspectState
+ containers []libpod.PodContainerInfo
+ Runtime *LocalRuntime
+}
+
+// RemovePods removes one or more based on the cli context.
+func (r *LocalRuntime) RemovePods(ctx context.Context, cli *cliconfig.PodRmValues) ([]string, []error) {
+ var (
+ rmErrs []error
+ rmPods []string
+ )
+ podIDs, err := iopodman.GetPodsByContext().Call(r.Conn, cli.All, cli.Latest, cli.InputArgs)
+ if err != nil {
+ rmErrs = append(rmErrs, err)
+ return nil, rmErrs
+ }
+
+ for _, p := range podIDs {
+ reply, err := iopodman.RemovePod().Call(r.Conn, p, cli.Force)
+ if err != nil {
+ rmErrs = append(rmErrs, err)
+ } else {
+ rmPods = append(rmPods, reply)
+ }
+ }
+ return rmPods, rmErrs
+}
+
+// Inspect looks up a pod by name or id and embeds its data into a remote pod
+// object.
+func (r *LocalRuntime) Inspect(nameOrID string) (*Pod, error) {
+ reply, err := iopodman.PodStateData().Call(r.Conn, nameOrID)
+ if err != nil {
+ return nil, err
+ }
+ data := libpod.PodInspect{}
+ if err := json.Unmarshal([]byte(reply), &data); err != nil {
+ return nil, err
+ }
+ pod := Pod{}
+ pod.Runtime = r
+ pod.config = data.Config
+ pod.state = data.State
+ pod.containers = data.Containers
+ return &pod, nil
+}
+
+// GetLatestPod gets the latest pod and wraps it in an adapter pod
+func (r *LocalRuntime) GetLatestPod() (*Pod, error) {
+ reply, err := iopodman.GetPodsByContext().Call(r.Conn, false, true, nil)
+ if err != nil {
+ return nil, err
+ }
+ if len(reply) > 0 {
+ return r.Inspect(reply[0])
+ }
+ return nil, errors.New("no pods exist")
+}
+
+// LookupPod gets a pod by name or ID and wraps it in an adapter pod
+func (r *LocalRuntime) LookupPod(nameOrID string) (*Pod, error) {
+ return r.Inspect(nameOrID)
+}
+
+// Inspect, like libpod pod inspect, returns a libpod.PodInspect object from
+// the data of a remotepod data struct
+func (p *Pod) Inspect() (*libpod.PodInspect, error) {
+ config := new(libpod.PodConfig)
+ deepcopier.Copy(p.remotepod.config).To(config)
+ inspectData := libpod.PodInspect{
+ Config: config,
+ State: p.remotepod.state,
+ Containers: p.containers,
+ }
+ return &inspectData, nil
+}
+
+// StopPods stops pods based on the cli context from the remote client.
+func (r *LocalRuntime) StopPods(ctx context.Context, cli *cliconfig.PodStopValues) ([]string, []error) {
+ var (
+ stopErrs []error
+ stopPods []string
+ )
+ var timeout int64 = -1
+ if cli.Flags().Changed("timeout") {
+ timeout = int64(cli.Timeout)
+ }
+ podIDs, err := iopodman.GetPodsByContext().Call(r.Conn, cli.All, cli.Latest, cli.InputArgs)
+ if err != nil {
+ return nil, []error{err}
+ }
+
+ for _, p := range podIDs {
+ podID, err := iopodman.StopPod().Call(r.Conn, p, timeout)
+ if err != nil {
+ stopErrs = append(stopErrs, err)
+ } else {
+ stopPods = append(stopPods, podID)
+ }
+ }
+ return stopPods, stopErrs
+}
+
+// KillPods kills pods over varlink for the remoteclient
+func (r *LocalRuntime) KillPods(ctx context.Context, cli *cliconfig.PodKillValues, signal uint) ([]string, []error) {
+ var (
+ killErrs []error
+ killPods []string
+ )
+
+ podIDs, err := iopodman.GetPodsByContext().Call(r.Conn, cli.All, cli.Latest, cli.InputArgs)
+ if err != nil {
+ return nil, []error{err}
+ }
+
+ for _, p := range podIDs {
+ podID, err := iopodman.KillPod().Call(r.Conn, p, int64(signal))
+ if err != nil {
+ killErrs = append(killErrs, err)
+ } else {
+ killPods = append(killPods, podID)
+ }
+ }
+ return killPods, killErrs
+}
+
+// StartPods starts pods for the remote client over varlink
+func (r *LocalRuntime) StartPods(ctx context.Context, cli *cliconfig.PodStartValues) ([]string, []error) {
+ var (
+ startErrs []error
+ startPods []string
+ )
+
+ podIDs, err := iopodman.GetPodsByContext().Call(r.Conn, cli.All, cli.Latest, cli.InputArgs)
+ if err != nil {
+ return nil, []error{err}
+ }
+
+ for _, p := range podIDs {
+ podID, err := iopodman.StartPod().Call(r.Conn, p)
+ if err != nil {
+ startErrs = append(startErrs, err)
+ } else {
+ startPods = append(startPods, podID)
+ }
+ }
+ 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
+}
+
+// PausePods pauses a pod using varlink and the remote client
+func (r *LocalRuntime) PausePods(c *cliconfig.PodPauseValues) ([]string, map[string]error, []error) {
+ var (
+ pauseIDs []string
+ pauseErrors []error
+ )
+ containerErrors := make(map[string]error)
+
+ pods, err := iopodman.GetPodsByContext().Call(r.Conn, c.All, c.Latest, c.InputArgs)
+ if err != nil {
+ pauseErrors = append(pauseErrors, err)
+ return nil, containerErrors, pauseErrors
+ }
+ for _, pod := range pods {
+ reply, err := iopodman.PausePod().Call(r.Conn, pod)
+ if err != nil {
+ pauseErrors = append(pauseErrors, err)
+ continue
+ }
+ pauseIDs = append(pauseIDs, reply)
+ }
+ return pauseIDs, nil, pauseErrors
+}
+
+// UnpausePods unpauses a pod using varlink and the remote client
+func (r *LocalRuntime) UnpausePods(c *cliconfig.PodUnpauseValues) ([]string, map[string]error, []error) {
+ var (
+ unpauseIDs []string
+ unpauseErrors []error
+ )
+ containerErrors := make(map[string]error)
+
+ pods, err := iopodman.GetPodsByContext().Call(r.Conn, c.All, c.Latest, c.InputArgs)
+ if err != nil {
+ unpauseErrors = append(unpauseErrors, err)
+ return nil, containerErrors, unpauseErrors
+ }
+ for _, pod := range pods {
+ reply, err := iopodman.UnpausePod().Call(r.Conn, pod)
+ if err != nil {
+ unpauseErrors = append(unpauseErrors, err)
+ continue
+ }
+ unpauseIDs = append(unpauseIDs, reply)
+ }
+ return unpauseIDs, nil, unpauseErrors
+}
+
+// RestartPods restarts pods using varlink and the remote client
+func (r *LocalRuntime) RestartPods(ctx context.Context, c *cliconfig.PodRestartValues) ([]string, map[string]error, []error) {
+ var (
+ restartIDs []string
+ restartErrors []error
+ )
+ containerErrors := make(map[string]error)
+
+ pods, err := iopodman.GetPodsByContext().Call(r.Conn, c.All, c.Latest, c.InputArgs)
+ if err != nil {
+ restartErrors = append(restartErrors, err)
+ return nil, containerErrors, restartErrors
+ }
+ for _, pod := range pods {
+ reply, err := iopodman.RestartPod().Call(r.Conn, pod)
+ if err != nil {
+ restartErrors = append(restartErrors, err)
+ continue
+ }
+ restartIDs = append(restartIDs, reply)
+ }
+ return restartIDs, nil, restartErrors
+}
diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go
new file mode 100644
index 000000000..4f5b98dbb
--- /dev/null
+++ b/pkg/adapter/runtime.go
@@ -0,0 +1,335 @@
+// +build !remoteclient
+
+package adapter
+
+import (
+ "context"
+ "io"
+ "io/ioutil"
+ "os"
+ "strconv"
+
+ "github.com/containers/buildah"
+ "github.com/containers/buildah/imagebuildah"
+ "github.com/containers/buildah/pkg/parse"
+ "github.com/containers/image/docker/reference"
+ "github.com/containers/image/types"
+ "github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/cmd/podman/libpodruntime"
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/pkg/rootless"
+ "github.com/pkg/errors"
+)
+
+// LocalRuntime describes a typical libpod runtime
+type LocalRuntime struct {
+ *libpod.Runtime
+ Remote bool
+}
+
+// ContainerImage ...
+type ContainerImage struct {
+ *image.Image
+}
+
+// Container ...
+type Container struct {
+ *libpod.Container
+}
+
+// Volume ...
+type Volume struct {
+ *libpod.Volume
+}
+
+// VolumeFilter is for filtering volumes on the client
+type VolumeFilter func(*Volume) bool
+
+// GetRuntime returns a LocalRuntime struct with the actual runtime embedded in it
+func GetRuntime(c *cliconfig.PodmanCommand) (*LocalRuntime, error) {
+ runtime, err := libpodruntime.GetRuntime(c)
+ if err != nil {
+ return nil, err
+ }
+ return &LocalRuntime{
+ Runtime: runtime,
+ }, nil
+}
+
+// GetImages returns a slice of images in containerimages
+func (r *LocalRuntime) GetImages() ([]*ContainerImage, error) {
+ var containerImages []*ContainerImage
+ images, err := r.Runtime.ImageRuntime().GetImages()
+ if err != nil {
+ return nil, err
+ }
+ for _, i := range images {
+ containerImages = append(containerImages, &ContainerImage{i})
+ }
+ return containerImages, nil
+
+}
+
+// NewImageFromLocal returns a containerimage representation of a image from local storage
+func (r *LocalRuntime) NewImageFromLocal(name string) (*ContainerImage, error) {
+ img, err := r.Runtime.ImageRuntime().NewFromLocal(name)
+ if err != nil {
+ return nil, err
+ }
+ return &ContainerImage{img}, nil
+}
+
+// LoadFromArchiveReference calls into local storage to load an image from an archive
+func (r *LocalRuntime) LoadFromArchiveReference(ctx context.Context, srcRef types.ImageReference, signaturePolicyPath string, writer io.Writer) ([]*ContainerImage, error) {
+ var containerImages []*ContainerImage
+ imgs, err := r.Runtime.ImageRuntime().LoadFromArchiveReference(ctx, srcRef, signaturePolicyPath, writer)
+ if err != nil {
+ return nil, err
+ }
+ for _, i := range imgs {
+ ci := ContainerImage{i}
+ containerImages = append(containerImages, &ci)
+ }
+ return containerImages, nil
+}
+
+// New calls into local storage to look for an image in local storage or to pull it
+func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *image.DockerRegistryOptions, signingoptions image.SigningOptions, forcePull bool, label *string) (*ContainerImage, error) {
+ img, err := r.Runtime.ImageRuntime().New(ctx, name, signaturePolicyPath, authfile, writer, dockeroptions, signingoptions, forcePull, label)
+ if err != nil {
+ return nil, err
+ }
+ return &ContainerImage{img}, nil
+}
+
+// RemoveImage calls into local storage and removes an image
+func (r *LocalRuntime) RemoveImage(ctx context.Context, img *ContainerImage, force bool) (string, error) {
+ return r.Runtime.RemoveImage(ctx, img.Image, force)
+}
+
+// LookupContainer ...
+func (r *LocalRuntime) LookupContainer(idOrName string) (*Container, error) {
+ ctr, err := r.Runtime.LookupContainer(idOrName)
+ if err != nil {
+ return nil, err
+ }
+ return &Container{ctr}, nil
+}
+
+// PruneImages is wrapper into PruneImages within the image pkg
+func (r *LocalRuntime) PruneImages(all bool) ([]string, error) {
+ return r.ImageRuntime().PruneImages(all)
+}
+
+// Export is a wrapper to container export to a tarfile
+func (r *LocalRuntime) Export(name string, path string) error {
+ ctr, err := r.Runtime.LookupContainer(name)
+ if err != nil {
+ return errors.Wrapf(err, "error looking up container %q", name)
+ }
+ if os.Geteuid() != 0 {
+ state, err := ctr.State()
+ if err != nil {
+ return errors.Wrapf(err, "cannot read container state %q", ctr.ID())
+ }
+ if state == libpod.ContainerStateRunning || state == libpod.ContainerStatePaused {
+ data, err := ioutil.ReadFile(ctr.Config().ConmonPidFile)
+ if err != nil {
+ return errors.Wrapf(err, "cannot read conmon PID file %q", ctr.Config().ConmonPidFile)
+ }
+ conmonPid, err := strconv.Atoi(string(data))
+ if err != nil {
+ return errors.Wrapf(err, "cannot parse PID %q", data)
+ }
+ became, ret, err := rootless.JoinDirectUserAndMountNS(uint(conmonPid))
+ if err != nil {
+ return err
+ }
+ if became {
+ os.Exit(ret)
+ }
+ } else {
+ became, ret, err := rootless.BecomeRootInUserNS()
+ if err != nil {
+ return err
+ }
+ if became {
+ os.Exit(ret)
+ }
+ }
+ }
+
+ return ctr.Export(path)
+}
+
+// Import is a wrapper to import a container image
+func (r *LocalRuntime) Import(ctx context.Context, source, reference string, changes []string, history string, quiet bool) (string, error) {
+ return r.Runtime.Import(ctx, source, reference, changes, history, quiet)
+}
+
+// CreateVolume is a wrapper to create volumes
+func (r *LocalRuntime) CreateVolume(ctx context.Context, c *cliconfig.VolumeCreateValues, labels, opts map[string]string) (string, error) {
+ var (
+ options []libpod.VolumeCreateOption
+ volName string
+ )
+
+ if len(c.InputArgs) > 0 {
+ volName = c.InputArgs[0]
+ options = append(options, libpod.WithVolumeName(volName))
+ }
+
+ if c.Flag("driver").Changed {
+ options = append(options, libpod.WithVolumeDriver(c.Driver))
+ }
+
+ if len(labels) != 0 {
+ options = append(options, libpod.WithVolumeLabels(labels))
+ }
+
+ if len(options) != 0 {
+ options = append(options, libpod.WithVolumeOptions(opts))
+ }
+ newVolume, err := r.NewVolume(ctx, options...)
+ if err != nil {
+ return "", err
+ }
+ return newVolume.Name(), nil
+}
+
+// RemoveVolumes is a wrapper to remove volumes
+func (r *LocalRuntime) RemoveVolumes(ctx context.Context, c *cliconfig.VolumeRmValues) ([]string, error) {
+ return r.Runtime.RemoveVolumes(ctx, c.InputArgs, c.All, c.Force)
+}
+
+// Push is a wrapper to push an image to a registry
+func (r *LocalRuntime) Push(ctx context.Context, srcName, destination, manifestMIMEType, authfile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions image.SigningOptions, dockerRegistryOptions *image.DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error {
+ newImage, err := r.ImageRuntime().NewFromLocal(srcName)
+ if err != nil {
+ return err
+ }
+ return newImage.PushImageToHeuristicDestination(ctx, destination, manifestMIMEType, authfile, signaturePolicyPath, writer, forceCompress, signingOptions, dockerRegistryOptions, nil)
+}
+
+// InspectVolumes returns a slice of volumes based on an arg list or --all
+func (r *LocalRuntime) InspectVolumes(ctx context.Context, c *cliconfig.VolumeInspectValues) ([]*Volume, error) {
+ var (
+ volumes []*libpod.Volume
+ err error
+ )
+
+ if c.All {
+ volumes, err = r.GetAllVolumes()
+ } else {
+ for _, v := range c.InputArgs {
+ vol, err := r.GetVolume(v)
+ if err != nil {
+ return nil, err
+ }
+ volumes = append(volumes, vol)
+ }
+ }
+ if err != nil {
+ return nil, err
+ }
+ return libpodVolumeToVolume(volumes), nil
+}
+
+// Volumes returns a slice of localruntime volumes
+func (r *LocalRuntime) Volumes(ctx context.Context) ([]*Volume, error) {
+ vols, err := r.GetAllVolumes()
+ if err != nil {
+ return nil, err
+ }
+ return libpodVolumeToVolume(vols), nil
+}
+
+// libpodVolumeToVolume converts a slice of libpod volumes to a slice
+// of localruntime volumes (same as libpod)
+func libpodVolumeToVolume(volumes []*libpod.Volume) []*Volume {
+ var vols []*Volume
+ for _, v := range volumes {
+ newVol := Volume{
+ v,
+ }
+ vols = append(vols, &newVol)
+ }
+ return vols
+}
+
+// Build is the wrapper to build images
+func (r *LocalRuntime) Build(ctx context.Context, c *cliconfig.BuildValues, options imagebuildah.BuildOptions, dockerfiles []string) error {
+ namespaceOptions, networkPolicy, err := parse.NamespaceOptions(c.PodmanCommand.Command)
+ if err != nil {
+ return errors.Wrapf(err, "error parsing namespace-related options")
+ }
+ usernsOption, idmappingOptions, err := parse.IDMappingOptions(c.PodmanCommand.Command)
+ if err != nil {
+ return errors.Wrapf(err, "error parsing ID mapping options")
+ }
+ namespaceOptions.AddOrReplace(usernsOption...)
+
+ systemContext, err := parse.SystemContextFromOptions(c.PodmanCommand.Command)
+ if err != nil {
+ return errors.Wrapf(err, "error building system context")
+ }
+
+ authfile := c.Authfile
+ if len(c.Authfile) == 0 {
+ authfile = os.Getenv("REGISTRY_AUTH_FILE")
+ }
+
+ systemContext.AuthFilePath = authfile
+ commonOpts, err := parse.CommonBuildOptions(c.PodmanCommand.Command)
+ if err != nil {
+ return err
+ }
+
+ options.NamespaceOptions = namespaceOptions
+ options.ConfigureNetwork = networkPolicy
+ options.IDMappingOptions = idmappingOptions
+ options.CommonBuildOpts = commonOpts
+ options.SystemContext = systemContext
+
+ if c.Flag("runtime").Changed {
+ options.Runtime = r.GetOCIRuntimePath()
+ }
+ if c.Quiet {
+ options.ReportWriter = ioutil.Discard
+ }
+
+ if rootless.IsRootless() {
+ options.Isolation = buildah.IsolationOCIRootless
+ }
+
+ return r.Runtime.Build(ctx, options, dockerfiles...)
+}
+
+// PruneVolumes is a wrapper function for libpod PruneVolumes
+func (r *LocalRuntime) PruneVolumes(ctx context.Context) ([]string, []error) {
+ return r.Runtime.PruneVolumes(ctx)
+}
+
+// SaveImage is a wrapper function for saving an image to the local filesystem
+func (r *LocalRuntime) SaveImage(ctx context.Context, c *cliconfig.SaveValues) error {
+ source := c.InputArgs[0]
+ additionalTags := c.InputArgs[1:]
+
+ newImage, err := r.Runtime.ImageRuntime().NewFromLocal(source)
+ if err != nil {
+ return err
+ }
+ return newImage.Save(ctx, source, c.Format, c.Output, additionalTags, c.Quiet, c.Compress)
+}
+
+// LoadImage is a wrapper function for libpod PruneVolumes
+func (r *LocalRuntime) LoadImage(ctx context.Context, name string, cli *cliconfig.LoadValues) (string, error) {
+ var (
+ writer io.Writer
+ )
+ if !cli.Quiet {
+ writer = os.Stderr
+ }
+ return r.Runtime.LoadImage(ctx, name, cli.Input, writer, cli.SignaturePolicy)
+}
diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go
new file mode 100644
index 000000000..ca2fad852
--- /dev/null
+++ b/pkg/adapter/runtime_remote.go
@@ -0,0 +1,798 @@
+// +build remoteclient
+
+package adapter
+
+import (
+ "bufio"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "strings"
+ "time"
+
+ "github.com/containers/buildah/imagebuildah"
+ "github.com/containers/image/docker/reference"
+ "github.com/containers/image/types"
+ "github.com/containers/libpod/cmd/podman/cliconfig"
+ "github.com/containers/libpod/cmd/podman/varlink"
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/utils"
+ "github.com/containers/storage/pkg/archive"
+ "github.com/opencontainers/go-digest"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ "github.com/varlink/go/varlink"
+)
+
+// ImageRuntime is wrapper for image runtime
+type RemoteImageRuntime struct{}
+
+// RemoteRuntime describes a wrapper runtime struct
+type RemoteRuntime struct {
+ Conn *varlink.Connection
+ Remote bool
+}
+
+// LocalRuntime describes a typical libpod runtime
+type LocalRuntime struct {
+ *RemoteRuntime
+}
+
+// GetRuntime returns a LocalRuntime struct with the actual runtime embedded in it
+func GetRuntime(c *cliconfig.PodmanCommand) (*LocalRuntime, error) {
+ runtime := RemoteRuntime{}
+ conn, err := runtime.Connect()
+ if err != nil {
+ return nil, err
+ }
+ rr := RemoteRuntime{
+ Conn: conn,
+ Remote: true,
+ }
+ foo := LocalRuntime{
+ &rr,
+ }
+ return &foo, nil
+}
+
+// Shutdown is a bogus wrapper for compat with the libpod runtime
+func (r RemoteRuntime) Shutdown(force bool) error {
+ return nil
+}
+
+// ContainerImage
+type ContainerImage struct {
+ remoteImage
+}
+
+type remoteImage struct {
+ ID string
+ Labels map[string]string
+ RepoTags []string
+ RepoDigests []string
+ Parent string
+ Size int64
+ Created time.Time
+ InputName string
+ Names []string
+ Digest digest.Digest
+ isParent bool
+ Runtime *LocalRuntime
+}
+
+// Container ...
+type Container struct {
+ remoteContainer
+}
+
+// remoteContainer ....
+type remoteContainer struct {
+ Runtime *LocalRuntime
+ config *libpod.ContainerConfig
+ state *libpod.ContainerState
+}
+
+type VolumeFilter func(*Volume) bool
+
+// Volume is embed for libpod volumes
+type Volume struct {
+ remoteVolume
+}
+
+type remoteVolume struct {
+ Runtime *LocalRuntime
+ config *libpod.VolumeConfig
+}
+
+// GetImages returns a slice of containerimages over a varlink connection
+func (r *LocalRuntime) GetImages() ([]*ContainerImage, error) {
+ var newImages []*ContainerImage
+ images, err := iopodman.ListImages().Call(r.Conn)
+ if err != nil {
+ return nil, err
+ }
+ for _, i := range images {
+ name := i.Id
+ if len(i.RepoTags) > 1 {
+ name = i.RepoTags[0]
+ }
+ newImage, err := imageInListToContainerImage(i, name, r)
+ if err != nil {
+ return nil, err
+ }
+ newImages = append(newImages, newImage)
+ }
+ return newImages, nil
+}
+
+func imageInListToContainerImage(i iopodman.Image, name string, runtime *LocalRuntime) (*ContainerImage, error) {
+ created, err := time.ParseInLocation(time.RFC3339, i.Created, time.UTC)
+ if err != nil {
+ return nil, err
+ }
+ ri := remoteImage{
+ InputName: name,
+ ID: i.Id,
+ Labels: i.Labels,
+ RepoTags: i.RepoTags,
+ RepoDigests: i.RepoTags,
+ Parent: i.ParentId,
+ Size: i.Size,
+ Created: created,
+ Names: i.RepoTags,
+ isParent: i.IsParent,
+ Runtime: runtime,
+ }
+ return &ContainerImage{ri}, nil
+}
+
+// NewImageFromLocal returns a container image representation of a image over varlink
+func (r *LocalRuntime) NewImageFromLocal(name string) (*ContainerImage, error) {
+ img, err := iopodman.GetImage().Call(r.Conn, name)
+ if err != nil {
+ return nil, err
+ }
+ return imageInListToContainerImage(img, name, r)
+
+}
+
+// LoadFromArchiveReference creates an image from a local archive
+func (r *LocalRuntime) LoadFromArchiveReference(ctx context.Context, srcRef types.ImageReference, signaturePolicyPath string, writer io.Writer) ([]*ContainerImage, error) {
+ var iid string
+ // TODO We need to find a way to leak certDir, creds, and the tlsverify into this function, normally this would
+ // come from cli options but we don't want want those in here either.
+ tlsverify := true
+ reply, err := iopodman.PullImage().Send(r.Conn, varlink.More, srcRef.DockerReference().String(), "", "", signaturePolicyPath, &tlsverify)
+ if err != nil {
+ return nil, err
+ }
+
+ for {
+ responses, flags, err := reply()
+ if err != nil {
+ return nil, err
+ }
+ for _, line := range responses.Logs {
+ fmt.Print(line)
+ }
+ iid = responses.Id
+ if flags&varlink.Continues == 0 {
+ break
+ }
+ }
+
+ newImage, err := r.NewImageFromLocal(iid)
+ if err != nil {
+ return nil, err
+ }
+ return []*ContainerImage{newImage}, nil
+}
+
+// New calls into local storage to look for an image in local storage or to pull it
+func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *image.DockerRegistryOptions, signingoptions image.SigningOptions, forcePull bool, label *string) (*ContainerImage, error) {
+ var iid string
+ if label != nil {
+ return nil, errors.New("the remote client function does not support checking a remote image for a label")
+ }
+ var (
+ tlsVerify bool
+ tlsVerifyPtr *bool
+ )
+ if dockeroptions.DockerInsecureSkipTLSVerify == types.OptionalBoolFalse {
+ tlsVerify = true
+ tlsVerifyPtr = &tlsVerify
+
+ }
+ if dockeroptions.DockerInsecureSkipTLSVerify == types.OptionalBoolTrue {
+ tlsVerify = false
+ tlsVerifyPtr = &tlsVerify
+ }
+
+ reply, err := iopodman.PullImage().Send(r.Conn, varlink.More, name, dockeroptions.DockerCertPath, "", signaturePolicyPath, tlsVerifyPtr)
+ if err != nil {
+ return nil, err
+ }
+ for {
+ responses, flags, err := reply()
+ if err != nil {
+ return nil, err
+ }
+ for _, line := range responses.Logs {
+ fmt.Print(line)
+ }
+ iid = responses.Id
+ if flags&varlink.Continues == 0 {
+ break
+ }
+ }
+ newImage, err := r.NewImageFromLocal(iid)
+ if err != nil {
+ return nil, err
+ }
+ return newImage, nil
+}
+
+// IsParent goes through the layers in the store and checks if i.TopLayer is
+// the parent of any other layer in store. Double check that image with that
+// layer exists as well.
+func (ci *ContainerImage) IsParent() (bool, error) {
+ return ci.remoteImage.isParent, nil
+}
+
+// ID returns the image ID as a string
+func (ci *ContainerImage) ID() string {
+ return ci.remoteImage.ID
+}
+
+// Names returns a string array of names associated with the image
+func (ci *ContainerImage) Names() []string {
+ return ci.remoteImage.Names
+}
+
+// Created returns the time the image was created
+func (ci *ContainerImage) Created() time.Time {
+ return ci.remoteImage.Created
+}
+
+// Size returns the size of the image
+func (ci *ContainerImage) Size(ctx context.Context) (*uint64, error) {
+ usize := uint64(ci.remoteImage.Size)
+ return &usize, nil
+}
+
+// Digest returns the image's digest
+func (ci *ContainerImage) Digest() digest.Digest {
+ return ci.remoteImage.Digest
+}
+
+// Labels returns a map of the image's labels
+func (ci *ContainerImage) Labels(ctx context.Context) (map[string]string, error) {
+ return ci.remoteImage.Labels, nil
+}
+
+// Dangling returns a bool if the image is "dangling"
+func (ci *ContainerImage) Dangling() bool {
+ return len(ci.Names()) == 0
+}
+
+// TagImage ...
+func (ci *ContainerImage) TagImage(tag string) error {
+ _, err := iopodman.TagImage().Call(ci.Runtime.Conn, ci.ID(), tag)
+ return err
+}
+
+// RemoveImage calls varlink to remove an image
+func (r *LocalRuntime) RemoveImage(ctx context.Context, img *ContainerImage, force bool) (string, error) {
+ return iopodman.RemoveImage().Call(r.Conn, img.InputName, force)
+}
+
+// History returns the history of an image and its layers
+func (ci *ContainerImage) History(ctx context.Context) ([]*image.History, error) {
+ var imageHistories []*image.History
+
+ reply, err := iopodman.HistoryImage().Call(ci.Runtime.Conn, ci.InputName)
+ if err != nil {
+ return nil, err
+ }
+ for _, h := range reply {
+ created, err := time.ParseInLocation(time.RFC3339, h.Created, time.UTC)
+ if err != nil {
+ return nil, err
+ }
+ ih := image.History{
+ ID: h.Id,
+ Created: &created,
+ CreatedBy: h.CreatedBy,
+ Size: h.Size,
+ Comment: h.Comment,
+ }
+ imageHistories = append(imageHistories, &ih)
+ }
+ return imageHistories, nil
+}
+
+// LookupContainer gets basic information about container over a varlink
+// connection and then translates it to a *Container
+func (r *LocalRuntime) LookupContainer(idOrName string) (*Container, error) {
+ state, err := r.ContainerState(idOrName)
+ if err != nil {
+ return nil, err
+ }
+ config := r.Config(idOrName)
+ if err != nil {
+ return nil, err
+ }
+
+ rc := remoteContainer{
+ r,
+ config,
+ state,
+ }
+
+ c := Container{
+ rc,
+ }
+ return &c, nil
+}
+
+func (r *LocalRuntime) GetLatestContainer() (*Container, error) {
+ return nil, libpod.ErrNotImplemented
+}
+
+// ContainerState returns the "state" of the container.
+func (r *LocalRuntime) ContainerState(name string) (*libpod.ContainerState, error) { //no-lint
+ reply, err := iopodman.ContainerStateData().Call(r.Conn, name)
+ if err != nil {
+ return nil, err
+ }
+ data := libpod.ContainerState{}
+ if err := json.Unmarshal([]byte(reply), &data); err != nil {
+ return nil, err
+ }
+ return &data, err
+
+}
+
+// Config returns a container config
+func (r *LocalRuntime) Config(name string) *libpod.ContainerConfig {
+ // TODO the Spec being returned is not populated. Matt and I could not figure out why. Will defer
+ // further looking into it for after devconf.
+ // The libpod function for this has no errors so we are kind of in a tough
+ // spot here. Logging the errors for now.
+ reply, err := iopodman.ContainerConfig().Call(r.Conn, name)
+ if err != nil {
+ logrus.Error("call to container.config failed")
+ }
+ data := libpod.ContainerConfig{}
+ if err := json.Unmarshal([]byte(reply), &data); err != nil {
+ logrus.Error("failed to unmarshal container inspect data")
+ }
+ return &data
+
+}
+
+// PruneImages is the wrapper call for a remote-client to prune images
+func (r *LocalRuntime) PruneImages(all bool) ([]string, error) {
+ return iopodman.ImagesPrune().Call(r.Conn, all)
+}
+
+// Export is a wrapper to container export to a tarfile
+func (r *LocalRuntime) Export(name string, path string) error {
+ tempPath, err := iopodman.ExportContainer().Call(r.Conn, name, "")
+ if err != nil {
+ return err
+ }
+ return r.GetFileFromRemoteHost(tempPath, path, true)
+}
+
+func (r *LocalRuntime) GetFileFromRemoteHost(remoteFilePath, outputPath string, delete bool) error {
+ outputFile, err := os.Create(outputPath)
+ if err != nil {
+ return err
+ }
+ defer outputFile.Close()
+
+ writer := bufio.NewWriter(outputFile)
+ defer writer.Flush()
+
+ reply, err := iopodman.ReceiveFile().Send(r.Conn, varlink.Upgrade, remoteFilePath, delete)
+ if err != nil {
+ return err
+ }
+
+ length, _, err := reply()
+ if err != nil {
+ return errors.Wrap(err, "unable to get file length for transfer")
+ }
+
+ reader := r.Conn.Reader
+ if _, err := io.CopyN(writer, reader, length); err != nil {
+ return errors.Wrap(err, "file transer failed")
+ }
+ return nil
+}
+
+// Import implements the remote calls required to import a container image to the store
+func (r *LocalRuntime) Import(ctx context.Context, source, reference string, changes []string, history string, quiet bool) (string, error) {
+ // First we send the file to the host
+ tempFile, err := r.SendFileOverVarlink(source)
+ if err != nil {
+ return "", err
+ }
+ return iopodman.ImportImage().Call(r.Conn, strings.TrimRight(tempFile, ":"), reference, history, changes, true)
+}
+
+func (r *LocalRuntime) Build(ctx context.Context, c *cliconfig.BuildValues, options imagebuildah.BuildOptions, dockerfiles []string) error {
+ buildOptions := iopodman.BuildOptions{
+ AddHosts: options.CommonBuildOpts.AddHost,
+ CgroupParent: options.CommonBuildOpts.CgroupParent,
+ CpuPeriod: int64(options.CommonBuildOpts.CPUPeriod),
+ CpuQuota: options.CommonBuildOpts.CPUQuota,
+ CpuShares: int64(options.CommonBuildOpts.CPUShares),
+ CpusetCpus: options.CommonBuildOpts.CPUSetMems,
+ CpusetMems: options.CommonBuildOpts.CPUSetMems,
+ Memory: options.CommonBuildOpts.Memory,
+ MemorySwap: options.CommonBuildOpts.MemorySwap,
+ ShmSize: options.CommonBuildOpts.ShmSize,
+ Ulimit: options.CommonBuildOpts.Ulimit,
+ Volume: options.CommonBuildOpts.Volumes,
+ }
+
+ buildinfo := iopodman.BuildInfo{
+ AdditionalTags: options.AdditionalTags,
+ Annotations: options.Annotations,
+ BuildArgs: options.Args,
+ BuildOptions: buildOptions,
+ CniConfigDir: options.CNIConfigDir,
+ CniPluginDir: options.CNIPluginPath,
+ Compression: string(options.Compression),
+ DefaultsMountFilePath: options.DefaultMountsFilePath,
+ Dockerfiles: dockerfiles,
+ //Err: string(options.Err),
+ ForceRmIntermediateCtrs: options.ForceRmIntermediateCtrs,
+ Iidfile: options.IIDFile,
+ Label: options.Labels,
+ Layers: options.Layers,
+ Nocache: options.NoCache,
+ //Out:
+ Output: options.Output,
+ OutputFormat: options.OutputFormat,
+ PullPolicy: options.PullPolicy.String(),
+ Quiet: options.Quiet,
+ RemoteIntermediateCtrs: options.RemoveIntermediateCtrs,
+ //ReportWriter:
+ RuntimeArgs: options.RuntimeArgs,
+ SignaturePolicyPath: options.SignaturePolicyPath,
+ Squash: options.Squash,
+ }
+ // tar the file
+ outputFile, err := ioutil.TempFile("", "varlink_tar_send")
+ if err != nil {
+ return err
+ }
+ defer outputFile.Close()
+ defer os.Remove(outputFile.Name())
+
+ // Create the tarball of the context dir to a tempfile
+ if err := utils.TarToFilesystem(options.ContextDirectory, outputFile); err != nil {
+ return err
+ }
+ // Send the context dir tarball over varlink.
+ tempFile, err := r.SendFileOverVarlink(outputFile.Name())
+ if err != nil {
+ return err
+ }
+ buildinfo.ContextDir = tempFile
+
+ reply, err := iopodman.BuildImage().Send(r.Conn, varlink.More, buildinfo)
+ if err != nil {
+ return err
+ }
+
+ for {
+ responses, flags, err := reply()
+ if err != nil {
+ return err
+ }
+ for _, line := range responses.Logs {
+ fmt.Print(line)
+ }
+ if flags&varlink.Continues == 0 {
+ break
+ }
+ }
+ return err
+}
+
+// SendFileOverVarlink sends a file over varlink in an upgraded connection
+func (r *LocalRuntime) SendFileOverVarlink(source string) (string, error) {
+ fs, err := os.Open(source)
+ if err != nil {
+ return "", err
+ }
+
+ fileInfo, err := fs.Stat()
+ if err != nil {
+ return "", err
+ }
+ logrus.Debugf("sending %s over varlink connection", source)
+ reply, err := iopodman.SendFile().Send(r.Conn, varlink.Upgrade, "", int64(fileInfo.Size()))
+ if err != nil {
+ return "", err
+ }
+ _, _, err = reply()
+ if err != nil {
+ return "", err
+ }
+
+ reader := bufio.NewReader(fs)
+ _, err = reader.WriteTo(r.Conn.Writer)
+ if err != nil {
+ return "", err
+ }
+ logrus.Debugf("file transfer complete for %s", source)
+ r.Conn.Writer.Flush()
+
+ // All was sent, wait for the ACK from the server
+ tempFile, err := r.Conn.Reader.ReadString(':')
+ if err != nil {
+ return "", err
+ }
+
+ // r.Conn is kaput at this point due to the upgrade
+ if err := r.RemoteRuntime.RefreshConnection(); err != nil {
+ return "", err
+
+ }
+
+ return strings.Replace(tempFile, ":", "", -1), nil
+}
+
+// GetAllVolumes retrieves all the volumes
+func (r *LocalRuntime) GetAllVolumes() ([]*libpod.Volume, error) {
+ return nil, libpod.ErrNotImplemented
+}
+
+// RemoveVolume removes a volumes
+func (r *LocalRuntime) RemoveVolume(ctx context.Context, v *libpod.Volume, force, prune bool) error {
+ return libpod.ErrNotImplemented
+}
+
+// GetContainers retrieves all containers from the state
+// Filters can be provided which will determine what containers are included in
+// the output. Multiple filters are handled by ANDing their output, so only
+// containers matching all filters are returned
+func (r *LocalRuntime) GetContainers(filters ...libpod.ContainerFilter) ([]*libpod.Container, error) {
+ return nil, libpod.ErrNotImplemented
+}
+
+// RemoveContainer removes the given container
+// If force is specified, the container will be stopped first
+// Otherwise, RemoveContainer will return an error if the container is running
+func (r *LocalRuntime) RemoveContainer(ctx context.Context, c *libpod.Container, force, volumes bool) error {
+ return libpod.ErrNotImplemented
+}
+
+// CreateVolume creates a volume over a varlink connection for the remote client
+func (r *LocalRuntime) CreateVolume(ctx context.Context, c *cliconfig.VolumeCreateValues, labels, opts map[string]string) (string, error) {
+ cvOpts := iopodman.VolumeCreateOpts{
+ Options: opts,
+ Labels: labels,
+ }
+ if len(c.InputArgs) > 0 {
+ cvOpts.VolumeName = c.InputArgs[0]
+ }
+
+ if c.Flag("driver").Changed {
+ cvOpts.Driver = c.Driver
+ }
+
+ return iopodman.VolumeCreate().Call(r.Conn, cvOpts)
+}
+
+// RemoveVolumes removes volumes over a varlink connection for the remote client
+func (r *LocalRuntime) RemoveVolumes(ctx context.Context, c *cliconfig.VolumeRmValues) ([]string, error) {
+ rmOpts := iopodman.VolumeRemoveOpts{
+ All: c.All,
+ Force: c.Force,
+ Volumes: c.InputArgs,
+ }
+ return iopodman.VolumeRemove().Call(r.Conn, rmOpts)
+}
+
+func (r *LocalRuntime) Push(ctx context.Context, srcName, destination, manifestMIMEType, authfile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions image.SigningOptions, dockerRegistryOptions *image.DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error {
+
+ var (
+ tls *bool
+ tlsVerify bool
+ )
+ if dockerRegistryOptions.DockerInsecureSkipTLSVerify == types.OptionalBoolTrue {
+ tlsVerify = false
+ tls = &tlsVerify
+ }
+ if dockerRegistryOptions.DockerInsecureSkipTLSVerify == types.OptionalBoolFalse {
+ tlsVerify = true
+ tls = &tlsVerify
+ }
+
+ reply, err := iopodman.PushImage().Send(r.Conn, varlink.More, srcName, destination, tls, signaturePolicyPath, "", dockerRegistryOptions.DockerCertPath, forceCompress, manifestMIMEType, signingOptions.RemoveSignatures, signingOptions.SignBy)
+ if err != nil {
+ return err
+ }
+ for {
+ responses, flags, err := reply()
+ if err != nil {
+ return err
+ }
+ for _, line := range responses.Logs {
+ fmt.Print(line)
+ }
+ if flags&varlink.Continues == 0 {
+ break
+ }
+ }
+
+ return err
+}
+
+// InspectVolumes returns a slice of volumes based on an arg list or --all
+func (r *LocalRuntime) InspectVolumes(ctx context.Context, c *cliconfig.VolumeInspectValues) ([]*Volume, error) {
+ reply, err := iopodman.GetVolumes().Call(r.Conn, c.InputArgs, c.All)
+ if err != nil {
+ return nil, err
+ }
+ return varlinkVolumeToVolume(r, reply), nil
+}
+
+//Volumes returns a slice of adapter.volumes based on information about libpod
+// volumes over a varlink connection
+func (r *LocalRuntime) Volumes(ctx context.Context) ([]*Volume, error) {
+ reply, err := iopodman.GetVolumes().Call(r.Conn, []string{}, true)
+ if err != nil {
+ return nil, err
+ }
+ return varlinkVolumeToVolume(r, reply), nil
+}
+
+func varlinkVolumeToVolume(r *LocalRuntime, volumes []iopodman.Volume) []*Volume {
+ var vols []*Volume
+ for _, v := range volumes {
+ volumeConfig := libpod.VolumeConfig{
+ Name: v.Name,
+ Labels: v.Labels,
+ MountPoint: v.MountPoint,
+ Driver: v.Driver,
+ Options: v.Options,
+ Scope: v.Scope,
+ }
+ n := remoteVolume{
+ Runtime: r,
+ config: &volumeConfig,
+ }
+ newVol := Volume{
+ n,
+ }
+ vols = append(vols, &newVol)
+ }
+ return vols
+}
+
+// PruneVolumes removes all unused volumes from the remote system
+func (r *LocalRuntime) PruneVolumes(ctx context.Context) ([]string, []error) {
+ var errs []error
+ prunedNames, prunedErrors, err := iopodman.VolumesPrune().Call(r.Conn)
+ if err != nil {
+ return []string{}, []error{err}
+ }
+ // We need to transform the string results of the error into actual error types
+ for _, e := range prunedErrors {
+ errs = append(errs, errors.New(e))
+ }
+ return prunedNames, errs
+}
+
+// SaveImage is a wrapper function for saving an image to the local filesystem
+func (r *LocalRuntime) SaveImage(ctx context.Context, c *cliconfig.SaveValues) error {
+ source := c.InputArgs[0]
+ additionalTags := c.InputArgs[1:]
+
+ options := iopodman.ImageSaveOptions{
+ Name: source,
+ Format: c.Format,
+ Output: c.Output,
+ MoreTags: additionalTags,
+ Quiet: c.Quiet,
+ Compress: c.Compress,
+ }
+ reply, err := iopodman.ImageSave().Send(r.Conn, varlink.More, options)
+ if err != nil {
+ return err
+ }
+
+ var fetchfile string
+ for {
+ responses, flags, err := reply()
+ if err != nil {
+ return err
+ }
+ if len(responses.Id) > 0 {
+ fetchfile = responses.Id
+ }
+ for _, line := range responses.Logs {
+ fmt.Print(line)
+ }
+ if flags&varlink.Continues == 0 {
+ break
+ }
+
+ }
+ if err != nil {
+ return err
+ }
+
+ outputToDir := false
+ outfile := c.Output
+ var outputFile *os.File
+ // If the result is supposed to be a dir, then we need to put the tarfile
+ // from the host in a temporary file
+ if options.Format != "oci-archive" && options.Format != "docker-archive" {
+ outputToDir = true
+ outputFile, err = ioutil.TempFile("", "saveimage_tempfile")
+ if err != nil {
+ return err
+ }
+ outfile = outputFile.Name()
+ defer outputFile.Close()
+ defer os.Remove(outputFile.Name())
+ }
+ // We now need to fetch the tarball result back to the more system
+ if err := r.GetFileFromRemoteHost(fetchfile, outfile, true); err != nil {
+ return err
+ }
+
+ // If the result is a tarball, we're done
+ // If it is a dir, we need to untar the temporary file into the dir
+ if outputToDir {
+ if err := utils.UntarToFileSystem(c.Output, outputFile, &archive.TarOptions{}); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// LoadImage loads a container image from a remote client's filesystem
+func (r *LocalRuntime) LoadImage(ctx context.Context, name string, cli *cliconfig.LoadValues) (string, error) {
+ var names string
+ remoteTempFile, err := r.SendFileOverVarlink(cli.Input)
+ if err != nil {
+ return "", nil
+ }
+ more := varlink.More
+ if cli.Quiet {
+ more = 0
+ }
+ reply, err := iopodman.LoadImage().Send(r.Conn, uint64(more), name, remoteTempFile, cli.Quiet, true)
+ if err != nil {
+ return "", err
+ }
+
+ for {
+ responses, flags, err := reply()
+ if err != nil {
+ logrus.Error(err)
+ return "", err
+ }
+ for _, line := range responses.Logs {
+ fmt.Print(line)
+ }
+ names = responses.Id
+ if flags&varlink.Continues == 0 {
+ break
+ }
+ }
+ return names, nil
+}
diff --git a/pkg/adapter/shortcuts/shortcuts.go b/pkg/adapter/shortcuts/shortcuts.go
new file mode 100644
index 000000000..0633399ae
--- /dev/null
+++ b/pkg/adapter/shortcuts/shortcuts.go
@@ -0,0 +1,27 @@
+package shortcuts
+
+import "github.com/containers/libpod/libpod"
+
+// GetPodsByContext gets pods whether all, latest, or a slice of names/ids
+func GetPodsByContext(all, latest bool, pods []string, runtime *libpod.Runtime) ([]*libpod.Pod, error) {
+ var outpods []*libpod.Pod
+ if all {
+ return runtime.GetAllPods()
+ }
+ if latest {
+ p, err := runtime.GetLatestPod()
+ if err != nil {
+ return nil, err
+ }
+ outpods = append(outpods, p)
+ return outpods, nil
+ }
+ for _, p := range pods {
+ pod, err := runtime.LookupPod(p)
+ if err != nil {
+ return nil, err
+ }
+ outpods = append(outpods, pod)
+ }
+ return outpods, nil
+}
diff --git a/pkg/adapter/volumes_remote.go b/pkg/adapter/volumes_remote.go
new file mode 100644
index 000000000..beacd943a
--- /dev/null
+++ b/pkg/adapter/volumes_remote.go
@@ -0,0 +1,33 @@
+// +build remoteclient
+
+package adapter
+
+// Name returns the name of the volume
+func (v *Volume) Name() string {
+ return v.config.Name
+}
+
+//Labels returns the labels for a volume
+func (v *Volume) Labels() map[string]string {
+ return v.config.Labels
+}
+
+// Driver returns the driver for the volume
+func (v *Volume) Driver() string {
+ return v.config.Driver
+}
+
+// Options returns the options a volume was created with
+func (v *Volume) Options() map[string]string {
+ return v.config.Options
+}
+
+// MountPath returns the path the volume is mounted to
+func (v *Volume) MountPoint() string {
+ return v.config.MountPoint
+}
+
+// Scope returns the scope for an adapter.volume
+func (v *Volume) Scope() string {
+ return v.config.Scope
+}
diff --git a/pkg/registries/registries.go b/pkg/registries/registries.go
index cbb8b730c..9f4c94533 100644
--- a/pkg/registries/registries.go
+++ b/pkg/registries/registries.go
@@ -3,10 +3,12 @@ package registries
import (
"os"
"path/filepath"
+ "strings"
"github.com/containers/image/pkg/sysregistries"
"github.com/containers/image/types"
"github.com/containers/libpod/pkg/rootless"
+ "github.com/docker/distribution/reference"
"github.com/pkg/errors"
)
@@ -49,3 +51,17 @@ func GetInsecureRegistries() ([]string, error) {
}
return registries, nil
}
+
+// GetRegistry returns the registry name from a string if specified
+func GetRegistry(image string) (string, error) {
+ // It is possible to only have the registry name in the format "myregistry/"
+ // if so, just trim the "/" from the end and return the registry name
+ if strings.HasSuffix(image, "/") {
+ return strings.TrimSuffix(image, "/"), nil
+ }
+ imgRef, err := reference.Parse(image)
+ if err != nil {
+ return "", err
+ }
+ return reference.Domain(imgRef.(reference.Named)), nil
+}
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c
index 279a03d3f..dfbc7fe33 100644
--- a/pkg/rootless/rootless_linux.c
+++ b/pkg/rootless/rootless_linux.c
@@ -12,6 +12,7 @@
#include <fcntl.h>
#include <sys/wait.h>
#include <string.h>
+#include <stdbool.h>
static const char *_max_user_namespaces = "/proc/sys/user/max_user_namespaces";
static const char *_unprivileged_user_namespaces = "/proc/sys/kernel/unprivileged_userns_clone";
@@ -108,6 +109,13 @@ reexec_userns_join (int userns, int mountns)
char uid[16];
char **argv;
int pid;
+ char *cwd = getcwd (NULL, 0);
+
+ if (cwd == NULL)
+ {
+ fprintf (stderr, "error getting current working directory: %s\n", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
sprintf (uid, "%d", geteuid ());
@@ -153,6 +161,13 @@ reexec_userns_join (int userns, int mountns)
_exit (EXIT_FAILURE);
}
+ if (chdir (cwd) < 0)
+ {
+ fprintf (stderr, "cannot chdir: %s\n", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
+ free (cwd);
+
execvp (argv[0], argv);
_exit (EXIT_FAILURE);
@@ -186,6 +201,25 @@ reexec_in_user_namespace (int ready)
pid_t ppid = getpid ();
char **argv;
char uid[16];
+ char *listen_fds = NULL;
+ char *listen_pid = NULL;
+ bool do_socket_activation = false;
+ char *cwd = getcwd (NULL, 0);
+
+ if (cwd == NULL)
+ {
+ fprintf (stderr, "error getting current working directory: %s\n", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
+
+ listen_pid = getenv("LISTEN_PID");
+ listen_fds = getenv("LISTEN_FDS");
+
+ if (listen_pid != NULL && listen_fds != NULL) {
+ if (strtol(listen_pid, NULL, 10) == getpid()) {
+ do_socket_activation = true;
+ }
+ }
sprintf (uid, "%d", geteuid ());
@@ -197,8 +231,22 @@ reexec_in_user_namespace (int ready)
check_proc_sys_userns_file (_max_user_namespaces);
check_proc_sys_userns_file (_unprivileged_user_namespaces);
}
- if (pid)
+ if (pid) {
+ if (do_socket_activation) {
+ long num_fds;
+ num_fds = strtol(listen_fds, NULL, 10);
+ if (num_fds != LONG_MIN && num_fds != LONG_MAX) {
+ long i;
+ for (i = 0; i < num_fds; i++) {
+ close(3+i);
+ }
+ }
+ unsetenv("LISTEN_PID");
+ unsetenv("LISTEN_FDS");
+ unsetenv("LISTEN_FDNAMES");
+ }
return pid;
+ }
argv = get_cmd_line_args (ppid);
if (argv == NULL)
@@ -207,6 +255,12 @@ reexec_in_user_namespace (int ready)
_exit (EXIT_FAILURE);
}
+ if (do_socket_activation) {
+ char s[32];
+ sprintf(s, "%d", getpid());
+ setenv("LISTEN_PID", s, true);
+ }
+
setenv ("_LIBPOD_USERNS_CONFIGURED", "init", 1);
setenv ("_LIBPOD_ROOTLESS_UID", uid, 1);
@@ -232,6 +286,13 @@ reexec_in_user_namespace (int ready)
_exit (EXIT_FAILURE);
}
+ if (chdir (cwd) < 0)
+ {
+ fprintf (stderr, "cannot chdir: %s\n", strerror (errno));
+ _exit (EXIT_FAILURE);
+ }
+ free (cwd);
+
execvp (argv[0], argv);
_exit (EXIT_FAILURE);
diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go
index 344f4afb9..50e07ee74 100644
--- a/pkg/spec/createconfig.go
+++ b/pkg/spec/createconfig.go
@@ -13,6 +13,7 @@ import (
"github.com/containers/libpod/pkg/namespaces"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/storage"
+ "github.com/containers/storage/pkg/stringid"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/docker/go-connections/nat"
spec "github.com/opencontainers/runtime-spec/specs-go"
@@ -134,8 +135,8 @@ type CreateConfig struct {
SeccompProfilePath string //SecurityOpts
SecurityOpts []string
Rootfs string
- LocalVolumes []string //Keeps track of the built-in volumes of container used in the --volumes-from flag
- Syslog bool // Whether to enable syslog on exit commands
+ LocalVolumes []spec.Mount //Keeps track of the built-in volumes of container used in the --volumes-from flag
+ Syslog bool // Whether to enable syslog on exit commands
}
func u32Ptr(i int64) *uint32 { u := uint32(i); return &u }
@@ -216,7 +217,7 @@ func (c *CreateConfig) initFSMounts() []spec.Mount {
//GetVolumeMounts takes user provided input for bind mounts and creates Mount structs
func (c *CreateConfig) GetVolumeMounts(specMounts []spec.Mount) ([]spec.Mount, error) {
- var m []spec.Mount
+ m := c.LocalVolumes
for _, i := range c.Volumes {
var options []string
spliti := strings.Split(i, ":")
@@ -234,22 +235,31 @@ func (c *CreateConfig) GetVolumeMounts(specMounts []spec.Mount) ([]spec.Mount, e
logrus.Debugf("User mount %s:%s options %v", spliti[0], spliti[1], options)
}
- // volumes from image config
- if c.ImageVolumeType != "tmpfs" {
+ if c.ImageVolumeType == "ignore" {
return m, nil
}
+
for vol := range c.BuiltinImgVolumes {
if libpod.MountExists(specMounts, vol) {
continue
}
+
mount := spec.Mount{
Destination: vol,
- Type: string(TypeTmpfs),
- Source: string(TypeTmpfs),
- Options: []string{"rprivate", "rw", "noexec", "nosuid", "nodev", "tmpcopyup"},
+ Type: c.ImageVolumeType,
+ Options: []string{"rprivate", "rw", "nodev"},
+ }
+ if c.ImageVolumeType == "tmpfs" {
+ mount.Source = "tmpfs"
+ mount.Options = append(mount.Options, "tmpcopyup")
+ } else {
+ // This will cause a new local Volume to be created on your system
+ mount.Source = stringid.GenerateNonCryptoID()
+ mount.Options = append(mount.Options, "bind")
}
m = append(m, mount)
}
+
return m, nil
}
@@ -257,6 +267,11 @@ func (c *CreateConfig) GetVolumeMounts(specMounts []spec.Mount) ([]spec.Mount, e
// and adds it to c.Volumes of the current container.
func (c *CreateConfig) GetVolumesFrom() error {
var options string
+
+ if rootless.SkipStorageSetup() {
+ return nil
+ }
+
for _, vol := range c.VolumesFrom {
splitVol := strings.SplitN(vol, ":", 2)
if len(splitVol) == 2 {
@@ -266,6 +281,10 @@ func (c *CreateConfig) GetVolumesFrom() error {
if err != nil {
return errors.Wrapf(err, "error looking up container %q", splitVol[0])
}
+ inspect, err := ctr.Inspect(false)
+ if err != nil {
+ return errors.Wrapf(err, "error inspecting %q", splitVol[0])
+ }
var createArtifact CreateConfig
artifact, err := ctr.GetArtifact("create-config")
if err != nil {
@@ -274,9 +293,13 @@ func (c *CreateConfig) GetVolumesFrom() error {
if err := json.Unmarshal(artifact, &createArtifact); err != nil {
return err
}
-
for key := range createArtifact.BuiltinImgVolumes {
- c.LocalVolumes = append(c.LocalVolumes, key)
+ for _, m := range inspect.Mounts {
+ if m.Destination == key {
+ c.LocalVolumes = append(c.LocalVolumes, m)
+ break
+ }
+ }
}
for _, i := range createArtifact.Volumes {
@@ -331,13 +354,22 @@ func (c *CreateConfig) createExitCommand() []string {
"--cgroup-manager", config.CgroupManager,
"--tmpdir", config.TmpDir,
}
+ if config.OCIRuntime != "" {
+ command = append(command, []string{"--runtime", config.OCIRuntime}...)
+ }
if config.StorageConfig.GraphDriverName != "" {
command = append(command, []string{"--storage-driver", config.StorageConfig.GraphDriverName}...)
}
if c.Syslog {
command = append(command, "--syslog")
}
- return append(command, []string{"container", "cleanup"}...)
+ command = append(command, []string{"container", "cleanup"}...)
+
+ if c.Rm {
+ command = append(command, "--rm")
+ }
+
+ return command
}
// GetContainerCreateOptions takes a CreateConfig and returns a slice of CtrCreateOptions
@@ -414,7 +446,15 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime, pod *l
}
if IsNS(string(c.NetMode)) {
- // pass
+ split := strings.SplitN(string(c.NetMode), ":", 2)
+ if len(split[0]) != 2 {
+ return nil, errors.Errorf("invalid user defined network namespace %q", c.NetMode.UserDefined())
+ }
+ _, err := os.Stat(split[1])
+ if err != nil {
+ return nil, err
+ }
+ options = append(options, libpod.WithNetNS(portBindings, false, string(c.NetMode), networks))
} else if c.NetMode.IsContainer() {
connectedCtr, err := c.Runtime.LookupContainer(c.NetMode.Container())
if err != nil {
@@ -515,11 +555,9 @@ func (c *CreateConfig) GetContainerCreateOptions(runtime *libpod.Runtime, pod *l
if c.CgroupParent != "" {
options = append(options, libpod.WithCgroupParent(c.CgroupParent))
}
- // For a rootless container always cleanup the storage/network as they
- // run in a different namespace thus not reusable when we restart.
- if c.Detach || rootless.IsRootless() {
- options = append(options, libpod.WithExitCommand(c.createExitCommand()))
- }
+
+ // Always use a cleanup process to clean up Podman after termination
+ options = append(options, libpod.WithExitCommand(c.createExitCommand()))
return options, nil
}
diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go
index 76b8963ff..28a636fa6 100644
--- a/pkg/spec/spec.go
+++ b/pkg/spec/spec.go
@@ -3,10 +3,12 @@ package createconfig
import (
"os"
"path"
+ "path/filepath"
"strings"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/storage/pkg/mount"
+ pmount "github.com/containers/storage/pkg/mount"
"github.com/docker/docker/daemon/caps"
"github.com/docker/go-units"
"github.com/opencontainers/runc/libcontainer/user"
@@ -392,9 +394,65 @@ func CreateConfigToOCISpec(config *CreateConfig) (*spec.Spec, error) { //nolint
configSpec.Linux.Resources = &spec.LinuxResources{}
}
+ // Make sure that the bind mounts keep options like nosuid, noexec, nodev.
+ mounts, err := pmount.GetMounts()
+ if err != nil {
+ return nil, err
+ }
+ for i := range configSpec.Mounts {
+ m := &configSpec.Mounts[i]
+ isBind := false
+ for _, o := range m.Options {
+ if o == "bind" || o == "rbind" {
+ isBind = true
+ break
+ }
+ }
+ if !isBind {
+ continue
+ }
+ mount, err := findMount(m.Source, mounts)
+ if err != nil {
+ return nil, err
+ }
+ if mount == nil {
+ continue
+ }
+ next_option:
+ for _, o := range strings.Split(mount.Opts, ",") {
+ if o == "nosuid" || o == "noexec" || o == "nodev" {
+ for _, e := range m.Options {
+ if e == o {
+ continue next_option
+ }
+ }
+ m.Options = append(m.Options, o)
+ }
+ }
+ }
+
return configSpec, nil
}
+func findMount(target string, mounts []*pmount.Info) (*pmount.Info, error) {
+ var err error
+ target, err = filepath.Abs(target)
+ if err != nil {
+ return nil, errors.Wrapf(err, "cannot resolve %s", target)
+ }
+ var bestSoFar *pmount.Info
+ for _, i := range mounts {
+ if bestSoFar != nil && len(bestSoFar.Mountpoint) > len(i.Mountpoint) {
+ // Won't be better than what we have already found
+ continue
+ }
+ if strings.HasPrefix(target, i.Mountpoint) {
+ bestSoFar = i
+ }
+ }
+ return bestSoFar, nil
+}
+
func blockAccessToKernelFilesystems(config *CreateConfig, g *generate.Generator) {
if config.PidMode.IsHost() && rootless.IsRootless() {
return
diff --git a/pkg/tracing/tracing.go b/pkg/tracing/tracing.go
new file mode 100644
index 000000000..cae76dee8
--- /dev/null
+++ b/pkg/tracing/tracing.go
@@ -0,0 +1,28 @@
+package tracing
+
+import (
+ "fmt"
+ "io"
+
+ opentracing "github.com/opentracing/opentracing-go"
+ jaeger "github.com/uber/jaeger-client-go"
+ config "github.com/uber/jaeger-client-go/config"
+)
+
+// Init returns an instance of Jaeger Tracer that samples 100% of traces and logs all spans to stdout.
+func Init(service string) (opentracing.Tracer, io.Closer) {
+ cfg := &config.Configuration{
+ Sampler: &config.SamplerConfig{
+ Type: "const",
+ Param: 1,
+ },
+ Reporter: &config.ReporterConfig{
+ LogSpans: true,
+ },
+ }
+ tracer, closer, err := cfg.New(service, config.Logger(jaeger.StdLogger))
+ if err != nil {
+ panic(fmt.Sprintf("ERROR: cannot init Jaeger: %v\n", err))
+ }
+ return tracer, closer
+}
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index 52f431881..db8a3d5bb 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -259,8 +259,8 @@ func GetRootlessStorageOpts() (storage.StoreOptions, error) {
return opts, nil
}
-// GetRootlessVolumeInfo returns where all the name volumes will be created in rootless mode
-func GetRootlessVolumeInfo() (string, error) {
+// GetRootlessVolumePath returns where all the name volumes will be created in rootless mode
+func GetRootlessVolumePath() (string, error) {
dataDir, _, err := GetRootlessDirInfo()
if err != nil {
return "", err
@@ -307,15 +307,13 @@ func GetDefaultStoreOptions() (storage.StoreOptions, string, error) {
err error
)
storageOpts := storage.DefaultStoreOptions
- volumePath := "/var/lib/containers/storage"
-
+ volumePath := filepath.Join(storageOpts.GraphRoot, "volumes")
if rootless.IsRootless() {
storageOpts, err = GetRootlessStorageOpts()
if err != nil {
return storageOpts, volumePath, err
}
-
- volumePath, err = GetRootlessVolumeInfo()
+ volumePath, err = GetRootlessVolumePath()
if err != nil {
return storageOpts, volumePath, err
}
diff --git a/pkg/varlinkapi/config.go b/pkg/varlinkapi/config.go
index 8dd217b77..f557d04e5 100644
--- a/pkg/varlinkapi/config.go
+++ b/pkg/varlinkapi/config.go
@@ -1,20 +1,21 @@
package varlinkapi
import (
+ "github.com/containers/libpod/cmd/podman/cliconfig"
iopodman "github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
- "github.com/urfave/cli"
+ "github.com/spf13/cobra"
)
// LibpodAPI is the basic varlink struct for libpod
type LibpodAPI struct {
- Cli *cli.Context
+ Cli *cobra.Command
iopodman.VarlinkInterface
Runtime *libpod.Runtime
}
// New creates a new varlink client
-func New(cli *cli.Context, runtime *libpod.Runtime) *iopodman.VarlinkInterface {
- lp := LibpodAPI{Cli: cli, Runtime: runtime}
+func New(cli *cliconfig.PodmanCommand, runtime *libpod.Runtime) *iopodman.VarlinkInterface {
+ lp := LibpodAPI{Cli: cli.Command, Runtime: runtime}
return iopodman.VarlinkNew(&lp)
}
diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go
index 737e2dd96..ad9f107a7 100644
--- a/pkg/varlinkapi/containers.go
+++ b/pkg/varlinkapi/containers.go
@@ -21,7 +21,7 @@ import (
// ListContainers ...
func (i *LibpodAPI) ListContainers(call iopodman.VarlinkCall) error {
var (
- listContainers []iopodman.ListContainerData
+ listContainers []iopodman.Container
)
containers, err := i.Runtime.GetAllContainers()
@@ -44,10 +44,10 @@ func (i *LibpodAPI) ListContainers(call iopodman.VarlinkCall) error {
}
// GetContainer ...
-func (i *LibpodAPI) GetContainer(call iopodman.VarlinkCall, name string) error {
- ctr, err := i.Runtime.LookupContainer(name)
+func (i *LibpodAPI) GetContainer(call iopodman.VarlinkCall, id string) error {
+ ctr, err := i.Runtime.LookupContainer(id)
if err != nil {
- return call.ReplyContainerNotFound(name)
+ return call.ReplyContainerNotFound(id, err.Error())
}
opts := shared.PsOptions{
Namespace: true,
@@ -64,7 +64,7 @@ func (i *LibpodAPI) GetContainer(call iopodman.VarlinkCall, name string) error {
func (i *LibpodAPI) InspectContainer(call iopodman.VarlinkCall, name string) error {
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyContainerNotFound(name)
+ return call.ReplyContainerNotFound(name, err.Error())
}
inspectInfo, err := ctr.Inspect(true)
if err != nil {
@@ -90,7 +90,7 @@ func (i *LibpodAPI) InspectContainer(call iopodman.VarlinkCall, name string) err
func (i *LibpodAPI) ListContainerProcesses(call iopodman.VarlinkCall, name string, opts []string) error {
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyContainerNotFound(name)
+ return call.ReplyContainerNotFound(name, err.Error())
}
containerState, err := ctr.State()
if err != nil {
@@ -118,7 +118,7 @@ func (i *LibpodAPI) GetContainerLogs(call iopodman.VarlinkCall, name string) err
var logs []string
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyContainerNotFound(name)
+ return call.ReplyContainerNotFound(name, err.Error())
}
logPath := ctr.LogPath()
@@ -198,7 +198,7 @@ func (i *LibpodAPI) ListContainerChanges(call iopodman.VarlinkCall, name string)
func (i *LibpodAPI) ExportContainer(call iopodman.VarlinkCall, name, outPath string) error {
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyContainerNotFound(name)
+ return call.ReplyContainerNotFound(name, err.Error())
}
outputFile, err := ioutil.TempFile("", "varlink_recv")
if err != nil {
@@ -220,7 +220,7 @@ func (i *LibpodAPI) ExportContainer(call iopodman.VarlinkCall, name, outPath str
func (i *LibpodAPI) GetContainerStats(call iopodman.VarlinkCall, name string) error {
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyContainerNotFound(name)
+ return call.ReplyContainerNotFound(name, err.Error())
}
containerStats, err := ctr.GetContainerStats(&libpod.ContainerStats{})
if err != nil {
@@ -247,16 +247,11 @@ func (i *LibpodAPI) GetContainerStats(call iopodman.VarlinkCall, name string) er
return call.ReplyGetContainerStats(cs)
}
-// ResizeContainerTty ...
-func (i *LibpodAPI) ResizeContainerTty(call iopodman.VarlinkCall) error {
- return call.ReplyMethodNotImplemented("ResizeContainerTty")
-}
-
// StartContainer ...
func (i *LibpodAPI) StartContainer(call iopodman.VarlinkCall, name string) error {
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyContainerNotFound(name)
+ return call.ReplyContainerNotFound(name, err.Error())
}
state, err := ctr.State()
if err != nil {
@@ -265,7 +260,7 @@ func (i *LibpodAPI) StartContainer(call iopodman.VarlinkCall, name string) error
if state == libpod.ContainerStateRunning || state == libpod.ContainerStatePaused {
return call.ReplyErrorOccurred("container is already running or paused")
}
- if err := ctr.Start(getContext()); err != nil {
+ if err := ctr.Start(getContext(), false); err != nil {
return call.ReplyErrorOccurred(err.Error())
}
return call.ReplyStartContainer(ctr.ID())
@@ -275,7 +270,7 @@ func (i *LibpodAPI) StartContainer(call iopodman.VarlinkCall, name string) error
func (i *LibpodAPI) StopContainer(call iopodman.VarlinkCall, name string, timeout int64) error {
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyContainerNotFound(name)
+ return call.ReplyContainerNotFound(name, err.Error())
}
if err := ctr.StopWithTimeout(uint(timeout)); err != nil && err != libpod.ErrCtrStopped {
return call.ReplyErrorOccurred(err.Error())
@@ -287,7 +282,7 @@ func (i *LibpodAPI) StopContainer(call iopodman.VarlinkCall, name string, timeou
func (i *LibpodAPI) RestartContainer(call iopodman.VarlinkCall, name string, timeout int64) error {
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyContainerNotFound(name)
+ return call.ReplyContainerNotFound(name, err.Error())
}
if err := ctr.RestartWithTimeout(getContext(), uint(timeout)); err != nil {
return call.ReplyErrorOccurred(err.Error())
@@ -316,7 +311,7 @@ func (i *LibpodAPI) KillContainer(call iopodman.VarlinkCall, name string, signal
}
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyContainerNotFound(name)
+ return call.ReplyContainerNotFound(name, err.Error())
}
if err := ctr.Kill(killSignal); err != nil {
return call.ReplyErrorOccurred(err.Error())
@@ -324,21 +319,11 @@ func (i *LibpodAPI) KillContainer(call iopodman.VarlinkCall, name string, signal
return call.ReplyKillContainer(ctr.ID())
}
-// UpdateContainer ...
-func (i *LibpodAPI) UpdateContainer(call iopodman.VarlinkCall) error {
- return call.ReplyMethodNotImplemented("UpdateContainer")
-}
-
-// RenameContainer ...
-func (i *LibpodAPI) RenameContainer(call iopodman.VarlinkCall) error {
- return call.ReplyMethodNotImplemented("RenameContainer")
-}
-
// PauseContainer ...
func (i *LibpodAPI) PauseContainer(call iopodman.VarlinkCall, name string) error {
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyContainerNotFound(name)
+ return call.ReplyContainerNotFound(name, err.Error())
}
if err := ctr.Pause(); err != nil {
return call.ReplyErrorOccurred(err.Error())
@@ -350,7 +335,7 @@ func (i *LibpodAPI) PauseContainer(call iopodman.VarlinkCall, name string) error
func (i *LibpodAPI) UnpauseContainer(call iopodman.VarlinkCall, name string) error {
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyContainerNotFound(name)
+ return call.ReplyContainerNotFound(name, err.Error())
}
if err := ctr.Unpause(); err != nil {
return call.ReplyErrorOccurred(err.Error())
@@ -358,17 +343,11 @@ func (i *LibpodAPI) UnpauseContainer(call iopodman.VarlinkCall, name string) err
return call.ReplyUnpauseContainer(ctr.ID())
}
-// AttachToContainer ...
-// TODO: DO we also want a different one for websocket?
-func (i *LibpodAPI) AttachToContainer(call iopodman.VarlinkCall) error {
- return call.ReplyMethodNotImplemented("AttachToContainer")
-}
-
// WaitContainer ...
func (i *LibpodAPI) WaitContainer(call iopodman.VarlinkCall, name string) error {
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyContainerNotFound(name)
+ return call.ReplyContainerNotFound(name, err.Error())
}
exitCode, err := ctr.Wait()
if err != nil {
@@ -379,13 +358,13 @@ func (i *LibpodAPI) WaitContainer(call iopodman.VarlinkCall, name string) error
}
// RemoveContainer ...
-func (i *LibpodAPI) RemoveContainer(call iopodman.VarlinkCall, name string, force bool) error {
+func (i *LibpodAPI) RemoveContainer(call iopodman.VarlinkCall, name string, force bool, removeVolumes bool) error {
ctx := getContext()
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyContainerNotFound(name)
+ return call.ReplyContainerNotFound(name, err.Error())
}
- if err := i.Runtime.RemoveContainer(ctx, ctr, force); err != nil {
+ if err := i.Runtime.RemoveContainer(ctx, ctr, force, removeVolumes); err != nil {
return call.ReplyErrorOccurred(err.Error())
}
return call.ReplyRemoveContainer(ctr.ID())
@@ -406,7 +385,7 @@ func (i *LibpodAPI) DeleteStoppedContainers(call iopodman.VarlinkCall) error {
return call.ReplyErrorOccurred(err.Error())
}
if state != libpod.ContainerStateRunning {
- if err := i.Runtime.RemoveContainer(ctx, ctr, false); err != nil {
+ if err := i.Runtime.RemoveContainer(ctx, ctr, false, false); err != nil {
return call.ReplyErrorOccurred(err.Error())
}
deletedContainers = append(deletedContainers, ctr.ID())
@@ -419,7 +398,7 @@ func (i *LibpodAPI) DeleteStoppedContainers(call iopodman.VarlinkCall) error {
func (i *LibpodAPI) GetAttachSockets(call iopodman.VarlinkCall, name string) error {
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyContainerNotFound(name)
+ return call.ReplyContainerNotFound(name, err.Error())
}
status, err := ctr.State()
@@ -448,7 +427,7 @@ func (i *LibpodAPI) ContainerCheckpoint(call iopodman.VarlinkCall, name string,
ctx := getContext()
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyContainerNotFound(name)
+ return call.ReplyContainerNotFound(name, err.Error())
}
options := libpod.ContainerCheckpointOptions{
@@ -467,7 +446,7 @@ func (i *LibpodAPI) ContainerRestore(call iopodman.VarlinkCall, name string, kee
ctx := getContext()
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyContainerNotFound(name)
+ return call.ReplyContainerNotFound(name, err.Error())
}
options := libpod.ContainerCheckpointOptions{
@@ -496,7 +475,7 @@ func getArtifact(ctr *libpod.Container) (*cc.CreateConfig, error) {
func (i *LibpodAPI) ContainerConfig(call iopodman.VarlinkCall, name string) error {
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyErrorOccurred(err.Error())
+ return call.ReplyContainerNotFound(name, err.Error())
}
config := ctr.Config()
b, err := json.Marshal(config)
@@ -510,7 +489,7 @@ func (i *LibpodAPI) ContainerConfig(call iopodman.VarlinkCall, name string) erro
func (i *LibpodAPI) ContainerArtifacts(call iopodman.VarlinkCall, name, artifactName string) error {
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyErrorOccurred(err.Error())
+ return call.ReplyContainerNotFound(name, err.Error())
}
artifacts, err := ctr.GetArtifact(artifactName)
if err != nil {
@@ -527,7 +506,7 @@ func (i *LibpodAPI) ContainerArtifacts(call iopodman.VarlinkCall, name, artifact
func (i *LibpodAPI) ContainerInspectData(call iopodman.VarlinkCall, name string) error {
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyErrorOccurred(err.Error())
+ return call.ReplyContainerNotFound(name, err.Error())
}
data, err := ctr.Inspect(true)
if err != nil {
@@ -545,7 +524,7 @@ func (i *LibpodAPI) ContainerInspectData(call iopodman.VarlinkCall, name string)
func (i *LibpodAPI) ContainerStateData(call iopodman.VarlinkCall, name string) error {
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyErrorOccurred(err.Error())
+ return call.ReplyContainerNotFound(name, err.Error())
}
data, err := ctr.ContainerState()
if err != nil {
diff --git a/pkg/varlinkapi/containers_create.go b/pkg/varlinkapi/containers_create.go
index f1835a189..6b53b22c6 100644
--- a/pkg/varlinkapi/containers_create.go
+++ b/pkg/varlinkapi/containers_create.go
@@ -131,9 +131,14 @@ func varlinkCreateToCreateConfig(ctx context.Context, create iopodman.Create, ru
}
imageID := data.ID
+ var ImageVolumes map[string]struct{}
+ if data != nil && create.Image_volume_type != "ignore" {
+ ImageVolumes = data.Config.Volumes
+ }
+
config := &cc.CreateConfig{
Runtime: runtime,
- BuiltinImgVolumes: data.Config.Volumes,
+ BuiltinImgVolumes: ImageVolumes,
ConmonPidFile: create.Conmon_pidfile,
ImageVolumeType: create.Image_volume_type,
CapAdd: create.Cap_add,
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go
index 5e0889645..210f139ce 100644
--- a/pkg/varlinkapi/images.go
+++ b/pkg/varlinkapi/images.go
@@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"io"
+ "io/ioutil"
"os"
"path/filepath"
"strings"
@@ -12,7 +13,6 @@ import (
"github.com/containers/buildah"
"github.com/containers/buildah/imagebuildah"
- "github.com/containers/image/docker"
dockerarchive "github.com/containers/image/docker/archive"
"github.com/containers/image/manifest"
"github.com/containers/image/transports/alltransports"
@@ -21,13 +21,13 @@ import (
"github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
- sysreg "github.com/containers/libpod/pkg/registries"
"github.com/containers/libpod/pkg/util"
"github.com/containers/libpod/utils"
- "github.com/docker/go-units"
+ "github.com/containers/storage/pkg/archive"
"github.com/opencontainers/image-spec/specs-go/v1"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
// ListImages lists all the images in the store
@@ -37,7 +37,7 @@ func (i *LibpodAPI) ListImages(call iopodman.VarlinkCall) error {
if err != nil {
return call.ReplyErrorOccurred(fmt.Sprintf("unable to get list of images %q", err))
}
- var imageList []iopodman.ImageInList
+ var imageList []iopodman.Image
for _, image := range images {
labels, _ := image.Labels(getContext())
containers, _ := image.Containers()
@@ -52,12 +52,12 @@ func (i *LibpodAPI) ListImages(call iopodman.VarlinkCall) error {
return call.ReplyErrorOccurred(err.Error())
}
- i := iopodman.ImageInList{
+ i := iopodman.Image{
Id: image.ID(),
ParentId: image.Parent,
RepoTags: image.Names(),
RepoDigests: repoDigests,
- Created: image.Created().String(),
+ Created: image.Created().Format(time.RFC3339),
Size: int64(*size),
VirtualSize: image.VirtualSize,
Containers: int64(len(containers)),
@@ -69,11 +69,11 @@ func (i *LibpodAPI) ListImages(call iopodman.VarlinkCall) error {
return call.ReplyListImages(imageList)
}
-// GetImage returns a single image in the form of a ImageInList
-func (i *LibpodAPI) GetImage(call iopodman.VarlinkCall, name string) error {
- newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
+// GetImage returns a single image in the form of a Image
+func (i *LibpodAPI) GetImage(call iopodman.VarlinkCall, id string) error {
+ newImage, err := i.Runtime.ImageRuntime().NewFromLocal(id)
if err != nil {
- return call.ReplyImageNotFound(err.Error())
+ return call.ReplyImageNotFound(id, err.Error())
}
labels, err := newImage.Labels(getContext())
if err != nil {
@@ -92,12 +92,12 @@ func (i *LibpodAPI) GetImage(call iopodman.VarlinkCall, name string) error {
return err
}
- il := iopodman.ImageInList{
+ il := iopodman.Image{
Id: newImage.ID(),
ParentId: newImage.Parent,
RepoTags: newImage.Names(),
RepoDigests: repoDigests,
- Created: newImage.Created().String(),
+ Created: newImage.Created().Format(time.RFC3339),
Size: int64(*size),
VirtualSize: newImage.VirtualSize,
Containers: int64(len(containers)),
@@ -109,83 +109,46 @@ func (i *LibpodAPI) GetImage(call iopodman.VarlinkCall, name string) error {
// BuildImage ...
func (i *LibpodAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildInfo) error {
var (
- memoryLimit int64
- memorySwap int64
- namespace []buildah.NamespaceOption
- err error
+ namespace []buildah.NamespaceOption
+ err error
)
systemContext := types.SystemContext{}
- dockerfiles := config.Dockerfile
- contextDir := ""
-
- for i := range dockerfiles {
- if strings.HasPrefix(dockerfiles[i], "http://") ||
- strings.HasPrefix(dockerfiles[i], "https://") ||
- strings.HasPrefix(dockerfiles[i], "git://") ||
- strings.HasPrefix(dockerfiles[i], "github.com/") {
- continue
- }
- absFile, err := filepath.Abs(dockerfiles[i])
- if err != nil {
- return errors.Wrapf(err, "error determining path to file %q", dockerfiles[i])
- }
- contextDir = filepath.Dir(absFile)
- dockerfiles[i], err = filepath.Rel(contextDir, absFile)
- if err != nil {
- return errors.Wrapf(err, "error determining path to file %q", dockerfiles[i])
- }
- break
- }
-
- pullPolicy := imagebuildah.PullNever
- if config.Pull {
- pullPolicy = imagebuildah.PullIfMissing
- }
+ contextDir := config.ContextDir
- if config.Pull_always {
- pullPolicy = imagebuildah.PullAlways
- }
- manifestType := "oci" //nolint
- if config.Image_format != "" {
- manifestType = config.Image_format
+ newContextDir, err := ioutil.TempDir("", "buildTarball")
+ if err != nil {
+ call.ReplyErrorOccurred("unable to create tempdir")
}
+ logrus.Debugf("created new context dir at %s", newContextDir)
- if strings.HasPrefix(manifestType, "oci") {
- manifestType = buildah.OCIv1ImageManifest
- } else if strings.HasPrefix(manifestType, "docker") {
- manifestType = buildah.Dockerv2ImageManifest
- } else {
- return call.ReplyErrorOccurred(fmt.Sprintf("unrecognized image type %q", manifestType))
+ reader, err := os.Open(contextDir)
+ if err != nil {
+ logrus.Errorf("failed to open the context dir tar file %s", contextDir)
+ return call.ReplyErrorOccurred(fmt.Sprintf("unable to open context dir tar file %s", contextDir))
}
-
- if config.Memory != "" {
- memoryLimit, err = units.RAMInBytes(config.Memory)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
+ defer reader.Close()
+ if err := archive.Untar(reader, newContextDir, &archive.TarOptions{}); err != nil {
+ logrus.Errorf("fail to untar the context dir tarball (%s) to the context dir (%s)", contextDir, newContextDir)
+ return call.ReplyErrorOccurred(fmt.Sprintf("unable to untar context dir %s", contextDir))
}
+ logrus.Debugf("untar of %s successful", contextDir)
- if config.Memory_swap != "" {
- memorySwap, err = units.RAMInBytes(config.Memory_swap)
- if err != nil {
- return call.ReplyErrorOccurred(err.Error())
- }
- }
+ // All output (stdout, stderr) is captured in output as well
+ var output bytes.Buffer
- output := bytes.NewBuffer([]byte{})
commonOpts := &buildah.CommonBuildOptions{
- AddHost: config.Add_hosts,
- CgroupParent: config.Cgroup_parent,
- CPUPeriod: uint64(config.Cpu_period),
- CPUQuota: config.Cpu_quota,
- CPUSetCPUs: config.Cpuset_cpus,
- CPUSetMems: config.Cpuset_mems,
- Memory: memoryLimit,
- MemorySwap: memorySwap,
- ShmSize: config.Shm_size,
- Ulimit: config.Ulimit,
- Volumes: config.Volume,
+ AddHost: config.BuildOptions.AddHosts,
+ CgroupParent: config.BuildOptions.CgroupParent,
+ CPUPeriod: uint64(config.BuildOptions.CpuPeriod),
+ CPUQuota: config.BuildOptions.CpuQuota,
+ CPUSetCPUs: config.BuildOptions.CpusetCpus,
+ CPUSetMems: config.BuildOptions.CpusetMems,
+ Memory: config.BuildOptions.Memory,
+ MemorySwap: config.BuildOptions.MemorySwap,
+ ShmSize: config.BuildOptions.ShmSize,
+ Ulimit: config.BuildOptions.Ulimit,
+ Volumes: config.BuildOptions.Volume,
}
hostNetwork := buildah.NamespaceOption{
@@ -196,37 +159,74 @@ func (i *LibpodAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildI
namespace = append(namespace, hostNetwork)
options := imagebuildah.BuildOptions{
- ContextDirectory: contextDir,
- PullPolicy: pullPolicy,
- Compression: imagebuildah.Gzip,
- Quiet: false,
- //SignaturePolicyPath:
- Args: config.Build_args,
- //Output:
- AdditionalTags: config.Tags,
- //Runtime: runtime.
- //RuntimeArgs: ,
- OutputFormat: manifestType,
- SystemContext: &systemContext,
- CommonBuildOpts: commonOpts,
- Squash: config.Squash,
- Labels: config.Label,
- Annotations: config.Annotations,
- ReportWriter: output,
- NamespaceOptions: namespace,
+ CommonBuildOpts: commonOpts,
+ AdditionalTags: config.AdditionalTags,
+ Annotations: config.Annotations,
+ Args: config.BuildArgs,
+ CNIConfigDir: config.CniConfigDir,
+ CNIPluginPath: config.CniPluginDir,
+ Compression: stringCompressionToArchiveType(config.Compression),
+ ContextDirectory: newContextDir,
+ DefaultMountsFilePath: config.DefaultsMountFilePath,
+ Err: &output,
+ ForceRmIntermediateCtrs: config.ForceRmIntermediateCtrs,
+ IIDFile: config.Iidfile,
+ Labels: config.Label,
+ Layers: config.Layers,
+ NoCache: config.Nocache,
+ Out: &output,
+ Output: config.Output,
+ NamespaceOptions: namespace,
+ OutputFormat: config.OutputFormat,
+ PullPolicy: stringPullPolicyToType(config.PullPolicy),
+ Quiet: config.Quiet,
+ RemoveIntermediateCtrs: config.RemoteIntermediateCtrs,
+ ReportWriter: &output,
+ RuntimeArgs: config.RuntimeArgs,
+ SignaturePolicyPath: config.SignaturePolicyPath,
+ Squash: config.Squash,
+ SystemContext: &systemContext,
}
if call.WantsMore() {
call.Continues = true
}
- c := build(i.Runtime, options, config.Dockerfile)
+ var newPathDockerFiles []string
+
+ for _, d := range config.Dockerfiles {
+ if strings.HasPrefix(d, "http://") ||
+ strings.HasPrefix(d, "https://") ||
+ strings.HasPrefix(d, "git://") ||
+ strings.HasPrefix(d, "github.com/") {
+ newPathDockerFiles = append(newPathDockerFiles, d)
+ continue
+ }
+ base := filepath.Base(d)
+ newPathDockerFiles = append(newPathDockerFiles, filepath.Join(newContextDir, base))
+ }
+
+ c := make(chan error)
+ go func() {
+ err := i.Runtime.Build(getContext(), options, newPathDockerFiles...)
+ c <- err
+ close(c)
+ }()
+
var log []string
done := false
for {
- line, err := output.ReadString('\n')
+ outputLine, err := output.ReadString('\n')
if err == nil {
- log = append(log, line)
+ log = append(log, outputLine)
+ if call.WantsMore() {
+ // we want to reply with what we have
+ br := iopodman.MoreResponse{
+ Logs: log,
+ }
+ call.ReplyBuildImage(br)
+ log = []string{}
+ }
continue
} else if err == io.EOF {
select {
@@ -236,15 +236,10 @@ func (i *LibpodAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildI
}
done = true
default:
- if !call.WantsMore() {
+ if call.WantsMore() {
time.Sleep(1 * time.Second)
break
}
- br := iopodman.BuildResponse{
- Logs: log,
- }
- call.ReplyBuildImage(br)
- log = []string{}
}
} else {
return call.ReplyErrorOccurred(err.Error())
@@ -254,40 +249,24 @@ func (i *LibpodAPI) BuildImage(call iopodman.VarlinkCall, config iopodman.BuildI
}
}
call.Continues = false
- newImage, err := i.Runtime.ImageRuntime().NewFromLocal(config.Tags[0])
+
+ newImage, err := i.Runtime.ImageRuntime().NewFromLocal(config.Output)
if err != nil {
return call.ReplyErrorOccurred(err.Error())
}
- br := iopodman.BuildResponse{
+ br := iopodman.MoreResponse{
Logs: log,
Id: newImage.ID(),
}
return call.ReplyBuildImage(br)
}
-func build(runtime *libpod.Runtime, options imagebuildah.BuildOptions, dockerfiles []string) chan error {
- c := make(chan error)
- go func() {
- err := runtime.Build(getContext(), options, dockerfiles...)
- c <- err
- close(c)
- }()
-
- return c
-}
-
-// CreateImage ...
-// TODO With Pull being added, should we skip Create?
-func (i *LibpodAPI) CreateImage(call iopodman.VarlinkCall) error {
- return call.ReplyMethodNotImplemented("CreateImage")
-}
-
// InspectImage returns an image's inspect information as a string that can be serialized.
// Requires an image ID or name
func (i *LibpodAPI) InspectImage(call iopodman.VarlinkCall, name string) error {
newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
if err != nil {
- return call.ReplyImageNotFound(name)
+ return call.ReplyImageNotFound(name, err.Error())
}
inspectInfo, err := newImage.Inspect(getContext())
if err != nil {
@@ -305,7 +284,7 @@ func (i *LibpodAPI) InspectImage(call iopodman.VarlinkCall, name string) error {
func (i *LibpodAPI) HistoryImage(call iopodman.VarlinkCall, name string) error {
newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
if err != nil {
- return call.ReplyImageNotFound(name)
+ return call.ReplyImageNotFound(name, err.Error())
}
history, err := newImage.History(getContext())
if err != nil {
@@ -315,7 +294,7 @@ func (i *LibpodAPI) HistoryImage(call iopodman.VarlinkCall, name string) error {
for _, hist := range history {
imageHistory := iopodman.ImageHistory{
Id: hist.ID,
- Created: hist.Created.String(),
+ Created: hist.Created.Format(time.RFC3339),
CreatedBy: hist.CreatedBy,
Tags: newImage.Names(),
Size: hist.Size,
@@ -327,15 +306,14 @@ func (i *LibpodAPI) HistoryImage(call iopodman.VarlinkCall, name string) error {
}
// PushImage pushes an local image to registry
-func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, tlsVerify bool, signaturePolicy, creds, certDir string, compress bool, format string, removeSignatures bool, signBy string) error {
+func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, tlsVerify *bool, signaturePolicy, creds, certDir string, compress bool, format string, removeSignatures bool, signBy string) error {
var (
registryCreds *types.DockerAuthConfig
manifestType string
)
-
newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
if err != nil {
- return call.ReplyImageNotFound(err.Error())
+ return call.ReplyImageNotFound(name, err.Error())
}
destname := name
if tag != "" {
@@ -352,8 +330,8 @@ func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, tlsVe
DockerRegistryCreds: registryCreds,
DockerCertPath: certDir,
}
- if !tlsVerify {
- dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.OptionalBoolTrue
+ if tlsVerify != nil {
+ dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!*tlsVerify)
}
if format != "" {
switch format {
@@ -372,17 +350,66 @@ func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, tlsVe
SignBy: signBy,
}
- if err := newImage.PushImageToHeuristicDestination(getContext(), destname, manifestType, "", signaturePolicy, nil, compress, so, &dockerRegistryOptions, nil); err != nil {
- return call.ReplyErrorOccurred(err.Error())
+ if call.WantsMore() {
+ call.Continues = true
}
- return call.ReplyPushImage(newImage.ID())
+
+ output := bytes.NewBuffer([]byte{})
+ c := make(chan error)
+ go func() {
+ err := newImage.PushImageToHeuristicDestination(getContext(), destname, manifestType, "", signaturePolicy, output, compress, so, &dockerRegistryOptions, nil)
+ c <- err
+ close(c)
+ }()
+
+ // TODO When pull output gets fixed for the remote client, we need to look into how we can turn below
+ // into something re-usable. it is in build too
+ var log []string
+ done := false
+ for {
+ line, err := output.ReadString('\n')
+ if err == nil {
+ log = append(log, line)
+ continue
+ } else if err == io.EOF {
+ select {
+ case err := <-c:
+ if err != nil {
+ logrus.Errorf("reading of output during push failed for %s", newImage.ID())
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ done = true
+ default:
+ if !call.WantsMore() {
+ time.Sleep(1 * time.Second)
+ break
+ }
+ br := iopodman.MoreResponse{
+ Logs: log,
+ }
+ call.ReplyPushImage(br)
+ log = []string{}
+ }
+ } else {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ if done {
+ break
+ }
+ }
+ call.Continues = false
+
+ br := iopodman.MoreResponse{
+ Logs: log,
+ }
+ return call.ReplyPushImage(br)
}
// TagImage accepts an image name and tag as strings and tags an image in the local store.
func (i *LibpodAPI) TagImage(call iopodman.VarlinkCall, name, tag string) error {
newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
if err != nil {
- return call.ReplyImageNotFound(name)
+ return call.ReplyImageNotFound(name, err.Error())
}
if err := newImage.TagImage(tag); err != nil {
return call.ReplyErrorOccurred(err.Error())
@@ -396,7 +423,7 @@ func (i *LibpodAPI) RemoveImage(call iopodman.VarlinkCall, name string, force bo
ctx := getContext()
newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
if err != nil {
- return call.ReplyImageNotFound(name)
+ return call.ReplyImageNotFound(name, err.Error())
}
_, err = i.Runtime.RemoveImage(ctx, newImage, force)
if err != nil {
@@ -405,38 +432,57 @@ func (i *LibpodAPI) RemoveImage(call iopodman.VarlinkCall, name string, force bo
return call.ReplyRemoveImage(newImage.ID())
}
-// SearchImage searches all registries configured in /etc/containers/registries.conf for an image
+// SearchImages searches all registries configured in /etc/containers/registries.conf for an image
// Requires an image name and a search limit as int
-func (i *LibpodAPI) SearchImage(call iopodman.VarlinkCall, name string, limit int64) error {
- sc := image.GetSystemContext("", "", false)
- registries, err := sysreg.GetRegistries()
+func (i *LibpodAPI) SearchImages(call iopodman.VarlinkCall, query string, limit *int64, tlsVerify *bool, filter iopodman.ImageSearchFilter) error {
+ // Transform all arguments to proper types first
+ argLimit := 0
+ argTLSVerify := types.OptionalBoolUndefined
+ argIsOfficial := types.OptionalBoolUndefined
+ argIsAutomated := types.OptionalBoolUndefined
+ if limit != nil {
+ argLimit = int(*limit)
+ }
+ if tlsVerify != nil {
+ argTLSVerify = types.NewOptionalBool(!*tlsVerify)
+ }
+ if filter.Is_official != nil {
+ argIsOfficial = types.NewOptionalBool(*filter.Is_official)
+ }
+ if filter.Is_automated != nil {
+ argIsAutomated = types.NewOptionalBool(*filter.Is_automated)
+ }
+
+ // Transform a SearchFilter the backend can deal with
+ sFilter := image.SearchFilter{
+ IsOfficial: argIsOfficial,
+ IsAutomated: argIsAutomated,
+ Stars: int(filter.Star_count),
+ }
+
+ searchOptions := image.SearchOptions{
+ Limit: argLimit,
+ Filter: sFilter,
+ InsecureSkipTLSVerify: argTLSVerify,
+ }
+ results, err := image.SearchImages(query, searchOptions)
if err != nil {
- return call.ReplyErrorOccurred(fmt.Sprintf("unable to get system registries: %q", err))
+ return call.ReplyErrorOccurred(err.Error())
}
- var imageResults []iopodman.ImageSearch
- for _, reg := range registries {
- results, err := docker.SearchRegistry(getContext(), sc, reg, name, int(limit))
- if err != nil {
- // If we are searching multiple registries, don't make something like an
- // auth error fatal. Unfortunately we cannot differentiate between auth
- // errors and other possibles errors
- if len(registries) > 1 {
- continue
- }
- return call.ReplyErrorOccurred(err.Error())
- }
- for _, result := range results {
- i := iopodman.ImageSearch{
- Description: result.Description,
- Is_official: result.IsOfficial,
- Is_automated: result.IsAutomated,
- Name: result.Name,
- Star_count: int64(result.StarCount),
- }
- imageResults = append(imageResults, i)
+
+ var imageResults []iopodman.ImageSearchResult
+ for _, result := range results {
+ i := iopodman.ImageSearchResult{
+ Registry: result.Index,
+ Description: result.Description,
+ Is_official: result.Official == "[OK]",
+ Is_automated: result.Automated == "[OK]",
+ Name: result.Name,
+ Star_count: int64(result.Stars),
}
+ imageResults = append(imageResults, i)
}
- return call.ReplySearchImage(imageResults)
+ return call.ReplySearchImages(imageResults)
}
// DeleteUnusedImages deletes any images that do not have containers associated with it.
@@ -466,7 +512,7 @@ func (i *LibpodAPI) DeleteUnusedImages(call iopodman.VarlinkCall) error {
func (i *LibpodAPI) Commit(call iopodman.VarlinkCall, name, imageName string, changes []string, author, message string, pause bool, manifestType string) error {
ctr, err := i.Runtime.LookupContainer(name)
if err != nil {
- return call.ReplyContainerNotFound(name)
+ return call.ReplyContainerNotFound(name, err.Error())
}
sc := image.GetSystemContext(i.Runtime.GetConfig().SignaturePolicyPath, "", false)
var mimeType string
@@ -530,7 +576,7 @@ func (i *LibpodAPI) ImportImage(call iopodman.VarlinkCall, source, reference, me
func (i *LibpodAPI) ExportImage(call iopodman.VarlinkCall, name, destination string, compress bool, tags []string) error {
newImage, err := i.Runtime.ImageRuntime().NewFromLocal(name)
if err != nil {
- return call.ReplyImageNotFound(name)
+ return call.ReplyImageNotFound(name, err.Error())
}
additionalTags, err := image.GetAdditionalTags(tags)
@@ -545,7 +591,7 @@ func (i *LibpodAPI) ExportImage(call iopodman.VarlinkCall, name, destination str
}
// PullImage pulls an image from a registry to the image store.
-func (i *LibpodAPI) PullImage(call iopodman.VarlinkCall, name string, certDir, creds, signaturePolicy string, tlsVerify bool) error {
+func (i *LibpodAPI) PullImage(call iopodman.VarlinkCall, name string, certDir, creds, signaturePolicy string, tlsVerify *bool) error {
var (
registryCreds *types.DockerAuthConfig
imageID string
@@ -562,30 +608,80 @@ func (i *LibpodAPI) PullImage(call iopodman.VarlinkCall, name string, certDir, c
DockerRegistryCreds: registryCreds,
DockerCertPath: certDir,
}
- if tlsVerify {
- dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!tlsVerify)
+ if tlsVerify != nil {
+ dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!*tlsVerify)
}
so := image.SigningOptions{}
- if strings.HasPrefix(name, dockerarchive.Transport.Name()+":") {
- srcRef, err := alltransports.ParseImageName(name)
- if err != nil {
- return errors.Wrapf(err, "error parsing %q", name)
+ if call.WantsMore() {
+ call.Continues = true
+ }
+ output := bytes.NewBuffer([]byte{})
+ c := make(chan error)
+ go func() {
+ //err := newImage.PushImageToHeuristicDestination(getContext(), destname, manifestType, "", signaturePolicy, output, compress, so, &dockerRegistryOptions, nil)
+ if strings.HasPrefix(name, dockerarchive.Transport.Name()+":") {
+ srcRef, err := alltransports.ParseImageName(name)
+ if err != nil {
+ c <- errors.Wrapf(err, "error parsing %q", name)
+ }
+ newImage, err := i.Runtime.ImageRuntime().LoadFromArchiveReference(getContext(), srcRef, signaturePolicy, output)
+ if err != nil {
+ c <- errors.Wrapf(err, "error pulling image from %q", name)
+ }
+ imageID = newImage[0].ID()
+ } else {
+ newImage, err := i.Runtime.ImageRuntime().New(getContext(), name, signaturePolicy, "", output, &dockerRegistryOptions, so, false, nil)
+ if err != nil {
+ c <- errors.Wrapf(err, "unable to pull %s", name)
+ }
+ imageID = newImage.ID()
}
- newImage, err := i.Runtime.ImageRuntime().LoadFromArchiveReference(getContext(), srcRef, signaturePolicy, nil)
- if err != nil {
- return errors.Wrapf(err, "error pulling image from %q", name)
+ c <- nil
+ close(c)
+ }()
+
+ var log []string
+ done := false
+ for {
+ line, err := output.ReadString('\n')
+ if err == nil {
+ log = append(log, line)
+ continue
+ } else if err == io.EOF {
+ select {
+ case err := <-c:
+ if err != nil {
+ logrus.Errorf("reading of output during pull failed for %s", name)
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ done = true
+ default:
+ if !call.WantsMore() {
+ time.Sleep(1 * time.Second)
+ break
+ }
+ br := iopodman.MoreResponse{
+ Logs: log,
+ }
+ call.ReplyPullImage(br)
+ log = []string{}
+ }
+ } else {
+ return call.ReplyErrorOccurred(err.Error())
}
- imageID = newImage[0].ID()
- } else {
- newImage, err := i.Runtime.ImageRuntime().New(getContext(), name, signaturePolicy, "", nil, &dockerRegistryOptions, so, false, nil)
- if err != nil {
- return call.ReplyErrorOccurred(fmt.Sprintf("unable to pull %s: %s", name, err.Error()))
+ if done {
+ break
}
- imageID = newImage.ID()
}
- return call.ReplyPullImage(imageID)
+ call.Continues = false
+
+ br := iopodman.MoreResponse{
+ Logs: log,
+ Id: imageID,
+ }
+ return call.ReplyPullImage(br)
}
// ImageExists returns bool as to whether the input image exists in local storage
@@ -606,8 +702,8 @@ func (i *LibpodAPI) ContainerRunlabel(call iopodman.VarlinkCall, input iopodman.
dockerRegistryOptions := image.DockerRegistryOptions{
DockerCertPath: input.CertDir,
}
- if !input.TlsVerify {
- dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.OptionalBoolTrue
+ if input.TlsVerify != nil {
+ dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!*input.TlsVerify)
}
stdErr := os.Stderr
@@ -640,3 +736,172 @@ func (i *LibpodAPI) ImagesPrune(call iopodman.VarlinkCall, all bool) error {
}
return call.ReplyImagesPrune(prunedImages)
}
+
+// ImageSave ....
+func (i *LibpodAPI) ImageSave(call iopodman.VarlinkCall, options iopodman.ImageSaveOptions) error {
+ newImage, err := i.Runtime.ImageRuntime().NewFromLocal(options.Name)
+ if err != nil {
+ if errors.Cause(err) == libpod.ErrNoSuchImage {
+ return call.ReplyImageNotFound(options.Name, err.Error())
+ }
+ return call.ReplyErrorOccurred(err.Error())
+ }
+
+ // Determine if we are dealing with a tarball or dir
+ var output string
+ outputToDir := false
+ if options.Format == "oci-archive" || options.Format == "docker-archive" {
+ tempfile, err := ioutil.TempFile("", "varlink_send")
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ output = tempfile.Name()
+ tempfile.Close()
+ } else {
+ var err error
+ outputToDir = true
+ output, err = ioutil.TempDir("", "varlink_send")
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ }
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ if call.WantsMore() {
+ call.Continues = true
+ }
+
+ saveOutput := bytes.NewBuffer([]byte{})
+ c := make(chan error)
+ go func() {
+ err := newImage.Save(getContext(), options.Name, options.Format, output, options.MoreTags, options.Quiet, options.Compress)
+ c <- err
+ close(c)
+ }()
+ var log []string
+ done := false
+ for {
+ line, err := saveOutput.ReadString('\n')
+ if err == nil {
+ log = append(log, line)
+ continue
+ } else if err == io.EOF {
+ select {
+ case err := <-c:
+ if err != nil {
+ logrus.Errorf("reading of output during save failed for %s", newImage.ID())
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ done = true
+ default:
+ if !call.WantsMore() {
+ time.Sleep(1 * time.Second)
+ break
+ }
+ br := iopodman.MoreResponse{
+ Logs: log,
+ }
+ call.ReplyImageSave(br)
+ log = []string{}
+ }
+ } else {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ if done {
+ break
+ }
+ }
+ call.Continues = false
+
+ sendfile := output
+ // Image has been saved to `output`
+ if outputToDir {
+ // If the output is a directory, we need to tar up the directory to send it back
+ //Create a tempfile for the directory tarball
+ outputFile, err := ioutil.TempFile("", "varlink_save_dir")
+ if err != nil {
+ return err
+ }
+ defer outputFile.Close()
+ if err := utils.TarToFilesystem(output, outputFile); err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ sendfile = outputFile.Name()
+ }
+ br := iopodman.MoreResponse{
+ Logs: log,
+ Id: sendfile,
+ }
+ return call.ReplyPushImage(br)
+}
+
+// LoadImage ...
+func (i *LibpodAPI) LoadImage(call iopodman.VarlinkCall, name, inputFile string, deleteInputFile, quiet bool) error {
+ var (
+ names string
+ writer io.Writer
+ err error
+ )
+ if !quiet {
+ writer = os.Stderr
+ }
+
+ if call.WantsMore() {
+ call.Continues = true
+ }
+ output := bytes.NewBuffer([]byte{})
+
+ c := make(chan error)
+ go func() {
+ names, err = i.Runtime.LoadImage(getContext(), name, inputFile, writer, "")
+ c <- err
+ close(c)
+ }()
+
+ var log []string
+ done := false
+ for {
+ line, err := output.ReadString('\n')
+ if err == nil {
+ log = append(log, line)
+ continue
+ } else if err == io.EOF {
+ select {
+ case err := <-c:
+ if err != nil {
+ logrus.Error(err)
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ done = true
+ default:
+ if !call.WantsMore() {
+ time.Sleep(1 * time.Second)
+ break
+ }
+ br := iopodman.MoreResponse{
+ Logs: log,
+ }
+ call.ReplyLoadImage(br)
+ log = []string{}
+ }
+ } else {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ if done {
+ break
+ }
+ }
+ call.Continues = false
+
+ br := iopodman.MoreResponse{
+ Logs: log,
+ Id: names,
+ }
+ if deleteInputFile {
+ if err := os.Remove(inputFile); err != nil {
+ logrus.Errorf("unable to delete input file %s", inputFile)
+ }
+ }
+ return call.ReplyLoadImage(br)
+}
diff --git a/pkg/varlinkapi/pods.go b/pkg/varlinkapi/pods.go
index 6e758786a..4ca4c4270 100644
--- a/pkg/varlinkapi/pods.go
+++ b/pkg/varlinkapi/pods.go
@@ -2,6 +2,7 @@ package varlinkapi
import (
"encoding/json"
+ "github.com/containers/libpod/pkg/adapter/shortcuts"
"github.com/containers/libpod/pkg/rootless"
"syscall"
@@ -13,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))
}
@@ -89,7 +86,7 @@ func (i *LibpodAPI) ListPods(call iopodman.VarlinkCall) error {
func (i *LibpodAPI) GetPod(call iopodman.VarlinkCall, name string) error {
pod, err := i.Runtime.LookupPod(name)
if err != nil {
- return call.ReplyPodNotFound(name)
+ return call.ReplyPodNotFound(name, err.Error())
}
opts := shared.PsOptions{}
@@ -105,7 +102,7 @@ func (i *LibpodAPI) GetPod(call iopodman.VarlinkCall, name string) error {
func (i *LibpodAPI) InspectPod(call iopodman.VarlinkCall, name string) error {
pod, err := i.Runtime.LookupPod(name)
if err != nil {
- return call.ReplyPodNotFound(name)
+ return call.ReplyPodNotFound(name, err.Error())
}
inspectData, err := pod.Inspect()
if err != nil {
@@ -122,7 +119,7 @@ func (i *LibpodAPI) InspectPod(call iopodman.VarlinkCall, name string) error {
func (i *LibpodAPI) StartPod(call iopodman.VarlinkCall, name string) error {
pod, err := i.Runtime.LookupPod(name)
if err != nil {
- return call.ReplyPodNotFound(name)
+ return call.ReplyPodNotFound(name, err.Error())
}
ctnrs, err := pod.AllContainers()
if err != nil {
@@ -143,7 +140,7 @@ func (i *LibpodAPI) StartPod(call iopodman.VarlinkCall, name string) error {
func (i *LibpodAPI) StopPod(call iopodman.VarlinkCall, name string, timeout int64) error {
pod, err := i.Runtime.LookupPod(name)
if err != nil {
- return call.ReplyPodNotFound(name)
+ return call.ReplyPodNotFound(name, err.Error())
}
ctrErrs, err := pod.StopWithTimeout(getContext(), true, int(timeout))
callErr := handlePodCall(call, pod, ctrErrs, err)
@@ -157,7 +154,7 @@ func (i *LibpodAPI) StopPod(call iopodman.VarlinkCall, name string, timeout int6
func (i *LibpodAPI) RestartPod(call iopodman.VarlinkCall, name string) error {
pod, err := i.Runtime.LookupPod(name)
if err != nil {
- return call.ReplyPodNotFound(name)
+ return call.ReplyPodNotFound(name, err.Error())
}
ctnrs, err := pod.AllContainers()
if err != nil {
@@ -184,7 +181,7 @@ func (i *LibpodAPI) KillPod(call iopodman.VarlinkCall, name string, signal int64
pod, err := i.Runtime.LookupPod(name)
if err != nil {
- return call.ReplyPodNotFound(name)
+ return call.ReplyPodNotFound(name, err.Error())
}
ctrErrs, err := pod.Kill(killSignal)
callErr := handlePodCall(call, pod, ctrErrs, err)
@@ -198,7 +195,7 @@ func (i *LibpodAPI) KillPod(call iopodman.VarlinkCall, name string, signal int64
func (i *LibpodAPI) PausePod(call iopodman.VarlinkCall, name string) error {
pod, err := i.Runtime.LookupPod(name)
if err != nil {
- return call.ReplyPodNotFound(name)
+ return call.ReplyPodNotFound(name, err.Error())
}
ctrErrs, err := pod.Pause()
callErr := handlePodCall(call, pod, ctrErrs, err)
@@ -212,7 +209,7 @@ func (i *LibpodAPI) PausePod(call iopodman.VarlinkCall, name string) error {
func (i *LibpodAPI) UnpausePod(call iopodman.VarlinkCall, name string) error {
pod, err := i.Runtime.LookupPod(name)
if err != nil {
- return call.ReplyPodNotFound(name)
+ return call.ReplyPodNotFound(name, err.Error())
}
ctrErrs, err := pod.Unpause()
callErr := handlePodCall(call, pod, ctrErrs, err)
@@ -227,7 +224,7 @@ func (i *LibpodAPI) RemovePod(call iopodman.VarlinkCall, name string, force bool
ctx := getContext()
pod, err := i.Runtime.LookupPod(name)
if err != nil {
- return call.ReplyPodNotFound(name)
+ return call.ReplyPodNotFound(name, err.Error())
}
if err = i.Runtime.RemovePod(ctx, pod, force, force); err != nil {
return call.ReplyErrorOccurred(err.Error())
@@ -240,7 +237,7 @@ func (i *LibpodAPI) RemovePod(call iopodman.VarlinkCall, name string, force bool
func (i *LibpodAPI) GetPodStats(call iopodman.VarlinkCall, name string) error {
pod, err := i.Runtime.LookupPod(name)
if err != nil {
- return call.ReplyPodNotFound(name)
+ return call.ReplyPodNotFound(name, err.Error())
}
prevStats := make(map[string]*libpod.ContainerStats)
podStats, err := pod.GetPodStats(prevStats)
@@ -271,3 +268,34 @@ func (i *LibpodAPI) GetPodStats(call iopodman.VarlinkCall, name string) error {
}
return call.ReplyGetPodStats(pod.ID(), containersStats)
}
+
+// GetPodsByContext returns a slice of pod ids based on all, latest, or a list
+func (i *LibpodAPI) GetPodsByContext(call iopodman.VarlinkCall, all, latest bool, input []string) error {
+ var podids []string
+
+ pods, err := shortcuts.GetPodsByContext(all, latest, input, i.Runtime)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ for _, p := range pods {
+ podids = append(podids, p.ID())
+ }
+ return call.ReplyGetPodsByContext(podids)
+}
+
+// PodStateData returns a container's state data in string format
+func (i *LibpodAPI) PodStateData(call iopodman.VarlinkCall, name string) error {
+ pod, err := i.Runtime.LookupPod(name)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ data, err := pod.Inspect()
+ if err != nil {
+ return call.ReplyErrorOccurred("unable to obtain pod state")
+ }
+ b, err := json.Marshal(data)
+ if err != nil {
+ return call.ReplyErrorOccurred("unable to serialize pod inspect data")
+ }
+ return call.ReplyPodStateData(string(b))
+}
diff --git a/pkg/varlinkapi/system.go b/pkg/varlinkapi/system.go
index 376502f21..3f32615ec 100644
--- a/pkg/varlinkapi/system.go
+++ b/pkg/varlinkapi/system.go
@@ -3,6 +3,7 @@ package varlinkapi
import (
goruntime "runtime"
"strings"
+ "time"
"github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
@@ -15,22 +16,14 @@ func (i *LibpodAPI) GetVersion(call iopodman.VarlinkCall) error {
return err
}
- return call.ReplyGetVersion(iopodman.Version{
- Remote_api_version: versionInfo.RemoteAPIVersion,
- Version: versionInfo.Version,
- Go_version: versionInfo.GoVersion,
- Git_commit: versionInfo.GitCommit,
- Built: versionInfo.Built,
- Os_arch: versionInfo.OsArch,
- })
-}
-
-// Ping returns a simple string "OK" response for clients to make sure
-// the service is working.
-func (i *LibpodAPI) Ping(call iopodman.VarlinkCall) error {
- return call.ReplyPing(iopodman.StringResponse{
- Message: "OK",
- })
+ return call.ReplyGetVersion(
+ versionInfo.Version,
+ versionInfo.GoVersion,
+ versionInfo.GitCommit,
+ time.Unix(versionInfo.Built, 0).Format(time.RFC3339),
+ versionInfo.OsArch,
+ versionInfo.RemoteAPIVersion,
+ )
}
// GetInfo returns details about the podman host and its stores
diff --git a/pkg/varlinkapi/transfers.go b/pkg/varlinkapi/transfers.go
index 0cb7e5e2e..9a97bc810 100644
--- a/pkg/varlinkapi/transfers.go
+++ b/pkg/varlinkapi/transfers.go
@@ -8,6 +8,7 @@ import (
"os"
"github.com/containers/libpod/cmd/podman/varlink"
+ "github.com/sirupsen/logrus"
)
// SendFile allows a client to send a file to the varlink server
@@ -34,6 +35,7 @@ func (i *LibpodAPI) SendFile(call iopodman.VarlinkCall, ftype string, length int
return err
}
+ logrus.Debugf("successfully received %s", outputFile.Name())
// Send an ACK to the client
call.Call.Writer.WriteString(fmt.Sprintf("%s:", outputFile.Name()))
call.Call.Writer.Flush()
diff --git a/pkg/varlinkapi/util.go b/pkg/varlinkapi/util.go
index a80c8db41..7e487c03a 100644
--- a/pkg/varlinkapi/util.go
+++ b/pkg/varlinkapi/util.go
@@ -3,11 +3,14 @@ package varlinkapi
import (
"context"
"strconv"
+ "strings"
"time"
+ "github.com/containers/buildah"
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
+ "github.com/containers/storage/pkg/archive"
)
// getContext returns a non-nil, empty context
@@ -15,7 +18,7 @@ func getContext() context.Context {
return context.TODO()
}
-func makeListContainer(containerID string, batchInfo shared.BatchContainerStruct) iopodman.ListContainerData {
+func makeListContainer(containerID string, batchInfo shared.BatchContainerStruct) iopodman.Container {
var (
mounts []iopodman.ContainerMount
ports []iopodman.ContainerPortMappings
@@ -56,12 +59,12 @@ func makeListContainer(containerID string, batchInfo shared.BatchContainerStruct
Ipc: ns.IPC,
}
- lc := iopodman.ListContainerData{
+ lc := iopodman.Container{
Id: containerID,
Image: batchInfo.ConConfig.RootfsImageName,
Imageid: batchInfo.ConConfig.RootfsImageID,
Command: batchInfo.ConConfig.Spec.Process.Args,
- Createdat: batchInfo.ConConfig.CreatedTime.String(),
+ Createdat: batchInfo.ConConfig.CreatedTime.Format(time.RFC3339),
Runningfor: time.Since(batchInfo.ConConfig.CreatedTime).String(),
Status: batchInfo.ConState.String(),
Ports: ports,
@@ -107,7 +110,7 @@ func makeListPod(pod *libpod.Pod, batchInfo shared.PsOptions) (iopodman.ListPodD
listPodsContainers = append(listPodsContainers, makeListPodContainers(ctr.ID(), batchInfo))
}
listPod := iopodman.ListPodData{
- Createdat: pod.CreatedTime().String(),
+ Createdat: pod.CreatedTime().Format(time.RFC3339),
Id: pod.ID(),
Name: pod.Name(),
Status: status,
@@ -133,3 +136,27 @@ func handlePodCall(call iopodman.VarlinkCall, pod *libpod.Pod, ctrErrs map[strin
return nil
}
+
+func stringCompressionToArchiveType(s string) archive.Compression {
+ switch strings.ToUpper(s) {
+ case "BZIP2":
+ return archive.Bzip2
+ case "GZIP":
+ return archive.Gzip
+ case "XZ":
+ return archive.Xz
+ }
+ return archive.Uncompressed
+}
+
+func stringPullPolicyToType(s string) buildah.PullPolicy {
+ switch strings.ToUpper(s) {
+ case "PULLIFMISSING":
+ return buildah.PullIfMissing
+ case "PULLALWAYS":
+ return buildah.PullAlways
+ case "PULLNEVER":
+ return buildah.PullNever
+ }
+ return buildah.PullIfMissing
+}
diff --git a/pkg/varlinkapi/volumes.go b/pkg/varlinkapi/volumes.go
new file mode 100644
index 000000000..02874d2b1
--- /dev/null
+++ b/pkg/varlinkapi/volumes.go
@@ -0,0 +1,90 @@
+package varlinkapi
+
+import (
+ "github.com/containers/libpod/cmd/podman/varlink"
+ "github.com/containers/libpod/libpod"
+)
+
+// VolumeCreate creates a libpod volume based on input from a varlink connection
+func (i *LibpodAPI) VolumeCreate(call iopodman.VarlinkCall, options iopodman.VolumeCreateOpts) error {
+ var volumeOptions []libpod.VolumeCreateOption
+
+ if len(options.VolumeName) > 0 {
+ volumeOptions = append(volumeOptions, libpod.WithVolumeName(options.VolumeName))
+ }
+ if len(options.Driver) > 0 {
+ volumeOptions = append(volumeOptions, libpod.WithVolumeDriver(options.Driver))
+ }
+ if len(options.Labels) > 0 {
+ volumeOptions = append(volumeOptions, libpod.WithVolumeLabels(options.Labels))
+ }
+ if len(options.Options) > 0 {
+ volumeOptions = append(volumeOptions, libpod.WithVolumeOptions(options.Options))
+ }
+ newVolume, err := i.Runtime.NewVolume(getContext(), volumeOptions...)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ return call.ReplyVolumeCreate(newVolume.Name())
+}
+
+// VolumeRemove removes volumes by options.All or options.Volumes
+func (i *LibpodAPI) VolumeRemove(call iopodman.VarlinkCall, options iopodman.VolumeRemoveOpts) error {
+ deletedVolumes, err := i.Runtime.RemoveVolumes(getContext(), options.Volumes, options.All, options.Force)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ return call.ReplyVolumeRemove(deletedVolumes)
+}
+
+// GetVolumes returns all the volumes known to the remote system
+func (i *LibpodAPI) GetVolumes(call iopodman.VarlinkCall, args []string, all bool) error {
+ var (
+ err error
+ reply []*libpod.Volume
+ volumes []iopodman.Volume
+ )
+ if all {
+ reply, err = i.Runtime.GetAllVolumes()
+ } else {
+ for _, v := range args {
+ vol, err := i.Runtime.GetVolume(v)
+ if err != nil {
+ return err
+ }
+ reply = append(reply, vol)
+ }
+ }
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ // Build the iopodman.volume struct for the return
+ for _, v := range reply {
+ newVol := iopodman.Volume{
+ Driver: v.Driver(),
+ Labels: v.Labels(),
+ MountPoint: v.MountPoint(),
+ Name: v.Name(),
+ Options: v.Options(),
+ Scope: v.Scope(),
+ }
+ volumes = append(volumes, newVol)
+ }
+ return call.ReplyGetVolumes(volumes)
+}
+
+// VolumesPrune removes unused images via a varlink call
+func (i *LibpodAPI) VolumesPrune(call iopodman.VarlinkCall) error {
+ var errs []string
+ prunedNames, prunedErrors := i.Runtime.PruneVolumes(getContext())
+ if len(prunedErrors) == 0 {
+ return call.ReplyVolumesPrune(prunedNames, []string{})
+ }
+
+ // We need to take the errors and capture their strings to go back over
+ // varlink
+ for _, e := range prunedErrors {
+ errs = append(errs, e.Error())
+ }
+ return call.ReplyVolumesPrune(prunedNames, errs)
+}