diff options
Diffstat (limited to 'pkg/domain')
-rw-r--r-- | pkg/domain/entities/containers.go | 82 | ||||
-rw-r--r-- | pkg/domain/entities/engine.go | 319 | ||||
-rw-r--r-- | pkg/domain/entities/engine_container.go | 15 | ||||
-rw-r--r-- | pkg/domain/entities/engine_image.go | 4 | ||||
-rw-r--r-- | pkg/domain/entities/images.go | 44 | ||||
-rw-r--r-- | pkg/domain/entities/pods.go | 5 | ||||
-rw-r--r-- | pkg/domain/entities/system.go | 14 | ||||
-rw-r--r-- | pkg/domain/entities/types.go | 10 | ||||
-rw-r--r-- | pkg/domain/infra/abi/containers.go | 190 | ||||
-rw-r--r-- | pkg/domain/infra/abi/events.go | 18 | ||||
-rw-r--r-- | pkg/domain/infra/abi/images.go | 61 | ||||
-rw-r--r-- | pkg/domain/infra/abi/pods.go | 6 | ||||
-rw-r--r-- | pkg/domain/infra/abi/system.go | 231 | ||||
-rw-r--r-- | pkg/domain/infra/runtime_abi.go | 4 | ||||
-rw-r--r-- | pkg/domain/infra/runtime_image_proxy.go | 2 | ||||
-rw-r--r-- | pkg/domain/infra/runtime_libpod.go | 58 | ||||
-rw-r--r-- | pkg/domain/infra/runtime_proxy.go | 2 | ||||
-rw-r--r-- | pkg/domain/infra/runtime_tunnel.go | 4 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/containers.go | 38 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/events.go | 31 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/images.go | 9 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/system.go | 10 |
22 files changed, 1032 insertions, 125 deletions
diff --git a/pkg/domain/entities/containers.go b/pkg/domain/entities/containers.go index 5d302058b..f21af9ce4 100644 --- a/pkg/domain/entities/containers.go +++ b/pkg/domain/entities/containers.go @@ -172,6 +172,26 @@ type AttachOptions struct { Stderr *os.File } +// ContainerLogsOptions describes the options to extract container logs. +type ContainerLogsOptions struct { + // Show extra details provided to the logs. + Details bool + // Follow the log output. + Follow bool + // Display logs for the latest container only. Ignored on the remote client. + Latest bool + // Show container names in the output. + Names bool + // Show logs since this timestamp. + Since time.Time + // Number of lines to display at the end of the output. + Tail int64 + // Show timestamps in the logs. + Timestamps bool + // Write the logs to Writer. + Writer io.Writer +} + // ExecOptions describes the cli values to exec into // a container type ExecOptions struct { @@ -245,3 +265,65 @@ type ContainerRunReport struct { ExitCode int Id string } + +// ContainerCleanupOptions are the CLI values for the +// cleanup command +type ContainerCleanupOptions struct { + All bool + Latest bool + Remove bool + RemoveImage bool +} + +// ContainerCleanupReport describes the response from a +// container cleanup +type ContainerCleanupReport struct { + CleanErr error + Id string + RmErr error + RmiErr error +} + +// ContainerInitOptions describes input options +// for the container init cli +type ContainerInitOptions struct { + All bool + Latest bool +} + +// ContainerInitReport describes the results of a +// container init +type ContainerInitReport struct { + Err error + Id string +} + +//ContainerMountOptions describes the input values for mounting containers +// in the CLI +type ContainerMountOptions struct { + All bool + Format string + Latest bool + NoTruncate bool +} + +// ContainerUnmountOptions are the options from the cli for unmounting +type ContainerUnmountOptions struct { + All bool + Force bool + Latest bool +} + +// ContainerMountReport describes the response from container mount +type ContainerMountReport struct { + Err error + Id string + Name string + Path string +} + +// ContainerUnmountReport describes the response from umounting a container +type ContainerUnmountReport struct { + Err error + Id string +} diff --git a/pkg/domain/entities/engine.go b/pkg/domain/entities/engine.go index c14348529..3b971a1e8 100644 --- a/pkg/domain/entities/engine.go +++ b/pkg/domain/entities/engine.go @@ -1,13 +1,23 @@ package entities import ( - "os/user" - "path/filepath" + "context" + "fmt" + "io" + "os" + "github.com/containers/buildah/pkg/parse" "github.com/containers/common/pkg/config" + "github.com/containers/common/pkg/sysinfo" + "github.com/containers/libpod/pkg/apparmor" + "github.com/containers/libpod/pkg/cgroups" + "github.com/containers/libpod/pkg/rootless" + "github.com/opencontainers/selinux/go-selinux" + "github.com/opentracing/opentracing-go" "github.com/spf13/pflag" ) +// EngineMode is the connection type podman is using to access libpod type EngineMode string const ( @@ -15,78 +25,243 @@ const ( TunnelMode = EngineMode("tunnel") ) +// Convert EngineMode to String func (m EngineMode) String() string { return string(m) } -type EngineOptions struct { - Uri string - Identities []string - FlagSet *pflag.FlagSet - EngineMode EngineMode - - CGroupManager string - CniConfigDir string - ConmonPath string - DefaultMountsFile string - EventsBackend string - HooksDir []string - MaxWorks int - Namespace string - Root string - Runroot string - Runtime string - StorageDriver string - StorageOpts []string - Syslog bool - Trace bool - NetworkCmdPath string - - Config string - CpuProfile string - LogLevel string - TmpDir string - - RemoteUserName string - RemoteHost string - VarlinkAddress string - ConnectionName string - RemoteConfigFilePath string - Port int - IdentityFile string - IgnoreHosts bool -} - -func NewEngineOptions() (EngineOptions, error) { - u, _ := user.Current() - return EngineOptions{ - CGroupManager: config.SystemdCgroupsManager, - CniConfigDir: "", - Config: "", - ConmonPath: filepath.Join("usr", "bin", "conmon"), - ConnectionName: "", - CpuProfile: "", - DefaultMountsFile: "", - EventsBackend: "", - HooksDir: nil, - IdentityFile: "", - IgnoreHosts: false, - LogLevel: "", - MaxWorks: 0, - Namespace: "", - NetworkCmdPath: "", - Port: 0, - RemoteConfigFilePath: "", - RemoteHost: "", - RemoteUserName: "", - Root: "", - Runroot: filepath.Join("run", "user", u.Uid), - Runtime: "", - StorageDriver: "overlayfs", - StorageOpts: nil, - Syslog: false, - TmpDir: filepath.Join("run", "user", u.Uid, "libpod", "tmp"), - Trace: false, - VarlinkAddress: "", - }, nil +// PodmanConfig combines the defaults and settings from the file system with the +// flags given in os.Args. Some runtime state is also stored here. +type PodmanConfig struct { + *config.Config + *pflag.FlagSet + + CGroupUsage string // rootless code determines Usage message + ConmonPath string // --conmon flag will set Engine.ConmonPath + CpuProfile string // Hidden: Should CPU profile be taken + EngineMode EngineMode // ABI or Tunneling mode + Identities []string // ssh identities for connecting to server + MaxWorks int // maximum number of parallel threads + RuntimePath string // --runtime flag will set Engine.RuntimePath + SpanCloser io.Closer // Close() for tracing object + SpanCtx context.Context // context to use when tracing + Span opentracing.Span // tracing object + Syslog bool // write to StdOut and Syslog, not supported when tunneling + Trace bool // Hidden: Trace execution + Uri string // URI to API Service + + Runroot string + StorageDriver string + StorageOpts []string +} + +// DefaultSecurityOptions: getter for security options from configuration +func (c PodmanConfig) DefaultSecurityOptions() []string { + securityOpts := []string{} + if c.Containers.SeccompProfile != "" && c.Containers.SeccompProfile != parse.SeccompDefaultPath { + securityOpts = append(securityOpts, fmt.Sprintf("seccomp=%s", c.Containers.SeccompProfile)) + } + if apparmor.IsEnabled() && c.Containers.ApparmorProfile != "" { + securityOpts = append(securityOpts, fmt.Sprintf("apparmor=%s", c.Containers.ApparmorProfile)) + } + if selinux.GetEnabled() && !c.Containers.EnableLabeling { + securityOpts = append(securityOpts, fmt.Sprintf("label=%s", selinux.DisableSecOpt()[0])) + } + return securityOpts +} + +// DefaultSysctls +func (c PodmanConfig) DefaultSysctls() []string { + return c.Containers.DefaultSysctls +} + +func (c PodmanConfig) DefaultVolumes() []string { + return c.Containers.Volumes +} + +func (c PodmanConfig) DefaultDevices() []string { + return c.Containers.Devices +} + +func (c PodmanConfig) DefaultDNSServers() []string { + return c.Containers.DNSServers +} + +func (c PodmanConfig) DefaultDNSSearches() []string { + return c.Containers.DNSSearches +} + +func (c PodmanConfig) DefaultDNSOptions() []string { + return c.Containers.DNSOptions +} + +func (c PodmanConfig) DefaultEnv() []string { + return c.Containers.Env +} + +func (c PodmanConfig) DefaultInitPath() string { + return c.Containers.InitPath +} + +func (c PodmanConfig) DefaultIPCNS() string { + return c.Containers.IPCNS } + +func (c PodmanConfig) DefaultPidNS() string { + return c.Containers.PidNS +} + +func (c PodmanConfig) DefaultNetNS() string { + if c.Containers.NetNS == "private" && rootless.IsRootless() { + return "slirp4netns" + } + return c.Containers.NetNS +} + +func (c PodmanConfig) DefaultCgroupNS() string { + return c.Containers.CgroupNS +} + +func (c PodmanConfig) DefaultUTSNS() string { + return c.Containers.UTSNS +} + +func (c PodmanConfig) DefaultShmSize() string { + return c.Containers.ShmSize +} + +func (c PodmanConfig) DefaultUlimits() []string { + return c.Containers.DefaultUlimits +} + +func (c PodmanConfig) DefaultUserNS() string { + if v, found := os.LookupEnv("PODMAN_USERNS"); found { + return v + } + return c.Containers.UserNS +} + +func (c PodmanConfig) DefaultPidsLimit() int64 { + if rootless.IsRootless() { + cgroup2, _ := cgroups.IsCgroup2UnifiedMode() + if cgroup2 { + return c.Containers.PidsLimit + } + } + return sysinfo.GetDefaultPidsLimit() +} + +func (c PodmanConfig) DefaultPidsDescription() string { + return "Tune container pids limit (set 0 for unlimited)" +} + +func (c PodmanConfig) DefaultDetachKeys() string { + return c.Engine.DetachKeys +} + +// TODO: Remove in rootless support PR +// // EngineOptions holds the environment for running the engines +// type EngineOptions struct { +// // Introduced with V2 +// Uri string +// Identities []string +// FlagSet *pflag.FlagSet +// EngineMode EngineMode +// CGroupUsage string +// +// // Introduced with V1 +// CGroupManager string // config.EngineConfig +// CniConfigDir string // config.NetworkConfig.NetworkConfigDir +// ConmonPath string // config.EngineConfig +// DefaultMountsFile string // config.ContainersConfig +// EventsBackend string // config.EngineConfig.EventsLogger +// HooksDir []string // config.EngineConfig +// MaxWorks int +// Namespace string // config.EngineConfig +// Root string // +// Runroot string // config.EngineConfig.StorageConfigRunRootSet?? +// Runtime string // config.EngineConfig.OCIRuntime +// StorageDriver string // config.EngineConfig.StorageConfigGraphDriverNameSet?? +// StorageOpts []string +// Syslog bool +// Trace bool +// NetworkCmdPath string // config.EngineConfig +// +// Config string +// CpuProfile string +// LogLevel string +// TmpDir string // config.EngineConfig +// +// RemoteUserName string // deprecated +// RemoteHost string // deprecated +// VarlinkAddress string // deprecated +// ConnectionName string +// RemoteConfigFilePath string +// Port int // deprecated +// IdentityFile string // deprecated +// IgnoreHosts bool +// } +// +// func NewEngineOptions(opts EngineOptions) (EngineOptions, error) { +// ctnrCfg, err := config.Default() +// if err != nil { +// logrus.Error(err) +// os.Exit(1) +// } +// +// cgroupManager := ctnrCfg.Engine.CgroupManager +// cgroupUsage := `Cgroup manager to use ("cgroupfs"|"systemd")` +// cgroupv2, _ := cgroups.IsCgroup2UnifiedMode() +// cniPluginDir := ctnrCfg.Network.CNIPluginDirs[0] +// +// cfg, err := config.NewConfig("") +// if err != nil { +// logrus.Errorf("Error loading container config %v\n", err) +// os.Exit(1) +// } +// cfg.CheckCgroupsAndAdjustConfig() +// +// if rootless.IsRootless() { +// if !cgroupv2 { +// cgroupManager = "" +// cgroupUsage = "Cgroup manager is not supported in rootless mode" +// } +// cniPluginDir = "" +// } +// +// return EngineOptions{ +// CGroupManager: cgroupManager, +// CGroupUsage: cgroupUsage, +// CniConfigDir: cniPluginDir, +// Config: opts.Config, // TODO: deprecate +// ConmonPath: opts.ConmonPath, +// ConnectionName: opts.ConnectionName, +// CpuProfile: opts.CpuProfile, +// DefaultMountsFile: ctnrCfg.Containers.DefaultMountsFile, +// EngineMode: opts.EngineMode, +// EventsBackend: ctnrCfg.Engine.EventsLogger, +// FlagSet: opts.FlagSet, // TODO: deprecate +// HooksDir: append(ctnrCfg.Engine.HooksDir[:0:0], ctnrCfg.Engine.HooksDir...), +// Identities: append(opts.Identities[:0:0], opts.Identities...), +// IdentityFile: opts.IdentityFile, // TODO: deprecate +// IgnoreHosts: opts.IgnoreHosts, +// LogLevel: opts.LogLevel, +// MaxWorks: opts.MaxWorks, +// Namespace: ctnrCfg.Engine.Namespace, +// NetworkCmdPath: ctnrCfg.Engine.NetworkCmdPath, +// Port: opts.Port, +// RemoteConfigFilePath: opts.RemoteConfigFilePath, +// RemoteHost: opts.RemoteHost, // TODO: deprecate +// RemoteUserName: opts.RemoteUserName, // TODO: deprecate +// Root: opts.Root, +// Runroot: opts.Runroot, +// Runtime: opts.Runtime, +// StorageDriver: opts.StorageDriver, +// StorageOpts: append(opts.StorageOpts[:0:0], opts.StorageOpts...), +// Syslog: opts.Syslog, +// TmpDir: opts.TmpDir, +// Trace: opts.Trace, +// Uri: opts.Uri, +// VarlinkAddress: opts.VarlinkAddress, +// }, nil +// } diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go index 24b7a9acc..5fdb9a8a6 100644 --- a/pkg/domain/entities/engine_container.go +++ b/pkg/domain/entities/engine_container.go @@ -3,33 +3,42 @@ package entities import ( "context" + "github.com/containers/common/pkg/config" "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/pkg/specgen" ) type ContainerEngine interface { + Config(ctx context.Context) (*config.Config, error) ContainerAttach(ctx context.Context, nameOrId string, options AttachOptions) error ContainerCheckpoint(ctx context.Context, namesOrIds []string, options CheckpointOptions) ([]*CheckpointReport, error) + ContainerCleanup(ctx context.Context, namesOrIds []string, options ContainerCleanupOptions) ([]*ContainerCleanupReport, error) ContainerCommit(ctx context.Context, nameOrId string, options CommitOptions) (*CommitReport, error) ContainerCreate(ctx context.Context, s *specgen.SpecGenerator) (*ContainerCreateReport, error) ContainerDiff(ctx context.Context, nameOrId string, options DiffOptions) (*DiffReport, error) ContainerExec(ctx context.Context, nameOrId string, options ExecOptions) (int, error) ContainerExists(ctx context.Context, nameOrId string) (*BoolReport, error) ContainerExport(ctx context.Context, nameOrId string, options ContainerExportOptions) error + ContainerInit(ctx context.Context, namesOrIds []string, options ContainerInitOptions) ([]*ContainerInitReport, error) ContainerInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]*ContainerInspectReport, error) ContainerKill(ctx context.Context, namesOrIds []string, options KillOptions) ([]*KillReport, error) ContainerList(ctx context.Context, options ContainerListOptions) ([]ListContainer, error) + ContainerMount(ctx context.Context, nameOrIds []string, options ContainerMountOptions) ([]*ContainerMountReport, error) ContainerPause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error) + ContainerLogs(ctx context.Context, containers []string, options ContainerLogsOptions) error ContainerRestart(ctx context.Context, namesOrIds []string, options RestartOptions) ([]*RestartReport, error) ContainerRestore(ctx context.Context, namesOrIds []string, options RestoreOptions) ([]*RestoreReport, error) ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*RmReport, error) - ContainerStart(ctx context.Context, namesOrIds []string, options ContainerStartOptions) ([]*ContainerStartReport, error) ContainerRun(ctx context.Context, opts ContainerRunOptions) (*ContainerRunReport, error) + ContainerStart(ctx context.Context, namesOrIds []string, options ContainerStartOptions) ([]*ContainerStartReport, error) ContainerStop(ctx context.Context, namesOrIds []string, options StopOptions) ([]*StopReport, error) ContainerTop(ctx context.Context, options TopOptions) (*StringSliceReport, error) + ContainerUnmount(ctx context.Context, nameOrIds []string, options ContainerUnmountOptions) ([]*ContainerUnmountReport, error) ContainerUnpause(ctx context.Context, namesOrIds []string, options PauseUnPauseOptions) ([]*PauseUnpauseReport, error) ContainerWait(ctx context.Context, namesOrIds []string, options WaitOptions) ([]WaitReport, error) + Events(ctx context.Context, opts EventsOptions) error HealthCheckRun(ctx context.Context, nameOrId string, options HealthCheckOptions) (*define.HealthCheckResults, error) + Info(ctx context.Context) (*define.Info, error) PodCreate(ctx context.Context, opts PodCreateOptions) (*PodCreateReport, error) PodExists(ctx context.Context, nameOrId string) (*BoolReport, error) PodInspect(ctx context.Context, options PodInspectOptions) (*PodInspectReport, error) @@ -42,11 +51,11 @@ type ContainerEngine interface { PodStop(ctx context.Context, namesOrIds []string, options PodStopOptions) ([]*PodStopReport, error) PodTop(ctx context.Context, options PodTopOptions) (*StringSliceReport, error) PodUnpause(ctx context.Context, namesOrIds []string, options PodunpauseOptions) ([]*PodUnpauseReport, error) + RestService(ctx context.Context, opts ServiceOptions) error + VarlinkService(ctx context.Context, opts ServiceOptions) error VolumeCreate(ctx context.Context, opts VolumeCreateOptions) (*IdOrNameResponse, error) VolumeInspect(ctx context.Context, namesOrIds []string, opts VolumeInspectOptions) ([]*VolumeInspectReport, error) VolumeList(ctx context.Context, opts VolumeListOptions) ([]*VolumeListReport, error) VolumePrune(ctx context.Context, opts VolumePruneOptions) ([]*VolumePruneReport, error) VolumeRm(ctx context.Context, namesOrIds []string, opts VolumeRmOptions) ([]*VolumeRmReport, error) - - Info(ctx context.Context) (*define.Info, error) } diff --git a/pkg/domain/entities/engine_image.go b/pkg/domain/entities/engine_image.go index 16b96e9ef..3a051ab9b 100644 --- a/pkg/domain/entities/engine_image.go +++ b/pkg/domain/entities/engine_image.go @@ -2,9 +2,12 @@ package entities import ( "context" + + "github.com/containers/common/pkg/config" ) type ImageEngine interface { + Config(ctx context.Context) (*config.Config, error) Delete(ctx context.Context, nameOrId []string, opts ImageDeleteOptions) (*ImageDeleteReport, error) Diff(ctx context.Context, nameOrId string, options DiffOptions) (*DiffReport, error) Exists(ctx context.Context, nameOrId string) (*BoolReport, error) @@ -19,4 +22,5 @@ type ImageEngine interface { Save(ctx context.Context, nameOrId string, tags []string, options ImageSaveOptions) error Tag(ctx context.Context, nameOrId string, tags []string, options ImageTagOptions) error Untag(ctx context.Context, nameOrId string, tags []string, options ImageUntagOptions) error + Search(ctx context.Context, term string, opts ImageSearchOptions) ([]ImageSearchReport, error) } diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go index bc8a34c13..78ebb8805 100644 --- a/pkg/domain/entities/images.go +++ b/pkg/domain/entities/images.go @@ -2,6 +2,7 @@ package entities import ( "net/url" + "time" "github.com/containers/image/v5/manifest" "github.com/containers/image/v5/types" @@ -99,12 +100,12 @@ type ImageDeleteReport struct { type ImageHistoryOptions struct{} type ImageHistoryLayer struct { - ID string `json:"Id"` - Created int64 `json:",omitempty"` - CreatedBy string `json:",omitempty"` - Tags []string `json:",omitempty"` - Size int64 `json:",omitempty"` - Comment string `json:",omitempty"` + ID string `json:"id"` + Created time.Time `json:"created,omitempty"` + CreatedBy string `json:",omitempty"` + Tags []string `json:"tags,omitempty"` + Size int64 `json:"size"` + Comment string `json:"comment,omitempty"` } type ImageHistoryReport struct { @@ -181,6 +182,37 @@ type ImagePushOptions struct { TLSVerify types.OptionalBool } +// ImageSearchOptions are the arguments for searching images. +type ImageSearchOptions struct { + // Authfile is the path to the authentication file. Ignored for remote + // calls. + Authfile string + // Filters for the search results. + Filters []string + // Limit the number of results. + Limit int + // NoTrunc will not truncate the output. + NoTrunc bool + // TLSVerify to enable/disable HTTPS and certificate verification. + TLSVerify types.OptionalBool +} + +// ImageSearchReport is the response from searching images. +type ImageSearchReport struct { + // Index is the image index (e.g., "docker.io" or "quay.io") + Index string + // Name is the canoncical name of the image (e.g., "docker.io/library/alpine"). + Name string + // Description of the image. + Description string + // Stars is the number of stars of the image. + Stars int + // Official indicates if it's an official image. + Official string + // Automated indicates if the image was created by an automated build. + Automated string +} + type ImageListOptions struct { All bool `json:"all" schema:"all"` Filter []string `json:"Filter,omitempty"` diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go index cd2e79961..9ca8ff43c 100644 --- a/pkg/domain/entities/pods.go +++ b/pkg/domain/entities/pods.go @@ -1,6 +1,7 @@ package entities import ( + "strings" "time" "github.com/containers/libpod/libpod" @@ -121,7 +122,9 @@ func (p PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) { s.Hostname = p.Hostname s.Labels = p.Labels s.NoInfra = !p.Infra - s.InfraCommand = []string{p.InfraCommand} + if len(p.InfraCommand) > 0 { + s.InfraCommand = strings.Split(p.InfraCommand, " ") + } s.InfraImage = p.InfraImage s.SharedNamespaces = p.Share diff --git a/pkg/domain/entities/system.go b/pkg/domain/entities/system.go new file mode 100644 index 000000000..3ddc04293 --- /dev/null +++ b/pkg/domain/entities/system.go @@ -0,0 +1,14 @@ +package entities + +import ( + "time" + + "github.com/spf13/cobra" +) + +// ServiceOptions provides the input for starting an API Service +type ServiceOptions struct { + URI string // Path to unix domain socket service should listen on + Timeout time.Duration // duration of inactivity the service should wait before shutting down + Command *cobra.Command // CLI command provided. Used in V1 code +} diff --git a/pkg/domain/entities/types.go b/pkg/domain/entities/types.go index 7e35957f4..91ae00764 100644 --- a/pkg/domain/entities/types.go +++ b/pkg/domain/entities/types.go @@ -3,6 +3,7 @@ package entities import ( "net" + "github.com/containers/libpod/libpod/events" "github.com/containers/libpod/pkg/specgen" "github.com/containers/storage/pkg/archive" "github.com/cri-o/ocicni/pkg/ocicni" @@ -62,3 +63,12 @@ type DiffOptions struct { type DiffReport struct { Changes []archive.Change } + +type EventsOptions struct { + FromStart bool + EventChan chan *events.Event + Filter []string + Stream bool + Since string + Until string +} diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index ccbe6d4fd..f464df3ac 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -4,23 +4,30 @@ package abi import ( "context" + "fmt" "io/ioutil" + "os" "strconv" "strings" + "sync" "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" ) @@ -709,3 +716,186 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta } 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 2edef2723..9467c14d4 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 } @@ -421,3 +428,43 @@ func (ir *ImageEngine) Diff(_ context.Context, nameOrId string, _ entities.DiffO } 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() +} diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go index c3e5d59bc..bb637de3e 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 } diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go index 8aaa69847..10872144b 100644 --- a/pkg/domain/infra/abi/system.go +++ b/pkg/domain/infra/abi/system.go @@ -4,10 +4,241 @@ 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(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) + } + } + } + } + + if !executeCommandInUserNS(cmd) { + return nil + } + + 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.WithError(err).Fatal("") + } + + 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.WithError(err).Fatal("") + } + if became { + os.Exit(ret) + } + return nil +} + +// Most podman commands when run in rootless mode, need to be executed in the +// users usernamespace. This function is updated with a list of commands that +// should NOT be run within the user namespace. +func executeCommandInUserNS(cmd *cobra.Command) bool { + return os.Geteuid() == 0 + // if os.Geteuid() == 0 { + // return false + // } + // switch cmd { + // case _migrateCommand, + // _mountCommand, + // _renumberCommand, + // _searchCommand, + // _versionCommand: + // return false + // } + // return true +} + +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 +} + +// func getCNIPluginsDir() string { +// if rootless.IsRootless() { +// return "" +// } +// +// return registry.PodmanOptions.Network.CNIPluginDirs[0] +// } diff --git a/pkg/domain/infra/runtime_abi.go b/pkg/domain/infra/runtime_abi.go index f11026571..0dbcf2ad2 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..45c5425a3 100644 --- a/pkg/domain/infra/runtime_image_proxy.go +++ b/pkg/domain/infra/runtime_image_proxy.go @@ -12,7 +12,7 @@ import ( // ContainerEngine Image Proxy will be EOL'ed after podmanV2 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..9cf374e2e 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..18f716ea0 100644 --- a/pkg/domain/infra/runtime_proxy.go +++ b/pkg/domain/infra/runtime_proxy.go @@ -12,7 +12,7 @@ import ( // ContainerEngine Proxy will be EOL'ed after podmanV2 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..129fdeb2c 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 b22c6e3ba..05b62efcf 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" @@ -305,6 +306,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") } @@ -329,3 +335,35 @@ func (ic *ContainerEngine) ContainerDiff(ctx context.Context, nameOrId string, _ 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 66abd7f47..7d40e0327 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" @@ -250,3 +251,11 @@ func (ir *ImageEngine) Diff(ctx context.Context, nameOrId string, _ entities.Dif } 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() +} diff --git a/pkg/domain/infra/tunnel/system.go b/pkg/domain/infra/tunnel/system.go index 5d6346234..7c7a55c05 100644 --- a/pkg/domain/infra/tunnel/system.go +++ b/pkg/domain/infra/tunnel/system.go @@ -2,11 +2,21 @@ 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" ) 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")) +} |