diff options
Diffstat (limited to 'pkg/domain/infra')
-rw-r--r-- | pkg/domain/infra/abi/containers.go | 245 | ||||
-rw-r--r-- | pkg/domain/infra/abi/events.go | 18 | ||||
-rw-r--r-- | pkg/domain/infra/abi/images.go | 77 | ||||
-rw-r--r-- | pkg/domain/infra/abi/images_list.go | 2 | ||||
-rw-r--r-- | pkg/domain/infra/abi/pods.go | 8 | ||||
-rw-r--r-- | pkg/domain/infra/abi/system.go | 215 | ||||
-rw-r--r-- | pkg/domain/infra/runtime_abi.go | 4 | ||||
-rw-r--r-- | pkg/domain/infra/runtime_image_proxy.go | 4 | ||||
-rw-r--r-- | pkg/domain/infra/runtime_libpod.go | 58 | ||||
-rw-r--r-- | pkg/domain/infra/runtime_proxy.go | 4 | ||||
-rw-r--r-- | pkg/domain/infra/runtime_tunnel.go | 4 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/containers.go | 47 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/events.go | 31 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/images.go | 22 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/system.go | 26 |
15 files changed, 713 insertions, 52 deletions
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index 828ee56f0..50003dbe2 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -4,23 +4,32 @@ package abi import ( "context" + "fmt" "io/ioutil" + "os" "strconv" "strings" + "sync" + + lpfilters "github.com/containers/libpod/libpod/filters" "github.com/containers/buildah" + "github.com/containers/common/pkg/config" "github.com/containers/image/v5/manifest" "github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/libpod/events" "github.com/containers/libpod/libpod/image" + "github.com/containers/libpod/libpod/logs" "github.com/containers/libpod/pkg/checkpoint" "github.com/containers/libpod/pkg/domain/entities" "github.com/containers/libpod/pkg/domain/infra/abi/terminal" "github.com/containers/libpod/pkg/ps" + "github.com/containers/libpod/pkg/rootless" "github.com/containers/libpod/pkg/signal" "github.com/containers/libpod/pkg/specgen" "github.com/containers/libpod/pkg/specgen/generate" + "github.com/containers/storage" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -166,6 +175,28 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin return reports, nil } +func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) (*entities.ContainerPruneReport, error) { + var filterFuncs []libpod.ContainerFilter + for k, v := range options.Filters { + for _, val := range v { + generatedFunc, err := lpfilters.GenerateContainerFilterFuncs(k, val, ic.Libpod) + if err != nil { + return nil, err + } + filterFuncs = append(filterFuncs, generatedFunc) + } + } + prunedContainers, pruneErrors, err := ic.Libpod.PruneContainers(filterFuncs) + if err != nil { + return nil, err + } + report := entities.ContainerPruneReport{ + ID: prunedContainers, + Err: pruneErrors, + } + return &report, nil +} + func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) { var ( reports []*entities.KillReport @@ -599,9 +630,9 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri ExitCode: 125, } if err := ctr.Start(ctx, ctr.PodID() != ""); err != nil { - //if lastError != nil { + // if lastError != nil { // fmt.Fprintln(os.Stderr, lastError) - //} + // } report.Err = err if errors.Cause(err) == define.ErrWillDeadlock { report.Err = errors.Wrapf(err, "please run 'podman system renumber' to resolve deadlocks") @@ -623,10 +654,20 @@ func (ic *ContainerEngine) ContainerList(ctx context.Context, options entities.C return ps.GetContainerLists(ic.Libpod, options) } +// ContainerDiff provides changes to given container +func (ic *ContainerEngine) ContainerDiff(ctx context.Context, nameOrId string, opts entities.DiffOptions) (*entities.DiffReport, error) { + if opts.Latest { + ctnr, err := ic.Libpod.GetLatestContainer() + if err != nil { + return nil, errors.Wrap(err, "unable to get latest container") + } + nameOrId = ctnr.ID() + } + changes, err := ic.Libpod.GetDiff("", nameOrId) + return &entities.DiffReport{Changes: changes}, err +} + func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.ContainerRunOptions) (*entities.ContainerRunReport, error) { - var ( - joinPod bool - ) if err := generate.CompleteSpec(ctx, ic.Libpod, opts.Spec); err != nil { return nil, err } @@ -635,6 +676,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta return nil, err } + var joinPod bool if len(ctr.PodID()) > 0 { joinPod = true } @@ -694,5 +736,198 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta } else { report.ExitCode = int(ecode) } + if opts.Rm { + if err := ic.Libpod.RemoveContainer(ctx, ctr, false, true); err != nil { + if errors.Cause(err) == define.ErrNoSuchCtr || + errors.Cause(err) == define.ErrCtrRemoved { + logrus.Warnf("Container %s does not exist: %v", ctr.ID(), err) + } else { + logrus.Errorf("Error removing container %s: %v", ctr.ID(), err) + } + } + } return &report, nil } + +func (ic *ContainerEngine) ContainerLogs(ctx context.Context, containers []string, options entities.ContainerLogsOptions) error { + if options.Writer == nil { + return errors.New("no io.Writer set for container logs") + } + + var wg sync.WaitGroup + + ctrs, err := getContainersByContext(false, options.Latest, containers, ic.Libpod) + if err != nil { + return err + } + + logOpts := &logs.LogOptions{ + Multi: len(ctrs) > 1, + Details: options.Details, + Follow: options.Follow, + Since: options.Since, + Tail: options.Tail, + Timestamps: options.Timestamps, + UseName: options.Names, + WaitGroup: &wg, + } + + chSize := len(ctrs) * int(options.Tail) + if chSize <= 0 { + chSize = 1 + } + logChannel := make(chan *logs.LogLine, chSize) + + if err := ic.Libpod.Log(ctrs, logOpts, logChannel); err != nil { + return err + } + + go func() { + wg.Wait() + close(logChannel) + }() + + for line := range logChannel { + fmt.Fprintln(options.Writer, line.String(logOpts)) + } + + return nil +} + +func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []string, options entities.ContainerCleanupOptions) ([]*entities.ContainerCleanupReport, error) { + var reports []*entities.ContainerCleanupReport + ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod) + if err != nil { + return nil, err + } + for _, ctr := range ctrs { + var err error + report := entities.ContainerCleanupReport{Id: ctr.ID()} + if options.Remove { + err = ic.Libpod.RemoveContainer(ctx, ctr, false, true) + if err != nil { + report.RmErr = errors.Wrapf(err, "failed to cleanup and remove container %v", ctr.ID()) + } + } else { + err := ctr.Cleanup(ctx) + if err != nil { + report.CleanErr = errors.Wrapf(err, "failed to cleanup container %v", ctr.ID()) + } + } + + if options.RemoveImage { + _, imageName := ctr.Image() + ctrImage, err := ic.Libpod.ImageRuntime().NewFromLocal(imageName) + if err != nil { + report.RmiErr = err + reports = append(reports, &report) + continue + } + _, err = ic.Libpod.RemoveImage(ctx, ctrImage, false) + report.RmiErr = err + } + reports = append(reports, &report) + } + return reports, nil +} + +func (ic *ContainerEngine) ContainerInit(ctx context.Context, namesOrIds []string, options entities.ContainerInitOptions) ([]*entities.ContainerInitReport, error) { + var reports []*entities.ContainerInitReport + ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod) + if err != nil { + return nil, err + } + for _, ctr := range ctrs { + report := entities.ContainerInitReport{Id: ctr.ID()} + report.Err = ctr.Init(ctx) + reports = append(reports, &report) + } + return reports, nil +} + +func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIds []string, options entities.ContainerMountOptions) ([]*entities.ContainerMountReport, error) { + if os.Geteuid() != 0 { + if driver := ic.Libpod.StorageConfig().GraphDriverName; driver != "vfs" { + // Do not allow to mount a graphdriver that is not vfs if we are creating the userns as part + // of the mount command. + return nil, fmt.Errorf("cannot mount using driver %s in rootless mode", driver) + } + + became, ret, err := rootless.BecomeRootInUserNS("") + if err != nil { + return nil, err + } + if became { + os.Exit(ret) + } + } + var reports []*entities.ContainerMountReport + ctrs, err := getContainersByContext(options.All, options.Latest, nameOrIds, ic.Libpod) + if err != nil { + return nil, err + } + for _, ctr := range ctrs { + report := entities.ContainerMountReport{Id: ctr.ID()} + report.Path, report.Err = ctr.Mount() + reports = append(reports, &report) + } + if len(reports) > 0 { + return reports, nil + } + + // No containers were passed, so we send back what is mounted + ctrs, err = getContainersByContext(true, false, []string{}, ic.Libpod) + if err != nil { + return nil, err + } + for _, ctr := range ctrs { + mounted, path, err := ctr.Mounted() + if err != nil { + return nil, err + } + + if mounted { + reports = append(reports, &entities.ContainerMountReport{ + Id: ctr.ID(), + Name: ctr.Name(), + Path: path, + }) + } + } + return reports, nil +} + +func (ic *ContainerEngine) ContainerUnmount(ctx context.Context, nameOrIds []string, options entities.ContainerUnmountOptions) ([]*entities.ContainerUnmountReport, error) { + var reports []*entities.ContainerUnmountReport + ctrs, err := getContainersByContext(options.All, options.Latest, nameOrIds, ic.Libpod) + if err != nil { + return nil, err + } + for _, ctr := range ctrs { + state, err := ctr.State() + if err != nil { + logrus.Debugf("Error umounting container %s state: %s", ctr.ID(), err.Error()) + continue + } + if state == define.ContainerStateRunning { + logrus.Debugf("Error umounting container %s, is running", ctr.ID()) + continue + } + + report := entities.ContainerUnmountReport{Id: ctr.ID()} + if err := ctr.Unmount(options.Force); err != nil { + if options.All && errors.Cause(err) == storage.ErrLayerNotMounted { + logrus.Debugf("Error umounting container %s, storage.ErrLayerNotMounted", ctr.ID()) + continue + } + report.Err = errors.Wrapf(err, "error unmounting container %s", ctr.ID()) + } + reports = append(reports, &report) + } + return reports, nil +} + +// GetConfig returns a copy of the configuration used by the runtime +func (ic *ContainerEngine) Config(_ context.Context) (*config.Config, error) { + return ic.Libpod.GetConfig() +} diff --git a/pkg/domain/infra/abi/events.go b/pkg/domain/infra/abi/events.go new file mode 100644 index 000000000..9540a5b96 --- /dev/null +++ b/pkg/domain/infra/abi/events.go @@ -0,0 +1,18 @@ +//+build ABISupport + +package abi + +import ( + "context" + + "github.com/containers/libpod/libpod/events" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/sirupsen/logrus" +) + +func (ic *ContainerEngine) Events(ctx context.Context, opts entities.EventsOptions) error { + readOpts := events.ReadOptions{FromStart: opts.FromStart, Stream: opts.Stream, Filters: opts.Filter, EventChannel: opts.EventChan, Since: opts.Since, Until: opts.Until} + err := ic.Libpod.Events(readOpts) + logrus.Error(err) + return err +} diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go index 9d706a112..0f710ad28 100644 --- a/pkg/domain/infra/abi/images.go +++ b/pkg/domain/infra/abi/images.go @@ -9,12 +9,14 @@ import ( "os" "strings" + "github.com/containers/common/pkg/config" "github.com/containers/image/v5/docker" dockerarchive "github.com/containers/image/v5/docker/archive" "github.com/containers/image/v5/docker/reference" "github.com/containers/image/v5/manifest" "github.com/containers/image/v5/transports/alltransports" "github.com/containers/image/v5/types" + "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/libpod/image" libpodImage "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/domain/entities" @@ -27,10 +29,11 @@ import ( ) func (ir *ImageEngine) Exists(_ context.Context, nameOrId string) (*entities.BoolReport, error) { - if _, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrId); err != nil { - return &entities.BoolReport{}, nil + _, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrId) + if err != nil && errors.Cause(err) != define.ErrNoSuchImage { + return nil, err } - return &entities.BoolReport{Value: true}, nil + return &entities.BoolReport{Value: err == nil}, nil } func (ir *ImageEngine) Delete(ctx context.Context, nameOrId []string, opts entities.ImageDeleteOptions) (*entities.ImageDeleteReport, error) { @@ -43,7 +46,9 @@ func (ir *ImageEngine) Delete(ctx context.Context, nameOrId []string, opts entit if err != nil { return &report, errors.Wrapf(err, "unable to query local images") } - + if len(targets) == 0 { + return &report, nil + } if len(targets) > 0 && len(targets) == len(previousTargets) { return &report, errors.New("unable to delete all images; re-run the rmi command again.") } @@ -140,7 +145,7 @@ func (ir *ImageEngine) History(ctx context.Context, nameOrId string, opts entiti func ToDomainHistoryLayer(layer *libpodImage.History) entities.ImageHistoryLayer { l := entities.ImageHistoryLayer{} l.ID = layer.ID - l.Created = layer.Created.Unix() + l.Created = *layer.Created l.CreatedBy = layer.CreatedBy copy(l.Tags, layer.Tags) l.Size = layer.Size @@ -392,8 +397,10 @@ func (ir *ImageEngine) Load(ctx context.Context, opts entities.ImageLoadOptions) if err != nil { return nil, errors.Wrap(err, "image loaded but no additional tags were created") } - if err := newImage.TagImage(opts.Name); err != nil { - return nil, errors.Wrapf(err, "error adding %q to image %q", opts.Name, newImage.InputName) + if len(opts.Name) > 0 { + if err := newImage.TagImage(fmt.Sprintf("%s:%s", opts.Name, opts.Tag)); err != nil { + return nil, errors.Wrapf(err, "error adding %q to image %q", opts.Name, newImage.InputName) + } } return &entities.ImageLoadReport{Name: name}, nil } @@ -413,3 +420,59 @@ func (ir *ImageEngine) Save(ctx context.Context, nameOrId string, tags []string, } return newImage.Save(ctx, nameOrId, options.Format, options.Output, tags, options.Quiet, options.Compress) } + +func (ir *ImageEngine) Diff(_ context.Context, nameOrId string, _ entities.DiffOptions) (*entities.DiffReport, error) { + changes, err := ir.Libpod.GetDiff("", nameOrId) + if err != nil { + return nil, err + } + return &entities.DiffReport{Changes: changes}, nil +} + +func (ir *ImageEngine) Search(ctx context.Context, term string, opts entities.ImageSearchOptions) ([]entities.ImageSearchReport, error) { + filter, err := image.ParseSearchFilter(opts.Filters) + if err != nil { + return nil, err + } + + searchOpts := image.SearchOptions{ + Authfile: opts.Authfile, + Filter: *filter, + Limit: opts.Limit, + NoTrunc: opts.NoTrunc, + InsecureSkipTLSVerify: opts.TLSVerify, + } + + searchResults, err := image.SearchImages(term, searchOpts) + if err != nil { + return nil, err + } + + // Convert from image.SearchResults to entities.ImageSearchReport. We don't + // want to leak any low-level packages into the remote client, which + // requires converting. + reports := make([]entities.ImageSearchReport, len(searchResults)) + for i := range searchResults { + reports[i].Index = searchResults[i].Index + reports[i].Name = searchResults[i].Name + reports[i].Description = searchResults[i].Index + reports[i].Stars = searchResults[i].Stars + reports[i].Official = searchResults[i].Official + reports[i].Automated = searchResults[i].Automated + } + + return reports, nil +} + +// GetConfig returns a copy of the configuration used by the runtime +func (ir *ImageEngine) Config(_ context.Context) (*config.Config, error) { + return ir.Libpod.GetConfig() +} + +func (ir *ImageEngine) Build(ctx context.Context, containerFiles []string, opts entities.BuildOptions) (*entities.BuildReport, error) { + id, _, err := ir.Libpod.Build(ctx, opts.BuildOptions, containerFiles...) + if err != nil { + return nil, err + } + return &entities.BuildReport{ID: id}, nil +} diff --git a/pkg/domain/infra/abi/images_list.go b/pkg/domain/infra/abi/images_list.go index 2f4020374..68b961cb6 100644 --- a/pkg/domain/infra/abi/images_list.go +++ b/pkg/domain/infra/abi/images_list.go @@ -54,7 +54,7 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) ID: img.ID(), ConfigDigest: string(img.ConfigDigest), - Created: img.Created().Unix(), + Created: img.Created(), Dangling: img.Dangling(), Digest: string(img.Digest()), Digests: digests, diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go index c3e5d59bc..59bf0f636 100644 --- a/pkg/domain/infra/abi/pods.go +++ b/pkg/domain/infra/abi/pods.go @@ -5,13 +5,13 @@ package abi import ( "context" - lpfilters "github.com/containers/libpod/libpod/filters" - "github.com/containers/libpod/libpod" "github.com/containers/libpod/libpod/define" + lpfilters "github.com/containers/libpod/libpod/filters" "github.com/containers/libpod/pkg/domain/entities" "github.com/containers/libpod/pkg/signal" "github.com/containers/libpod/pkg/specgen" + "github.com/containers/libpod/pkg/specgen/generate" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -246,7 +246,7 @@ func (ic *ContainerEngine) PodRm(ctx context.Context, namesOrIds []string, optio 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) + pod, err := generate.MakePod(podSpec, ic.Libpod) if err != nil { return nil, err } @@ -351,5 +351,5 @@ func (ic *ContainerEngine) PodInspect(ctx context.Context, options entities.PodI if err != nil { return nil, err } - return &entities.PodInspectReport{PodInspect: inspect}, nil + return &entities.PodInspectReport{InspectPodData: inspect}, nil } diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go new file mode 100644 index 000000000..67593b2dd --- /dev/null +++ b/pkg/domain/infra/abi/system.go @@ -0,0 +1,215 @@ +// +build ABISupport + +package abi + +import ( + "context" + "fmt" + "io/ioutil" + "net" + "os" + "strconv" + "strings" + "syscall" + + "github.com/containers/common/pkg/config" + "github.com/containers/libpod/libpod/define" + api "github.com/containers/libpod/pkg/api/server" + "github.com/containers/libpod/pkg/cgroups" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/containers/libpod/pkg/rootless" + "github.com/containers/libpod/pkg/util" + iopodman "github.com/containers/libpod/pkg/varlink" + iopodmanAPI "github.com/containers/libpod/pkg/varlinkapi" + "github.com/containers/libpod/utils" + "github.com/containers/libpod/version" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/varlink/go/varlink" +) + +func (ic *ContainerEngine) Info(ctx context.Context) (*define.Info, error) { + return ic.Libpod.Info() +} + +func (ic *ContainerEngine) RestService(_ context.Context, opts entities.ServiceOptions) error { + var ( + listener net.Listener + err error + ) + + if opts.URI != "" { + fields := strings.Split(opts.URI, ":") + if len(fields) == 1 { + return errors.Errorf("%s is an invalid socket destination", opts.URI) + } + address := strings.Join(fields[1:], ":") + listener, err = net.Listen(fields[0], address) + if err != nil { + return errors.Wrapf(err, "unable to create socket %s", opts.URI) + } + } + + server, err := api.NewServerWithSettings(ic.Libpod, opts.Timeout, &listener) + if err != nil { + return err + } + defer func() { + if err := server.Shutdown(); err != nil { + logrus.Warnf("Error when stopping API service: %s", err) + } + }() + + err = server.Serve() + _ = listener.Close() + return err +} + +func (ic *ContainerEngine) VarlinkService(_ context.Context, opts entities.ServiceOptions) error { + var varlinkInterfaces = []*iopodman.VarlinkInterface{ + iopodmanAPI.New(opts.Command, ic.Libpod), + } + + service, err := varlink.NewService( + "Atomic", + "podman", + version.Version, + "https://github.com/containers/libpod", + ) + if err != nil { + return errors.Wrapf(err, "unable to create new varlink service") + } + + for _, i := range varlinkInterfaces { + if err := service.RegisterInterface(i); err != nil { + return errors.Errorf("unable to register varlink interface %v", i) + } + } + + // Run the varlink server at the given address + if err = service.Listen(opts.URI, opts.Timeout); err != nil { + switch err.(type) { + case varlink.ServiceTimeoutError: + logrus.Infof("varlink service expired (use --timeout to increase session time beyond %s ms, 0 means never timeout)", opts.Timeout.String()) + return nil + default: + return errors.Wrapf(err, "unable to start varlink service") + } + } + return nil +} + +func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command) error { + // do it only after podman has already re-execed and running with uid==0. + if os.Geteuid() == 0 { + ownsCgroup, err := cgroups.UserOwnsCurrentSystemdCgroup() + if err != nil { + logrus.Warnf("Failed to detect the owner for the current cgroup: %v", err) + } + if !ownsCgroup { + conf, err := ic.Config(context.Background()) + if err != nil { + return err + } + unitName := fmt.Sprintf("podman-%d.scope", os.Getpid()) + if err := utils.RunUnderSystemdScope(os.Getpid(), "user.slice", unitName); err != nil { + if conf.Engine.CgroupManager == config.SystemdCgroupsManager { + logrus.Warnf("Failed to add podman to systemd sandbox cgroup: %v", err) + } else { + logrus.Debugf("Failed to add podman to systemd sandbox cgroup: %v", err) + } + } + } + } + + pausePidPath, err := util.GetRootlessPauseProcessPidPath() + if err != nil { + return errors.Wrapf(err, "could not get pause process pid file path") + } + + became, ret, err := rootless.TryJoinPauseProcess(pausePidPath) + if err != nil { + return err + } + if became { + os.Exit(ret) + } + + // if there is no pid file, try to join existing containers, and create a pause process. + ctrs, err := ic.Libpod.GetRunningContainers() + if err != nil { + logrus.Error(err.Error()) + os.Exit(1) + } + + paths := []string{} + for _, ctr := range ctrs { + paths = append(paths, ctr.Config().ConmonPidFile) + } + + became, ret, err = rootless.TryJoinFromFilePaths(pausePidPath, true, paths) + if err := movePauseProcessToScope(); err != nil { + conf, err := ic.Config(context.Background()) + if err != nil { + return err + } + if conf.Engine.CgroupManager == config.SystemdCgroupsManager { + logrus.Warnf("Failed to add pause process to systemd sandbox cgroup: %v", err) + } else { + logrus.Debugf("Failed to add pause process to systemd sandbox cgroup: %v", err) + } + } + if err != nil { + logrus.Error(err) + os.Exit(1) + } + if became { + os.Exit(ret) + } + return nil +} + +func movePauseProcessToScope() error { + pausePidPath, err := util.GetRootlessPauseProcessPidPath() + if err != nil { + return errors.Wrapf(err, "could not get pause process pid file path") + } + + data, err := ioutil.ReadFile(pausePidPath) + if err != nil { + return errors.Wrapf(err, "cannot read pause pid file") + } + pid, err := strconv.ParseUint(string(data), 10, 0) + if err != nil { + return errors.Wrapf(err, "cannot parse pid file %s", pausePidPath) + } + + return utils.RunUnderSystemdScope(int(pid), "user.slice", "podman-pause.scope") +} + +func setRLimits() error { // nolint:deadcode,unused + rlimits := new(syscall.Rlimit) + rlimits.Cur = 1048576 + rlimits.Max = 1048576 + if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, rlimits); err != nil { + if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, rlimits); err != nil { + return errors.Wrapf(err, "error getting rlimits") + } + rlimits.Cur = rlimits.Max + if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, rlimits); err != nil { + return errors.Wrapf(err, "error setting new rlimits") + } + } + return nil +} + +func setUMask() { // nolint:deadcode,unused + // Be sure we can create directories with 0755 mode. + syscall.Umask(0022) +} + +// checkInput can be used to verify any of the globalopt values +func checkInput() error { // nolint:deadcode,unused + return nil +} diff --git a/pkg/domain/infra/runtime_abi.go b/pkg/domain/infra/runtime_abi.go index f11026571..7aa6986a7 100644 --- a/pkg/domain/infra/runtime_abi.go +++ b/pkg/domain/infra/runtime_abi.go @@ -12,7 +12,7 @@ import ( ) // NewContainerEngine factory provides a libpod runtime for container-related operations -func NewContainerEngine(facts entities.EngineOptions) (entities.ContainerEngine, error) { +func NewContainerEngine(facts *entities.PodmanConfig) (entities.ContainerEngine, error) { switch facts.EngineMode { case entities.ABIMode: r, err := NewLibpodRuntime(facts.FlagSet, facts) @@ -25,7 +25,7 @@ func NewContainerEngine(facts entities.EngineOptions) (entities.ContainerEngine, } // NewContainerEngine factory provides a libpod runtime for image-related operations -func NewImageEngine(facts entities.EngineOptions) (entities.ImageEngine, error) { +func NewImageEngine(facts *entities.PodmanConfig) (entities.ImageEngine, error) { switch facts.EngineMode { case entities.ABIMode: r, err := NewLibpodImageRuntime(facts.FlagSet, facts) diff --git a/pkg/domain/infra/runtime_image_proxy.go b/pkg/domain/infra/runtime_image_proxy.go index befc66b9a..ea5d0e6f2 100644 --- a/pkg/domain/infra/runtime_image_proxy.go +++ b/pkg/domain/infra/runtime_image_proxy.go @@ -10,9 +10,9 @@ import ( "github.com/spf13/pflag" ) -// ContainerEngine Image Proxy will be EOL'ed after podmanV2 is separated from libpod repo +// ContainerEngine Image Proxy will be EOL'ed after podman is separated from libpod repo -func NewLibpodImageRuntime(flags *pflag.FlagSet, opts entities.EngineOptions) (entities.ImageEngine, error) { +func NewLibpodImageRuntime(flags *pflag.FlagSet, opts *entities.PodmanConfig) (entities.ImageEngine, error) { r, err := GetRuntime(context.Background(), flags, opts) if err != nil { return nil, err diff --git a/pkg/domain/infra/runtime_libpod.go b/pkg/domain/infra/runtime_libpod.go index d59759707..dc59fec3d 100644 --- a/pkg/domain/infra/runtime_libpod.go +++ b/pkg/domain/infra/runtime_libpod.go @@ -1,3 +1,5 @@ +// +build ABISupport + package infra import ( @@ -22,68 +24,70 @@ type engineOpts struct { migrate bool noStore bool withFDS bool - flags entities.EngineOptions + config *entities.PodmanConfig } // GetRuntimeMigrate gets a libpod runtime that will perform a migration of existing containers -func GetRuntimeMigrate(ctx context.Context, fs *flag.FlagSet, ef entities.EngineOptions, newRuntime string) (*libpod.Runtime, error) { +func GetRuntimeMigrate(ctx context.Context, fs *flag.FlagSet, cfg *entities.PodmanConfig, newRuntime string) (*libpod.Runtime, error) { return getRuntime(ctx, fs, &engineOpts{ name: newRuntime, renumber: false, migrate: true, noStore: false, withFDS: true, - flags: ef, + config: cfg, }) } // GetRuntimeDisableFDs gets a libpod runtime that will disable sd notify -func GetRuntimeDisableFDs(ctx context.Context, fs *flag.FlagSet, ef entities.EngineOptions) (*libpod.Runtime, error) { +func GetRuntimeDisableFDs(ctx context.Context, fs *flag.FlagSet, cfg *entities.PodmanConfig) (*libpod.Runtime, error) { return getRuntime(ctx, fs, &engineOpts{ renumber: false, migrate: false, noStore: false, withFDS: false, - flags: ef, + config: cfg, }) } // GetRuntimeRenumber gets a libpod runtime that will perform a lock renumber -func GetRuntimeRenumber(ctx context.Context, fs *flag.FlagSet, ef entities.EngineOptions) (*libpod.Runtime, error) { +func GetRuntimeRenumber(ctx context.Context, fs *flag.FlagSet, cfg *entities.PodmanConfig) (*libpod.Runtime, error) { return getRuntime(ctx, fs, &engineOpts{ renumber: true, migrate: false, noStore: false, withFDS: true, - flags: ef, + config: cfg, }) } // GetRuntime generates a new libpod runtime configured by command line options -func GetRuntime(ctx context.Context, flags *flag.FlagSet, ef entities.EngineOptions) (*libpod.Runtime, error) { +func GetRuntime(ctx context.Context, flags *flag.FlagSet, cfg *entities.PodmanConfig) (*libpod.Runtime, error) { return getRuntime(ctx, flags, &engineOpts{ renumber: false, migrate: false, noStore: false, withFDS: true, - flags: ef, + config: cfg, }) } // GetRuntimeNoStore generates a new libpod runtime configured by command line options -func GetRuntimeNoStore(ctx context.Context, fs *flag.FlagSet, ef entities.EngineOptions) (*libpod.Runtime, error) { +func GetRuntimeNoStore(ctx context.Context, fs *flag.FlagSet, cfg *entities.PodmanConfig) (*libpod.Runtime, error) { return getRuntime(ctx, fs, &engineOpts{ renumber: false, migrate: false, noStore: true, withFDS: true, - flags: ef, + config: cfg, }) } func getRuntime(ctx context.Context, fs *flag.FlagSet, opts *engineOpts) (*libpod.Runtime, error) { options := []libpod.RuntimeOption{} storageOpts := storage.StoreOptions{} + cfg := opts.config + storageSet := false uidmapFlag := fs.Lookup("uidmap") @@ -109,25 +113,25 @@ func getRuntime(ctx context.Context, fs *flag.FlagSet, opts *engineOpts) (*libpo if fs.Changed("root") { storageSet = true - storageOpts.GraphRoot = opts.flags.Root + storageOpts.GraphRoot = cfg.Engine.StaticDir } if fs.Changed("runroot") { storageSet = true - storageOpts.RunRoot = opts.flags.Runroot + storageOpts.RunRoot = cfg.Runroot } if len(storageOpts.RunRoot) > 50 { return nil, errors.New("the specified runroot is longer than 50 characters") } if fs.Changed("storage-driver") { storageSet = true - storageOpts.GraphDriverName = opts.flags.StorageDriver + storageOpts.GraphDriverName = cfg.StorageDriver // Overriding the default storage driver caused GraphDriverOptions from storage.conf to be ignored storageOpts.GraphDriverOptions = []string{} } // This should always be checked after storage-driver is checked - if len(opts.flags.StorageOpts) > 0 { + if len(cfg.StorageOpts) > 0 { storageSet = true - storageOpts.GraphDriverOptions = opts.flags.StorageOpts + storageOpts.GraphDriverOptions = cfg.StorageOpts } if opts.migrate { options = append(options, libpod.WithMigrate()) @@ -151,30 +155,30 @@ func getRuntime(ctx context.Context, fs *flag.FlagSet, opts *engineOpts) (*libpo // TODO CLI flags for image config? // TODO CLI flag for signature policy? - if len(opts.flags.Namespace) > 0 { - options = append(options, libpod.WithNamespace(opts.flags.Namespace)) + if len(cfg.Engine.Namespace) > 0 { + options = append(options, libpod.WithNamespace(cfg.Engine.Namespace)) } if fs.Changed("runtime") { - options = append(options, libpod.WithOCIRuntime(opts.flags.Runtime)) + options = append(options, libpod.WithOCIRuntime(cfg.RuntimePath)) } if fs.Changed("conmon") { - options = append(options, libpod.WithConmonPath(opts.flags.ConmonPath)) + options = append(options, libpod.WithConmonPath(cfg.ConmonPath)) } if fs.Changed("tmpdir") { - options = append(options, libpod.WithTmpDir(opts.flags.TmpDir)) + options = append(options, libpod.WithTmpDir(cfg.Engine.TmpDir)) } if fs.Changed("network-cmd-path") { - options = append(options, libpod.WithNetworkCmdPath(opts.flags.NetworkCmdPath)) + options = append(options, libpod.WithNetworkCmdPath(cfg.Engine.NetworkCmdPath)) } if fs.Changed("events-backend") { - options = append(options, libpod.WithEventsLogger(opts.flags.EventsBackend)) + options = append(options, libpod.WithEventsLogger(cfg.Engine.EventsLogger)) } if fs.Changed("cgroup-manager") { - options = append(options, libpod.WithCgroupManager(opts.flags.CGroupManager)) + options = append(options, libpod.WithCgroupManager(cfg.Engine.CgroupManager)) } else { unified, err := cgroups.IsCgroup2UnifiedMode() if err != nil { @@ -189,13 +193,13 @@ func getRuntime(ctx context.Context, fs *flag.FlagSet, opts *engineOpts) (*libpo // TODO flag to set libpod tmp dir? if fs.Changed("cni-config-dir") { - options = append(options, libpod.WithCNIConfigDir(opts.flags.CniConfigDir)) + options = append(options, libpod.WithCNIConfigDir(cfg.Network.NetworkConfigDir)) } if fs.Changed("default-mounts-file") { - options = append(options, libpod.WithDefaultMountsFile(opts.flags.DefaultMountsFile)) + options = append(options, libpod.WithDefaultMountsFile(cfg.Containers.DefaultMountsFile)) } if fs.Changed("hooks-dir") { - options = append(options, libpod.WithHooksDir(opts.flags.HooksDir...)) + options = append(options, libpod.WithHooksDir(cfg.Engine.HooksDir...)) } // TODO flag to set CNI plugins dir? diff --git a/pkg/domain/infra/runtime_proxy.go b/pkg/domain/infra/runtime_proxy.go index 2e38c74b9..41193fd89 100644 --- a/pkg/domain/infra/runtime_proxy.go +++ b/pkg/domain/infra/runtime_proxy.go @@ -10,9 +10,9 @@ import ( flag "github.com/spf13/pflag" ) -// ContainerEngine Proxy will be EOL'ed after podmanV2 is separated from libpod repo +// ContainerEngine Proxy will be EOL'ed after podman is separated from libpod repo -func NewLibpodRuntime(flags *flag.FlagSet, opts entities.EngineOptions) (entities.ContainerEngine, error) { +func NewLibpodRuntime(flags *flag.FlagSet, opts *entities.PodmanConfig) (entities.ContainerEngine, error) { r, err := GetRuntime(context.Background(), flags, opts) if err != nil { return nil, err diff --git a/pkg/domain/infra/runtime_tunnel.go b/pkg/domain/infra/runtime_tunnel.go index dc04b4e53..752218aaf 100644 --- a/pkg/domain/infra/runtime_tunnel.go +++ b/pkg/domain/infra/runtime_tunnel.go @@ -11,7 +11,7 @@ import ( "github.com/containers/libpod/pkg/domain/infra/tunnel" ) -func NewContainerEngine(facts entities.EngineOptions) (entities.ContainerEngine, error) { +func NewContainerEngine(facts *entities.PodmanConfig) (entities.ContainerEngine, error) { switch facts.EngineMode { case entities.ABIMode: return nil, fmt.Errorf("direct runtime not supported") @@ -23,7 +23,7 @@ func NewContainerEngine(facts entities.EngineOptions) (entities.ContainerEngine, } // NewImageEngine factory provides a libpod runtime for image-related operations -func NewImageEngine(facts entities.EngineOptions) (entities.ImageEngine, error) { +func NewImageEngine(facts *entities.PodmanConfig) (entities.ImageEngine, error) { switch facts.EngineMode { case entities.ABIMode: return nil, fmt.Errorf("direct image runtime not supported") diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index e96200c5b..679bb371b 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -5,6 +5,7 @@ import ( "io" "os" + "github.com/containers/common/pkg/config" "github.com/containers/image/v5/docker/reference" "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/pkg/bindings/containers" @@ -145,6 +146,10 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, return reports, nil } +func (ic *ContainerEngine) ContainerPrune(ctx context.Context, options entities.ContainerPruneOptions) (*entities.ContainerPruneReport, error) { + return containers.Prune(ic.ClientCxt, options.Filters) +} + func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, error) { var ( reports []*entities.ContainerInspectReport @@ -305,6 +310,11 @@ func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecG return &entities.ContainerCreateReport{Id: response.ID}, nil } +func (ic *ContainerEngine) ContainerLogs(ctx context.Context, containers []string, options entities.ContainerLogsOptions) error { + // The endpoint is not ready yet and requires some more work. + return errors.New("not implemented yet") +} + func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrId string, options entities.AttachOptions) error { return errors.New("not implemented") } @@ -324,3 +334,40 @@ func (ic *ContainerEngine) ContainerList(ctx context.Context, options entities.C func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.ContainerRunOptions) (*entities.ContainerRunReport, error) { return nil, errors.New("not implemented") } + +func (ic *ContainerEngine) ContainerDiff(ctx context.Context, nameOrId string, _ entities.DiffOptions) (*entities.DiffReport, error) { + changes, err := containers.Diff(ic.ClientCxt, nameOrId) + return &entities.DiffReport{Changes: changes}, err +} + +func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []string, options entities.ContainerCleanupOptions) ([]*entities.ContainerCleanupReport, error) { + return nil, errors.New("not implemented") +} + +func (ic *ContainerEngine) ContainerInit(ctx context.Context, namesOrIds []string, options entities.ContainerInitOptions) ([]*entities.ContainerInitReport, error) { + var reports []*entities.ContainerInitReport + ctrs, err := getContainersByContext(ic.ClientCxt, options.All, namesOrIds) + if err != nil { + return nil, err + } + for _, ctr := range ctrs { + err := containers.ContainerInit(ic.ClientCxt, ctr.ID) + reports = append(reports, &entities.ContainerInitReport{ + Err: err, + Id: ctr.ID, + }) + } + return reports, nil +} + +func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIds []string, options entities.ContainerMountOptions) ([]*entities.ContainerMountReport, error) { + return nil, errors.New("mounting containers is not supported for remote clients") +} + +func (ic *ContainerEngine) ContainerUnmount(ctx context.Context, nameOrIds []string, options entities.ContainerUnmountOptions) ([]*entities.ContainerUnmountReport, error) { + return nil, errors.New("unmounting containers is not supported for remote clients") +} + +func (ic *ContainerEngine) Config(_ context.Context) (*config.Config, error) { + return config.Default() +} diff --git a/pkg/domain/infra/tunnel/events.go b/pkg/domain/infra/tunnel/events.go new file mode 100644 index 000000000..46d88341a --- /dev/null +++ b/pkg/domain/infra/tunnel/events.go @@ -0,0 +1,31 @@ +package tunnel + +import ( + "context" + "strings" + + "github.com/containers/libpod/pkg/api/handlers" + "github.com/containers/libpod/pkg/bindings/system" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/pkg/errors" +) + +func (ic *ContainerEngine) Events(ctx context.Context, opts entities.EventsOptions) error { + filters := make(map[string][]string) + if len(opts.Filter) > 0 { + for _, filter := range opts.Filter { + split := strings.Split(filter, "=") + if len(split) < 2 { + return errors.Errorf("invalid filter %q", filter) + } + filters[split[0]] = append(filters[split[0]], strings.Join(split[1:], "=")) + } + } + binChan := make(chan handlers.Event) + go func() { + for e := range binChan { + opts.EventChan <- e.ToLibpodEvent() + } + }() + return system.Events(ic.ClientCxt, binChan, nil, &opts.Since, &opts.Until, filters) +} diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index 516914a68..6ea2bd9f2 100644 --- a/pkg/domain/infra/tunnel/images.go +++ b/pkg/domain/infra/tunnel/images.go @@ -5,6 +5,7 @@ import ( "io/ioutil" "os" + "github.com/containers/common/pkg/config" "github.com/containers/image/v5/docker/reference" images "github.com/containers/libpod/pkg/bindings/images" "github.com/containers/libpod/pkg/domain/entities" @@ -241,3 +242,24 @@ func (ir *ImageEngine) Save(ctx context.Context, nameOrId string, tags []string, } return utils2.UntarToFileSystem(options.Output, f, nil) } + +// Diff reports the changes to the given image +func (ir *ImageEngine) Diff(ctx context.Context, nameOrId string, _ entities.DiffOptions) (*entities.DiffReport, error) { + changes, err := images.Diff(ir.ClientCxt, nameOrId) + if err != nil { + return nil, err + } + return &entities.DiffReport{Changes: changes}, nil +} + +func (ir *ImageEngine) Search(ctx context.Context, term string, opts entities.ImageSearchOptions) ([]entities.ImageSearchReport, error) { + return images.Search(ir.ClientCxt, term, opts) +} + +func (ir *ImageEngine) Config(_ context.Context) (*config.Config, error) { + return config.Default() +} + +func (ir *ImageEngine) Build(ctx context.Context, containerFiles []string, opts entities.BuildOptions) (*entities.BuildReport, error) { + return nil, errors.New("not implemented yet") +} diff --git a/pkg/domain/infra/tunnel/system.go b/pkg/domain/infra/tunnel/system.go index 5bafef1fe..f373525c5 100644 --- a/pkg/domain/infra/tunnel/system.go +++ b/pkg/domain/infra/tunnel/system.go @@ -1 +1,27 @@ package tunnel + +import ( + "context" + "errors" + + "github.com/containers/libpod/libpod/define" + "github.com/containers/libpod/pkg/bindings/system" + "github.com/containers/libpod/pkg/domain/entities" + "github.com/spf13/cobra" +) + +func (ic *ContainerEngine) Info(ctx context.Context) (*define.Info, error) { + return system.Info(ic.ClientCxt) +} + +func (ic *ContainerEngine) RestService(_ context.Context, _ entities.ServiceOptions) error { + panic(errors.New("rest service is not supported when tunneling")) +} + +func (ic *ContainerEngine) VarlinkService(_ context.Context, _ entities.ServiceOptions) error { + panic(errors.New("varlink service is not supported when tunneling")) +} + +func (ic *ContainerEngine) SetupRootless(_ context.Context, cmd *cobra.Command) error { + panic(errors.New("rootless engine mode is not supported when tunneling")) +} |