summaryrefslogtreecommitdiff
path: root/pkg/domain/infra/abi
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/domain/infra/abi')
-rw-r--r--pkg/domain/infra/abi/containers.go327
-rw-r--r--pkg/domain/infra/abi/images.go166
-rw-r--r--pkg/domain/infra/abi/images_list.go80
-rw-r--r--pkg/domain/infra/abi/images_test.go37
-rw-r--r--pkg/domain/infra/abi/parse/parse.go68
-rw-r--r--pkg/domain/infra/abi/pods.go252
-rw-r--r--pkg/domain/infra/abi/runtime.go17
-rw-r--r--pkg/domain/infra/abi/volumes.go159
8 files changed, 1106 insertions, 0 deletions
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
new file mode 100644
index 000000000..d25af24c5
--- /dev/null
+++ b/pkg/domain/infra/abi/containers.go
@@ -0,0 +1,327 @@
+// +build ABISupport
+
+package abi
+
+import (
+ "context"
+ "io/ioutil"
+ "strings"
+
+ "github.com/containers/buildah"
+ "github.com/containers/image/v5/manifest"
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/pkg/adapter/shortcuts"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/signal"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// TODO: Should return *entities.ContainerExistsReport, error
+func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrId string) (*entities.BoolReport, error) {
+ _, err := ic.Libpod.LookupContainer(nameOrId)
+ if err != nil && errors.Cause(err) != define.ErrNoSuchCtr {
+ return nil, err
+ }
+ return &entities.BoolReport{Value: err == nil}, nil
+}
+
+func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []string, options entities.WaitOptions) ([]entities.WaitReport, error) {
+ var (
+ responses []entities.WaitReport
+ )
+ ctrs, err := shortcuts.GetContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+ for _, c := range ctrs {
+ response := entities.WaitReport{Id: c.ID()}
+ exitCode, err := c.WaitForConditionWithInterval(options.Interval, options.Condition)
+ if err != nil {
+ response.Error = err
+ } else {
+ response.ExitCode = exitCode
+ }
+ responses = append(responses, response)
+ }
+ return responses, nil
+}
+
+func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
+ var (
+ ctrs []*libpod.Container
+ err error
+ report []*entities.PauseUnpauseReport
+ )
+ if options.All {
+ ctrs, err = ic.Libpod.GetAllContainers()
+ } else {
+ ctrs, err = shortcuts.GetContainersByContext(false, false, namesOrIds, ic.Libpod)
+ }
+ if err != nil {
+ return nil, err
+ }
+ for _, c := range ctrs {
+ err := c.Pause()
+ report = append(report, &entities.PauseUnpauseReport{Id: c.ID(), Err: err})
+ }
+ return report, nil
+}
+
+func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
+ var (
+ ctrs []*libpod.Container
+ err error
+ report []*entities.PauseUnpauseReport
+ )
+ if options.All {
+ ctrs, err = ic.Libpod.GetAllContainers()
+ } else {
+ ctrs, err = shortcuts.GetContainersByContext(false, false, namesOrIds, ic.Libpod)
+ }
+ if err != nil {
+ return nil, err
+ }
+ for _, c := range ctrs {
+ err := c.Unpause()
+ report = append(report, &entities.PauseUnpauseReport{Id: c.ID(), Err: err})
+ }
+ return report, nil
+}
+func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, options entities.StopOptions) ([]*entities.StopReport, error) {
+ var (
+ reports []*entities.StopReport
+ )
+ names := namesOrIds
+ for _, cidFile := range options.CIDFiles {
+ content, err := ioutil.ReadFile(cidFile)
+ if err != nil {
+ return nil, errors.Wrap(err, "error reading CIDFile")
+ }
+ id := strings.Split(string(content), "\n")[0]
+ names = append(names, id)
+ }
+ ctrs, err := shortcuts.GetContainersByContext(options.All, options.Latest, names, ic.Libpod)
+ if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
+ return nil, err
+ }
+ for _, con := range ctrs {
+ report := entities.StopReport{Id: con.ID()}
+ err = con.StopWithTimeout(options.Timeout)
+ if err != nil {
+ // These first two are considered non-fatal under the right conditions
+ if errors.Cause(err) == define.ErrCtrStopped {
+ logrus.Debugf("Container %s is already stopped", con.ID())
+ reports = append(reports, &report)
+ continue
+
+ } else if options.All && errors.Cause(err) == define.ErrCtrStateInvalid {
+ logrus.Debugf("Container %s is not running, could not stop", con.ID())
+ reports = append(reports, &report)
+ continue
+ }
+ report.Err = err
+ reports = append(reports, &report)
+ continue
+ }
+ reports = append(reports, &report)
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) {
+ var (
+ reports []*entities.KillReport
+ )
+ sig, err := signal.ParseSignalNameOrNumber(options.Signal)
+ if err != nil {
+ return nil, err
+ }
+ ctrs, err := shortcuts.GetContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+ for _, con := range ctrs {
+ reports = append(reports, &entities.KillReport{
+ Id: con.ID(),
+ Err: con.Kill(uint(sig)),
+ })
+ }
+ return reports, nil
+}
+func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []string, options entities.RestartOptions) ([]*entities.RestartReport, error) {
+ var (
+ reports []*entities.RestartReport
+ )
+ ctrs, err := shortcuts.GetContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+ for _, con := range ctrs {
+ timeout := con.StopTimeout()
+ if options.Timeout != nil {
+ timeout = *options.Timeout
+ }
+ reports = append(reports, &entities.RestartReport{
+ Id: con.ID(),
+ Err: con.RestartWithTimeout(ctx, timeout),
+ })
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, options entities.RmOptions) ([]*entities.RmReport, error) {
+ var (
+ reports []*entities.RmReport
+ )
+ if options.Storage {
+ for _, ctr := range namesOrIds {
+ report := entities.RmReport{Id: ctr}
+ if err := ic.Libpod.RemoveStorageContainer(ctr, options.Force); err != nil {
+ report.Err = err
+ }
+ reports = append(reports, &report)
+ }
+ return reports, nil
+ }
+
+ names := namesOrIds
+ for _, cidFile := range options.CIDFiles {
+ content, err := ioutil.ReadFile(cidFile)
+ if err != nil {
+ return nil, errors.Wrap(err, "error reading CIDFile")
+ }
+ id := strings.Split(string(content), "\n")[0]
+ names = append(names, id)
+ }
+
+ ctrs, err := shortcuts.GetContainersByContext(options.All, options.Latest, names, ic.Libpod)
+ if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
+ // Failed to get containers. If force is specified, get the containers ID
+ // and evict them
+ if !options.Force {
+ return nil, err
+ }
+
+ for _, ctr := range namesOrIds {
+ logrus.Debugf("Evicting container %q", ctr)
+ report := entities.RmReport{Id: ctr}
+ id, err := ic.Libpod.EvictContainer(ctx, ctr, options.Volumes)
+ if err != nil {
+ if options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr {
+ logrus.Debugf("Ignoring error (--allow-missing): %v", err)
+ reports = append(reports, &report)
+ continue
+ }
+ report.Err = errors.Wrapf(err, "Failed to evict container: %q", id)
+ reports = append(reports, &report)
+ continue
+ }
+ reports = append(reports, &report)
+ }
+ return reports, nil
+ }
+
+ for _, c := range ctrs {
+ report := entities.RmReport{Id: c.ID()}
+ err := ic.Libpod.RemoveContainer(ctx, c, options.Force, options.Volumes)
+ if err != nil {
+ if options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr {
+ logrus.Debugf("Ignoring error (--allow-missing): %v", err)
+ reports = append(reports, &report)
+ continue
+ }
+ logrus.Debugf("Failed to remove container %s: %s", c.ID(), err.Error())
+ report.Err = err
+ reports = append(reports, &report)
+ continue
+ }
+ reports = append(reports, &report)
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.ContainerInspectOptions) ([]*entities.ContainerInspectReport, error) {
+ var reports []*entities.ContainerInspectReport
+ ctrs, err := shortcuts.GetContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+ for _, c := range ctrs {
+ data, err := c.Inspect(options.Size)
+ if err != nil {
+ return nil, err
+ }
+ reports = append(reports, &entities.ContainerInspectReport{InspectContainerData: data})
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) ContainerTop(ctx context.Context, options entities.TopOptions) (*entities.StringSliceReport, error) {
+ var (
+ container *libpod.Container
+ err error
+ )
+
+ // Look up the container.
+ if options.Latest {
+ container, err = ic.Libpod.GetLatestContainer()
+ } else {
+ container, err = ic.Libpod.LookupContainer(options.NameOrID)
+ }
+ if err != nil {
+ return nil, errors.Wrap(err, "unable to lookup requested container")
+ }
+
+ // Run Top.
+ report := &entities.StringSliceReport{}
+ report.Value, err = container.Top(options.Descriptors)
+ return report, err
+}
+
+func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrId string, options entities.CommitOptions) (*entities.CommitReport, error) {
+ var (
+ mimeType string
+ )
+ ctr, err := ic.Libpod.LookupContainer(nameOrId)
+ if err != nil {
+ return nil, err
+ }
+ rtc, err := ic.Libpod.GetConfig()
+ if err != nil {
+ return nil, err
+ }
+ switch options.Format {
+ case "oci":
+ mimeType = buildah.OCIv1ImageManifest
+ if len(options.Message) > 0 {
+ return nil, errors.Errorf("messages are only compatible with the docker image format (-f docker)")
+ }
+ case "docker":
+ mimeType = manifest.DockerV2Schema2MediaType
+ default:
+ return nil, errors.Errorf("unrecognized image format %q", options.Format)
+ }
+ sc := image.GetSystemContext(rtc.Engine.SignaturePolicyPath, "", false)
+ coptions := buildah.CommitOptions{
+ SignaturePolicyPath: rtc.Engine.SignaturePolicyPath,
+ ReportWriter: options.Writer,
+ SystemContext: sc,
+ PreferredManifestType: mimeType,
+ }
+ opts := libpod.ContainerCommitOptions{
+ CommitOptions: coptions,
+ Pause: options.Pause,
+ IncludeVolumes: options.IncludeVolumes,
+ Message: options.Message,
+ Changes: options.Changes,
+ Author: options.Author,
+ }
+ newImage, err := ctr.Commit(ctx, options.ImageName, opts)
+ if err != nil {
+ return nil, err
+ }
+ return &entities.CommitReport{Id: newImage.ID()}, nil
+}
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
new file mode 100644
index 000000000..44420c1e1
--- /dev/null
+++ b/pkg/domain/infra/abi/images.go
@@ -0,0 +1,166 @@
+// +build ABISupport
+
+package abi
+
+import (
+ "context"
+ "fmt"
+
+ libpodImage "github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/storage"
+ "github.com/pkg/errors"
+)
+
+func (ir *ImageEngine) Exists(_ context.Context, nameOrId string) (*entities.BoolReport, error) {
+ if _, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrId); err != nil {
+ return &entities.BoolReport{}, nil
+ }
+ return &entities.BoolReport{Value: true}, nil
+}
+
+func (ir *ImageEngine) Delete(ctx context.Context, nameOrId []string, opts entities.ImageDeleteOptions) (*entities.ImageDeleteReport, error) {
+ report := entities.ImageDeleteReport{}
+
+ if opts.All {
+ var previousTargets []*libpodImage.Image
+ repeatRun:
+ targets, err := ir.Libpod.ImageRuntime().GetRWImages()
+ if err != nil {
+ return &report, errors.Wrapf(err, "unable to query local images")
+ }
+
+ if len(targets) > 0 && len(targets) == len(previousTargets) {
+ return &report, errors.New("unable to delete all images; re-run the rmi command again.")
+ }
+ previousTargets = targets
+
+ for _, img := range targets {
+ isParent, err := img.IsParent(ctx)
+ if err != nil {
+ return &report, err
+ }
+ if isParent {
+ continue
+ }
+ err = ir.deleteImage(ctx, img, opts, report)
+ report.Errors = append(report.Errors, err)
+ }
+ if len(previousTargets) != 1 {
+ goto repeatRun
+ }
+ return &report, nil
+ }
+
+ for _, id := range nameOrId {
+ image, err := ir.Libpod.ImageRuntime().NewFromLocal(id)
+ if err != nil {
+ return nil, err
+ }
+
+ err = ir.deleteImage(ctx, image, opts, report)
+ if err != nil {
+ return &report, err
+ }
+ }
+ return &report, nil
+}
+
+func (ir *ImageEngine) deleteImage(ctx context.Context, img *libpodImage.Image, opts entities.ImageDeleteOptions, report entities.ImageDeleteReport) error {
+ results, err := ir.Libpod.RemoveImage(ctx, img, opts.Force)
+ switch errors.Cause(err) {
+ case nil:
+ break
+ case storage.ErrImageUsedByContainer:
+ report.ImageInUse = errors.New(
+ fmt.Sprintf("A container associated with containers/storage, i.e. via Buildah, CRI-O, etc., may be associated with this image: %-12.12s\n", img.ID()))
+ return nil
+ case libpodImage.ErrNoSuchImage:
+ report.ImageNotFound = err
+ return nil
+ default:
+ return err
+ }
+
+ report.Deleted = append(report.Deleted, results.Deleted)
+ report.Untagged = append(report.Untagged, results.Untagged...)
+ return nil
+}
+
+func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) {
+ results, err := ir.Libpod.ImageRuntime().PruneImages(ctx, opts.All, opts.Filter)
+ if err != nil {
+ return nil, err
+ }
+
+ report := entities.ImagePruneReport{
+ Report: entities.Report{
+ Id: results,
+ Err: nil,
+ },
+ Size: 0,
+ }
+ return &report, nil
+}
+
+func (ir *ImageEngine) History(ctx context.Context, nameOrId string, opts entities.ImageHistoryOptions) (*entities.ImageHistoryReport, error) {
+ image, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrId)
+ if err != nil {
+ return nil, err
+ }
+ results, err := image.History(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ history := entities.ImageHistoryReport{
+ Layers: make([]entities.ImageHistoryLayer, len(results)),
+ }
+
+ for i, layer := range results {
+ history.Layers[i] = ToDomainHistoryLayer(layer)
+ }
+ return &history, nil
+}
+
+func ToDomainHistoryLayer(layer *libpodImage.History) entities.ImageHistoryLayer {
+ l := entities.ImageHistoryLayer{}
+ l.ID = layer.ID
+ l.Created = layer.Created.Unix()
+ l.CreatedBy = layer.CreatedBy
+ copy(l.Tags, layer.Tags)
+ l.Size = layer.Size
+ l.Comment = layer.Comment
+ return l
+}
+
+// func (r *imageRuntime) Delete(ctx context.Context, nameOrId string, opts entities.ImageDeleteOptions) (*entities.ImageDeleteReport, error) {
+// image, err := r.libpod.ImageEngine().NewFromLocal(nameOrId)
+// if err != nil {
+// return nil, err
+// }
+//
+// results, err := r.libpod.RemoveImage(ctx, image, opts.Force)
+// if err != nil {
+// return nil, err
+// }
+//
+// report := entities.ImageDeleteReport{}
+// if err := utils.DeepCopy(&report, results); err != nil {
+// return nil, err
+// }
+// return &report, nil
+// }
+//
+// func (r *imageRuntime) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) {
+// // TODO: map FilterOptions
+// id, err := r.libpod.ImageEngine().PruneImages(ctx, opts.All, []string{})
+// if err != nil {
+// return nil, err
+// }
+//
+// // TODO: Determine Size
+// report := entities.ImagePruneReport{}
+// copy(report.Report.Id, id)
+// return &report, nil
+// }
diff --git a/pkg/domain/infra/abi/images_list.go b/pkg/domain/infra/abi/images_list.go
new file mode 100644
index 000000000..2f4020374
--- /dev/null
+++ b/pkg/domain/infra/abi/images_list.go
@@ -0,0 +1,80 @@
+// +build ABISupport
+
+package abi
+
+import (
+ "context"
+
+ libpodImage "github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/pkg/domain/entities"
+)
+
+func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) ([]*entities.ImageSummary, error) {
+ var (
+ images []*libpodImage.Image
+ err error
+ )
+
+ // TODO: Future work support for domain.Filters
+ // filters := utils.ToLibpodFilters(opts.Filters)
+
+ if len(opts.Filter) > 0 {
+ images, err = ir.Libpod.ImageRuntime().GetImagesWithFilters(opts.Filter)
+ } else {
+ images, err = ir.Libpod.ImageRuntime().GetImages()
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ summaries := make([]*entities.ImageSummary, len(images))
+ for i, img := range images {
+ var repoTags []string
+ if opts.All {
+ pairs, err := libpodImage.ReposToMap(img.Names())
+ if err != nil {
+ return nil, err
+ }
+
+ for repo, tags := range pairs {
+ for _, tag := range tags {
+ repoTags = append(repoTags, repo+":"+tag)
+ }
+ }
+ } else {
+ repoTags, _ = img.RepoTags()
+ }
+
+ digests := make([]string, len(img.Digests()))
+ for j, d := range img.Digests() {
+ digests[j] = string(d)
+ }
+
+ e := entities.ImageSummary{
+ ID: img.ID(),
+
+ ConfigDigest: string(img.ConfigDigest),
+ Created: img.Created().Unix(),
+ Dangling: img.Dangling(),
+ Digest: string(img.Digest()),
+ Digests: digests,
+ History: img.NamesHistory(),
+ Names: img.Names(),
+ ParentId: img.Parent,
+ ReadOnly: img.IsReadOnly(),
+ SharedSize: 0,
+ VirtualSize: img.VirtualSize,
+ RepoTags: repoTags,
+ }
+ e.Labels, _ = img.Labels(context.TODO())
+
+ ctnrs, _ := img.Containers()
+ e.Containers = len(ctnrs)
+
+ sz, _ := img.Size(context.TODO())
+ e.Size = int64(*sz)
+
+ summaries[i] = &e
+ }
+ return summaries, nil
+}
diff --git a/pkg/domain/infra/abi/images_test.go b/pkg/domain/infra/abi/images_test.go
new file mode 100644
index 000000000..20ef1b150
--- /dev/null
+++ b/pkg/domain/infra/abi/images_test.go
@@ -0,0 +1,37 @@
+package abi
+
+//
+// import (
+// "context"
+// "testing"
+//
+// "github.com/stretchr/testify/mock"
+// )
+//
+// type MockImageRuntime struct {
+// mock.Mock
+// }
+//
+// func (m *MockImageRuntime) Delete(ctx context.Context, renderer func() interface{}, name string) error {
+// _ = m.Called(ctx, renderer, name)
+// return nil
+// }
+//
+// func TestImageSuccess(t *testing.T) {
+// actual := func() interface{} { return nil }
+//
+// m := new(MockImageRuntime)
+// m.On(
+// "Delete",
+// mock.AnythingOfType("*context.emptyCtx"),
+// mock.AnythingOfType("func() interface {}"),
+// "fedora").
+// Return(nil)
+//
+// r := DirectImageRuntime{m}
+// err := r.Delete(context.TODO(), actual, "fedora")
+// if err != nil {
+// t.Errorf("error should be nil, got: %v", err)
+// }
+// m.AssertExpectations(t)
+// }
diff --git a/pkg/domain/infra/abi/parse/parse.go b/pkg/domain/infra/abi/parse/parse.go
new file mode 100644
index 000000000..6c0e1ee55
--- /dev/null
+++ b/pkg/domain/infra/abi/parse/parse.go
@@ -0,0 +1,68 @@
+package parse
+
+import (
+ "strconv"
+ "strings"
+
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// Handle volume options from CLI.
+// Parse "o" option to find UID, GID.
+func ParseVolumeOptions(opts map[string]string) ([]libpod.VolumeCreateOption, error) {
+ libpodOptions := []libpod.VolumeCreateOption{}
+ volumeOptions := make(map[string]string)
+
+ for key, value := range opts {
+ switch key {
+ case "o":
+ // o has special handling to parse out UID, GID.
+ // These are separate Libpod options.
+ splitVal := strings.Split(value, ",")
+ finalVal := []string{}
+ for _, o := range splitVal {
+ // Options will be formatted as either "opt" or
+ // "opt=value"
+ splitO := strings.SplitN(o, "=", 2)
+ switch strings.ToLower(splitO[0]) {
+ case "uid":
+ if len(splitO) != 2 {
+ return nil, errors.Wrapf(define.ErrInvalidArg, "uid option must provide a UID")
+ }
+ intUID, err := strconv.Atoi(splitO[1])
+ if err != nil {
+ return nil, errors.Wrapf(err, "cannot convert UID %s to integer", splitO[1])
+ }
+ logrus.Debugf("Removing uid= from options and adding WithVolumeUID for UID %d", intUID)
+ libpodOptions = append(libpodOptions, libpod.WithVolumeUID(intUID))
+ case "gid":
+ if len(splitO) != 2 {
+ return nil, errors.Wrapf(define.ErrInvalidArg, "gid option must provide a GID")
+ }
+ intGID, err := strconv.Atoi(splitO[1])
+ if err != nil {
+ return nil, errors.Wrapf(err, "cannot convert GID %s to integer", splitO[1])
+ }
+ logrus.Debugf("Removing gid= from options and adding WithVolumeGID for GID %d", intGID)
+ libpodOptions = append(libpodOptions, libpod.WithVolumeGID(intGID))
+ default:
+ finalVal = append(finalVal, o)
+ }
+ }
+ if len(finalVal) > 0 {
+ volumeOptions[key] = strings.Join(finalVal, ",")
+ }
+ default:
+ volumeOptions[key] = value
+ }
+ }
+
+ if len(volumeOptions) > 0 {
+ libpodOptions = append(libpodOptions, libpod.WithVolumeOptions(volumeOptions))
+ }
+
+ return libpodOptions, nil
+}
diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go
new file mode 100644
index 000000000..619e973cf
--- /dev/null
+++ b/pkg/domain/infra/abi/pods.go
@@ -0,0 +1,252 @@
+// +build ABISupport
+
+package abi
+
+import (
+ "context"
+
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/signal"
+ "github.com/containers/libpod/pkg/specgen"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+// getPodsByContext returns a slice of pods. Note that all, latest and pods are
+// mutually exclusive arguments.
+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
+ }
+ var err error
+ for _, p := range pods {
+ pod, e := runtime.LookupPod(p)
+ if e != nil {
+ // Log all errors here, so callers don't need to.
+ logrus.Debugf("Error looking up pod %q: %v", p, e)
+ if err == nil {
+ err = e
+ }
+ } else {
+ outpods = append(outpods, pod)
+ }
+ }
+ return outpods, err
+}
+
+func (ic *ContainerEngine) PodExists(ctx context.Context, nameOrId string) (*entities.BoolReport, error) {
+ _, err := ic.Libpod.LookupPod(nameOrId)
+ if err != nil && errors.Cause(err) != define.ErrNoSuchPod {
+ return nil, err
+ }
+ return &entities.BoolReport{Value: err == nil}, nil
+}
+
+func (ic *ContainerEngine) PodKill(ctx context.Context, namesOrIds []string, options entities.PodKillOptions) ([]*entities.PodKillReport, error) {
+ var (
+ reports []*entities.PodKillReport
+ )
+ sig, err := signal.ParseSignalNameOrNumber(options.Signal)
+ if err != nil {
+ return nil, err
+ }
+ pods, err := getPodsByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, p := range pods {
+ report := entities.PodKillReport{Id: p.ID()}
+ conErrs, err := p.Kill(uint(sig))
+ if err != nil {
+ report.Errs = []error{err}
+ reports = append(reports, &report)
+ continue
+ }
+ if len(conErrs) > 0 {
+ for _, err := range conErrs {
+ report.Errs = append(report.Errs, err)
+ }
+ reports = append(reports, &report)
+ continue
+ }
+ reports = append(reports, &report)
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) PodPause(ctx context.Context, namesOrIds []string, options entities.PodPauseOptions) ([]*entities.PodPauseReport, error) {
+ var (
+ reports []*entities.PodPauseReport
+ )
+ pods, err := getPodsByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+ for _, p := range pods {
+ report := entities.PodPauseReport{Id: p.ID()}
+ errs, err := p.Pause()
+ if err != nil {
+ report.Errs = []error{err}
+ continue
+ }
+ if len(errs) > 0 {
+ for _, v := range errs {
+ report.Errs = append(report.Errs, v)
+ }
+ reports = append(reports, &report)
+ continue
+ }
+ reports = append(reports, &report)
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) PodUnpause(ctx context.Context, namesOrIds []string, options entities.PodunpauseOptions) ([]*entities.PodUnpauseReport, error) {
+ var (
+ reports []*entities.PodUnpauseReport
+ )
+ pods, err := getPodsByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+ for _, p := range pods {
+ report := entities.PodUnpauseReport{Id: p.ID()}
+ errs, err := p.Unpause()
+ if err != nil {
+ report.Errs = []error{err}
+ continue
+ }
+ if len(errs) > 0 {
+ for _, v := range errs {
+ report.Errs = append(report.Errs, v)
+ }
+ reports = append(reports, &report)
+ continue
+ }
+ reports = append(reports, &report)
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) PodStop(ctx context.Context, namesOrIds []string, options entities.PodStopOptions) ([]*entities.PodStopReport, error) {
+ var (
+ reports []*entities.PodStopReport
+ )
+ pods, err := getPodsByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+ for _, p := range pods {
+ report := entities.PodStopReport{Id: p.ID()}
+ errs, err := p.StopWithTimeout(ctx, false, options.Timeout)
+ if err != nil {
+ report.Errs = []error{err}
+ continue
+ }
+ if len(errs) > 0 {
+ for _, v := range errs {
+ report.Errs = append(report.Errs, v)
+ }
+ reports = append(reports, &report)
+ continue
+ }
+ reports = append(reports, &report)
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) PodRestart(ctx context.Context, namesOrIds []string, options entities.PodRestartOptions) ([]*entities.PodRestartReport, error) {
+ var (
+ reports []*entities.PodRestartReport
+ )
+ pods, err := getPodsByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+ for _, p := range pods {
+ report := entities.PodRestartReport{Id: p.ID()}
+ errs, err := p.Restart(ctx)
+ if err != nil {
+ report.Errs = []error{err}
+ continue
+ }
+ if len(errs) > 0 {
+ for _, v := range errs {
+ report.Errs = append(report.Errs, v)
+ }
+ reports = append(reports, &report)
+ continue
+ }
+ reports = append(reports, &report)
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) PodStart(ctx context.Context, namesOrIds []string, options entities.PodStartOptions) ([]*entities.PodStartReport, error) {
+ var (
+ reports []*entities.PodStartReport
+ )
+ pods, err := getPodsByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+ for _, p := range pods {
+ report := entities.PodStartReport{Id: p.ID()}
+ errs, err := p.Start(ctx)
+ if err != nil {
+ report.Errs = []error{err}
+ continue
+ }
+ if len(errs) > 0 {
+ for _, v := range errs {
+ report.Errs = append(report.Errs, v)
+ }
+ reports = append(reports, &report)
+ continue
+ }
+ reports = append(reports, &report)
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) PodRm(ctx context.Context, namesOrIds []string, options entities.PodRmOptions) ([]*entities.PodRmReport, error) {
+ var (
+ reports []*entities.PodRmReport
+ )
+ pods, err := getPodsByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+ for _, p := range pods {
+ report := entities.PodRmReport{Id: p.ID()}
+ err := ic.Libpod.RemovePod(ctx, p, true, options.Force)
+ if err != nil {
+ report.Err = err
+ continue
+ }
+ reports = append(reports, &report)
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) PodCreate(ctx context.Context, opts entities.PodCreateOptions) (*entities.PodCreateReport, error) {
+ podSpec := specgen.NewPodSpecGenerator()
+ opts.ToPodSpecGen(podSpec)
+ pod, err := podSpec.MakePod(ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+ return &entities.PodCreateReport{Id: pod.ID()}, nil
+}
diff --git a/pkg/domain/infra/abi/runtime.go b/pkg/domain/infra/abi/runtime.go
new file mode 100644
index 000000000..b53fb6d3a
--- /dev/null
+++ b/pkg/domain/infra/abi/runtime.go
@@ -0,0 +1,17 @@
+// +build ABISupport
+
+package abi
+
+import (
+ "github.com/containers/libpod/libpod"
+)
+
+// Image-related runtime linked against libpod library
+type ImageEngine struct {
+ Libpod *libpod.Runtime
+}
+
+// Container-related runtime linked against libpod library
+type ContainerEngine struct {
+ Libpod *libpod.Runtime
+}
diff --git a/pkg/domain/infra/abi/volumes.go b/pkg/domain/infra/abi/volumes.go
new file mode 100644
index 000000000..bdae4359d
--- /dev/null
+++ b/pkg/domain/infra/abi/volumes.go
@@ -0,0 +1,159 @@
+// +build ABISupport
+
+package abi
+
+import (
+ "context"
+
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/domain/filters"
+ "github.com/containers/libpod/pkg/domain/infra/abi/parse"
+ "github.com/pkg/errors"
+)
+
+func (ic *ContainerEngine) VolumeCreate(ctx context.Context, opts entities.VolumeCreateOptions) (*entities.IdOrNameResponse, error) {
+ var (
+ volumeOptions []libpod.VolumeCreateOption
+ )
+ if len(opts.Name) > 0 {
+ volumeOptions = append(volumeOptions, libpod.WithVolumeName(opts.Name))
+ }
+ if len(opts.Driver) > 0 {
+ volumeOptions = append(volumeOptions, libpod.WithVolumeDriver(opts.Driver))
+ }
+ if len(opts.Label) > 0 {
+ volumeOptions = append(volumeOptions, libpod.WithVolumeLabels(opts.Label))
+ }
+ if len(opts.Options) > 0 {
+ parsedOptions, err := parse.ParseVolumeOptions(opts.Options)
+ if err != nil {
+ return nil, err
+ }
+ volumeOptions = append(volumeOptions, parsedOptions...)
+ }
+ vol, err := ic.Libpod.NewVolume(ctx, volumeOptions...)
+ if err != nil {
+ return nil, err
+ }
+ return &entities.IdOrNameResponse{IdOrName: vol.Name()}, nil
+}
+
+func (ic *ContainerEngine) VolumeRm(ctx context.Context, namesOrIds []string, opts entities.VolumeRmOptions) ([]*entities.VolumeRmReport, error) {
+ var (
+ err error
+ reports []*entities.VolumeRmReport
+ vols []*libpod.Volume
+ )
+ if opts.All {
+ vols, err = ic.Libpod.Volumes()
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ for _, id := range namesOrIds {
+ vol, err := ic.Libpod.LookupVolume(id)
+ if err != nil {
+ reports = append(reports, &entities.VolumeRmReport{
+ Err: err,
+ Id: id,
+ })
+ continue
+ }
+ vols = append(vols, vol)
+ }
+ }
+ for _, vol := range vols {
+ reports = append(reports, &entities.VolumeRmReport{
+ Err: ic.Libpod.RemoveVolume(ctx, vol, opts.Force),
+ Id: vol.Name(),
+ })
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) VolumeInspect(ctx context.Context, namesOrIds []string, opts entities.VolumeInspectOptions) ([]*entities.VolumeInspectReport, error) {
+ var (
+ err error
+ reports []*entities.VolumeInspectReport
+ vols []*libpod.Volume
+ )
+
+ // Note: as with previous implementation, a single failure here
+ // results a return.
+ if opts.All {
+ vols, err = ic.Libpod.GetAllVolumes()
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ for _, v := range namesOrIds {
+ vol, err := ic.Libpod.LookupVolume(v)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error inspecting volume %s", v)
+ }
+ vols = append(vols, vol)
+ }
+ }
+ for _, v := range vols {
+ config := entities.VolumeConfigResponse{
+ Name: v.Name(),
+ Driver: v.Driver(),
+ Mountpoint: v.MountPoint(),
+ CreatedAt: v.CreatedTime(),
+ Labels: v.Labels(),
+ Scope: v.Scope(),
+ Options: v.Options(),
+ UID: v.UID(),
+ GID: v.GID(),
+ }
+ reports = append(reports, &entities.VolumeInspectReport{VolumeConfigResponse: &config})
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) VolumePrune(ctx context.Context, opts entities.VolumePruneOptions) ([]*entities.VolumePruneReport, error) {
+ var (
+ reports []*entities.VolumePruneReport
+ )
+ pruned, err := ic.Libpod.PruneVolumes(ctx)
+ if err != nil {
+ return nil, err
+ }
+ for k, v := range pruned {
+ reports = append(reports, &entities.VolumePruneReport{
+ Err: v,
+ Id: k,
+ })
+ }
+ return reports, nil
+}
+
+func (ic *ContainerEngine) VolumeList(ctx context.Context, opts entities.VolumeListOptions) ([]*entities.VolumeListReport, error) {
+ var (
+ reports []*entities.VolumeListReport
+ )
+ volumeFilters, err := filters.GenerateVolumeFilters(opts.Filter)
+ if err != nil {
+ return nil, err
+ }
+ vols, err := ic.Libpod.Volumes(volumeFilters...)
+ if err != nil {
+ return nil, err
+ }
+ for _, v := range vols {
+ config := entities.VolumeConfigResponse{
+ Name: v.Name(),
+ Driver: v.Driver(),
+ Mountpoint: v.MountPoint(),
+ CreatedAt: v.CreatedTime(),
+ Labels: v.Labels(),
+ Scope: v.Scope(),
+ Options: v.Options(),
+ UID: v.UID(),
+ GID: v.GID(),
+ }
+ reports = append(reports, &entities.VolumeListReport{VolumeConfigResponse: config})
+ }
+ return reports, nil
+}