diff options
Diffstat (limited to 'pkg/varlinkapi')
-rw-r--r-- | pkg/varlinkapi/config.go | 9 | ||||
-rw-r--r-- | pkg/varlinkapi/containers.go | 77 | ||||
-rw-r--r-- | pkg/varlinkapi/containers_create.go | 7 | ||||
-rw-r--r-- | pkg/varlinkapi/images.go | 635 | ||||
-rw-r--r-- | pkg/varlinkapi/pods.go | 56 | ||||
-rw-r--r-- | pkg/varlinkapi/system.go | 25 | ||||
-rw-r--r-- | pkg/varlinkapi/transfers.go | 2 | ||||
-rw-r--r-- | pkg/varlinkapi/util.go | 35 | ||||
-rw-r--r-- | pkg/varlinkapi/volumes.go | 90 |
9 files changed, 663 insertions, 273 deletions
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) +} |