diff options
Diffstat (limited to 'libpod')
-rw-r--r-- | libpod/container.go | 3 | ||||
-rw-r--r-- | libpod/container_api.go | 7 | ||||
-rw-r--r-- | libpod/container_inspect.go | 2 | ||||
-rw-r--r-- | libpod/container_internal.go | 36 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 44 | ||||
-rw-r--r-- | libpod/define/errors.go | 4 | ||||
-rw-r--r-- | libpod/events/config.go | 12 | ||||
-rw-r--r-- | libpod/events/events.go | 23 | ||||
-rw-r--r-- | libpod/events/events_linux.go | 4 | ||||
-rw-r--r-- | libpod/events/journal_linux.go | 24 | ||||
-rw-r--r-- | libpod/events/logfile.go | 7 | ||||
-rw-r--r-- | libpod/events/nullout.go | 8 | ||||
-rw-r--r-- | libpod/image/search.go | 7 | ||||
-rw-r--r-- | libpod/info.go | 2 | ||||
-rw-r--r-- | libpod/kube.go | 12 | ||||
-rw-r--r-- | libpod/oci_internal_linux.go | 4 | ||||
-rw-r--r-- | libpod/options.go | 312 | ||||
-rw-r--r-- | libpod/runtime.go | 77 | ||||
-rw-r--r-- | libpod/runtime_ctr.go | 17 | ||||
-rw-r--r-- | libpod/runtime_img.go | 7 |
20 files changed, 395 insertions, 217 deletions
diff --git a/libpod/container.go b/libpod/container.go index 2d96b1120..9c01d2adf 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -377,6 +377,9 @@ type ContainerConfig struct { RestartRetries uint `json:"restart_retries,omitempty"` // TODO log options for log drivers + // PostConfigureNetNS needed when a user namespace is created by an OCI runtime + // if the network namespace is created before the user namespace it will be + // owned by the wrong user namespace. PostConfigureNetNS bool `json:"postConfigureNetNS"` // OCIRuntime used to create the container diff --git a/libpod/container_api.go b/libpod/container_api.go index cd020e429..abcfcb271 100644 --- a/libpod/container_api.go +++ b/libpod/container_api.go @@ -187,7 +187,7 @@ func (c *Container) StopWithTimeout(timeout uint) error { c.state.State == define.ContainerStateExited { return define.ErrCtrStopped } - defer c.newContainerEvent(events.Stop) + return c.stop(timeout) } @@ -773,6 +773,11 @@ type ContainerCheckpointOptions struct { // IgnoreRootfs tells the API to not export changes to // the container's root file-system (or to not import) IgnoreRootfs bool + // IgnoreStaticIP tells the API to ignore the IP set + // during 'podman run' with '--ip'. This is especially + // important to be able to restore a container multiple + // times with '--import --name'. + IgnoreStaticIP bool } // Checkpoint checkpoints a container diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go index aee8c4657..1b6dd829c 100644 --- a/libpod/container_inspect.go +++ b/libpod/container_inspect.go @@ -99,6 +99,7 @@ type InspectContainerData struct { ImageID string `json:"Image"` ImageName string `json:"ImageName"` Rootfs string `json:"Rootfs"` + Pod string `json:"Pod"` ResolvConfPath string `json:"ResolvConfPath"` HostnamePath string `json:"HostnamePath"` HostsPath string `json:"HostsPath"` @@ -717,6 +718,7 @@ func (c *Container) getContainerInspectData(size bool, driverData *driver.Data) ExitCommand: config.ExitCommand, Namespace: config.Namespace, Rootfs: config.Rootfs, + Pod: config.Pod, ResolvConfPath: resolvPath, HostnamePath: hostnamePath, HostsPath: hostsPath, diff --git a/libpod/container_internal.go b/libpod/container_internal.go index 83ee5640e..313f67963 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -634,19 +634,15 @@ func (c *Container) removeConmonFiles() error { return errors.Wrapf(err, "error removing container %s OOM file", c.ID()) } - // Instead of outright deleting the exit file, rename it (if it exists). - // We want to retain it so we can get the exit code of containers which - // are removed (at least until we have a workable events system) + // Remove the exit file so we don't leak memory in tmpfs exitFile := filepath.Join(c.ociRuntime.exitsDir, c.ID()) - oldExitFile := filepath.Join(c.ociRuntime.exitsDir, fmt.Sprintf("%s-old", c.ID())) if _, err := os.Stat(exitFile); err != nil { if !os.IsNotExist(err) { return errors.Wrapf(err, "error running stat on container %s exit file", c.ID()) } } else { - // Rename should replace the old exit file (if it exists) - if err := os.Rename(exitFile, oldExitFile); err != nil { - return errors.Wrapf(err, "error renaming container %s exit file", c.ID()) + if err := os.Remove(exitFile); err != nil { + return errors.Wrapf(err, "error removing container %s exit file", c.ID()) } } @@ -1112,7 +1108,13 @@ func (c *Container) stop(timeout uint) error { } // Wait until we have an exit file, and sync once we do - return c.waitForExitFileAndSync() + if err := c.waitForExitFileAndSync(); err != nil { + return err + } + + c.newContainerEvent(events.Stop) + + return nil } // Internal, non-locking function to pause a container @@ -1150,9 +1152,27 @@ func (c *Container) restartWithTimeout(ctx context.Context, timeout uint) (err e c.newContainerEvent(events.Restart) if c.state.State == define.ContainerStateRunning { + conmonPID := c.state.ConmonPID if err := c.stop(timeout); err != nil { return err } + // Old versions of conmon have a bug where they create the exit file before + // closing open file descriptors causing a race condition when restarting + // containers with open ports since we cannot bind the ports as they're not + // yet closed by conmon. + // + // Killing the old conmon PID is ~okay since it forces the FDs of old conmons + // to be closed, while it's a NOP for newer versions which should have + // exited already. + if conmonPID != 0 { + // Ignore errors from FindProcess() as conmon could already have exited. + p, err := os.FindProcess(conmonPID) + if p != nil && err == nil { + if err = p.Kill(); err != nil { + logrus.Debugf("error killing conmon process: %v", err) + } + } + } } defer func() { if err != nil { diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 6dbd53fbf..5aa4ee9a9 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -471,9 +471,9 @@ func (c *Container) setupSystemd(mounts []spec.Mount, g generate.Generator) erro return err } - g.RemoveMount("/sys/fs/cgroup") - if unified { + g.RemoveMount("/sys/fs/cgroup") + sourcePath := filepath.Join("/sys/fs/cgroup") systemdMnt := spec.Mount{ Destination: "/sys/fs/cgroup", @@ -483,31 +483,13 @@ func (c *Container) setupSystemd(mounts []spec.Mount, g generate.Generator) erro } g.AddMount(systemdMnt) } else { - // rootless containers have no write access to /sys/fs/cgroup, so don't - // add any mount into the container. - if !rootless.IsRootless() { - cgroupPath, err := c.CGroupPath() - if err != nil { - return err - } - sourcePath := filepath.Join("/sys/fs/cgroup", cgroupPath) - - systemdMnt := spec.Mount{ - Destination: "/sys/fs/cgroup", - Type: "bind", - Source: sourcePath, - Options: []string{"bind", "private"}, - } - g.AddMount(systemdMnt) - } else { - systemdMnt := spec.Mount{ - Destination: "/sys/fs/cgroup", - Type: "bind", - Source: "/sys/fs/cgroup", - Options: []string{"bind", "nodev", "noexec", "nosuid"}, - } - g.AddMount(systemdMnt) + systemdMnt := spec.Mount{ + Destination: "/sys/fs/cgroup/systemd", + Type: "bind", + Source: "/sys/fs/cgroup/systemd", + Options: []string{"bind", "nodev", "noexec", "nosuid"}, } + g.AddMount(systemdMnt) } return nil @@ -743,6 +725,14 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti return err } + // If a container is restored multiple times from an exported checkpoint with + // the help of '--import --name', the restore will fail if during 'podman run' + // a static container IP was set with '--ip'. The user can tell the restore + // process to ignore the static IP with '--ignore-static-ip' + if options.IgnoreStaticIP { + c.config.StaticIP = nil + } + // Read network configuration from checkpoint // Currently only one interface with one IP is supported. networkStatusFile, err := os.Open(filepath.Join(c.bundlePath(), "network.status")) @@ -752,7 +742,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti // TODO: This implicit restoring with or without IP depending on an // unrelated restore parameter (--name) does not seem like the // best solution. - if err == nil && options.Name == "" { + if err == nil && options.Name == "" && !options.IgnoreStaticIP { // The file with the network.status does exist. Let's restore the // container with the same IP address as during checkpointing. defer networkStatusFile.Close() diff --git a/libpod/define/errors.go b/libpod/define/errors.go index a4368a9aa..9d532263c 100644 --- a/libpod/define/errors.go +++ b/libpod/define/errors.go @@ -107,4 +107,8 @@ var ( // ErrOCIRuntimeNotFound indicates the OCI runtime attempted to invoke a command // that was not found ErrOCIRuntimeNotFound = errors.New("OCI runtime command not found error") + + // ErrConmonOutdated indicates the version of conmon found (whether via the configuration or $PATH) + // is out of date for the current podman version + ErrConmonOutdated = errors.New("outdated conmon version") ) diff --git a/libpod/events/config.go b/libpod/events/config.go index b9f01f3a5..453c64f8c 100644 --- a/libpod/events/config.go +++ b/libpod/events/config.go @@ -14,19 +14,21 @@ const ( LogFile EventerType = iota // Journald indicates journald should be used to log events Journald EventerType = iota + // Null is a no-op events logger. It does not read or write events. + Null EventerType = iota ) // Event describes the attributes of a libpod event type Event struct { // ContainerExitCode is for storing the exit code of a container which can // be used for "internal" event notification - ContainerExitCode int + ContainerExitCode int `json:",omitempty"` // ID can be for the container, image, volume, etc - ID string + ID string `json:",omitempty"` // Image used where applicable - Image string + Image string `json:",omitempty"` // Name where applicable - Name string + Name string `json:",omitempty"` // Status describes the event that occurred Status Status // Time the event occurred @@ -51,6 +53,8 @@ type Eventer interface { Write(event Event) error // Read an event from the backend Read(options ReadOptions) error + // String returns the type of event logger + String() string } // ReadOptions describe the attributes needed to read event logs diff --git a/libpod/events/events.go b/libpod/events/events.go index 2bebff162..5e828bc8a 100644 --- a/libpod/events/events.go +++ b/libpod/events/events.go @@ -16,11 +16,30 @@ var ErrNoJournaldLogging = errors.New("No support for journald logging") // String returns a string representation of EventerType func (et EventerType) String() string { - if et == LogFile { + switch et { + case LogFile: return "file" + case Journald: + return "journald" + case Null: + return "none" + default: + return "invalid" + } +} +// IsValidEventer checks if the given string is a valid eventer type. +func IsValidEventer(eventer string) bool { + switch eventer { + case LogFile.String(): + return true + case Journald.String(): + return true + case Null.String(): + return true + default: + return false } - return "journald" } // NewEvent creates a event struct and populates with diff --git a/libpod/events/events_linux.go b/libpod/events/events_linux.go index 11f309574..ffb100be8 100644 --- a/libpod/events/events_linux.go +++ b/libpod/events/events_linux.go @@ -18,8 +18,10 @@ func NewEventer(options EventerOptions) (eventer Eventer, err error) { } case strings.ToUpper(LogFile.String()): eventer = EventLogFile{options} + case strings.ToUpper(Null.String()): + eventer = NewNullEventer() default: - return eventer, errors.Errorf("unknown event logger type: %s", strings.ToUpper(options.EventerType)) + return nil, errors.Errorf("unknown event logger type: %s", strings.ToUpper(options.EventerType)) } return eventer, nil } diff --git a/libpod/events/journal_linux.go b/libpod/events/journal_linux.go index d5bce4334..7d195dc79 100644 --- a/libpod/events/journal_linux.go +++ b/libpod/events/journal_linux.go @@ -54,14 +54,17 @@ func (e EventJournalD) Read(options ReadOptions) error { if err != nil { return errors.Wrapf(err, "failed to generate event options") } - podmanJournal := sdjournal.Match{Field: "SYSLOG_IDENTIFIER", Value: "podman"} //nolint - j, err := sdjournal.NewJournal() //nolint + j, err := sdjournal.NewJournal() //nolint if err != nil { return err } - if err := j.AddMatch(podmanJournal.String()); err != nil { - return errors.Wrap(err, "failed to add filter for event log") - } + // TODO AddMatch and Seek seem to conflict + // Issue filed upstream -> https://github.com/coreos/go-systemd/issues/315 + // Leaving commented code in case upstream fixes things + //podmanJournal := sdjournal.Match{Field: "SYSLOG_IDENTIFIER", Value: "podman"} //nolint + //if err := j.AddMatch(podmanJournal.String()); err != nil { + // return errors.Wrap(err, "failed to add filter for event log") + //} if len(options.Since) == 0 && len(options.Until) == 0 && options.Stream { if err := j.SeekTail(); err != nil { return errors.Wrap(err, "failed to seek end of journal") @@ -96,6 +99,12 @@ func (e EventJournalD) Read(options ReadOptions) error { if err != nil { return err } + // TODO this keeps us from feeding the podman event parser with + // with regular journal content; it can be removed if the above + // problem with AddMatch is resolved. + if entry.Fields["PODMAN_EVENT"] == "" { + continue + } newEvent, err := newEventFromJournalEntry(entry) if err != nil { // We can't decode this event. @@ -146,3 +155,8 @@ func newEventFromJournalEntry(entry *sdjournal.JournalEntry) (*Event, error) { / } return &newEvent, nil } + +// String returns a string representation of the logger +func (e EventJournalD) String() string { + return Journald.String() +} diff --git a/libpod/events/logfile.go b/libpod/events/logfile.go index e5efc09bb..4b65b0ad0 100644 --- a/libpod/events/logfile.go +++ b/libpod/events/logfile.go @@ -55,7 +55,7 @@ func (e EventLogFile) Read(options ReadOptions) error { return err } switch event.Type { - case Image, Volume, Pod, Container: + case Image, Volume, Pod, System, Container: // no-op default: return errors.Errorf("event type %s is not valid in %s", event.Type.String(), e.options.LogFilePath) @@ -71,3 +71,8 @@ func (e EventLogFile) Read(options ReadOptions) error { close(options.EventChannel) return nil } + +// String returns a string representation of the logger +func (e EventLogFile) String() string { + return LogFile.String() +} diff --git a/libpod/events/nullout.go b/libpod/events/nullout.go index b11afcf80..f3b36e609 100644 --- a/libpod/events/nullout.go +++ b/libpod/events/nullout.go @@ -17,6 +17,10 @@ func (e EventToNull) Read(options ReadOptions) error { // NewNullEventer returns a new null eventer. You should only do this for // the purposes on internal libpod testing. func NewNullEventer() Eventer { - e := EventToNull{} - return e + return EventToNull{} +} + +// String returns a string representation of the logger +func (e EventToNull) String() string { + return "none" } diff --git a/libpod/image/search.go b/libpod/image/search.go index e557431c6..82ef4f75a 100644 --- a/libpod/image/search.go +++ b/libpod/image/search.go @@ -162,8 +162,11 @@ func searchImageInRegistry(term string, registry string, options SearchOptions) if len(results) < limit { limit = len(results) } - if options.Limit != 0 && options.Limit < len(results) { - limit = options.Limit + if options.Limit != 0 { + limit = len(results) + if options.Limit < len(results) { + limit = options.Limit + } } paramsArr := []SearchResult{} diff --git a/libpod/info.go b/libpod/info.go index 4a89fa648..9ab6f7e52 100644 --- a/libpod/info.go +++ b/libpod/info.go @@ -102,7 +102,7 @@ func (r *Runtime) hostInfo() (map[string]interface{}, error) { return nil, errors.Wrapf(err, "error getting hostname") } info["hostname"] = host - + info["eventlogger"] = r.eventer.String() return info, nil } diff --git a/libpod/kube.go b/libpod/kube.go index 084a3df4f..d0e7baf95 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -406,18 +406,26 @@ func determineCapAddDropFromCapabilities(defaultCaps, containerCaps []string) *v drop []v1.Capability add []v1.Capability ) + dedupDrop := make(map[string]bool) + dedupAdd := make(map[string]bool) // Find caps in the defaultCaps but not in the container's // those indicate a dropped cap for _, capability := range defaultCaps { if !util.StringInSlice(capability, containerCaps) { - drop = append(drop, v1.Capability(capability)) + if _, ok := dedupDrop[capability]; !ok { + drop = append(drop, v1.Capability(capability)) + dedupDrop[capability] = true + } } } // Find caps in the container but not in the defaults; those indicate // an added cap for _, capability := range containerCaps { if !util.StringInSlice(capability, defaultCaps) { - add = append(add, v1.Capability(capability)) + if _, ok := dedupAdd[capability]; !ok { + add = append(add, v1.Capability(capability)) + dedupAdd[capability] = true + } } } diff --git a/libpod/oci_internal_linux.go b/libpod/oci_internal_linux.go index 0bcd021db..52cebefab 100644 --- a/libpod/oci_internal_linux.go +++ b/libpod/oci_internal_linux.go @@ -278,6 +278,10 @@ func (r *OCIRuntime) sharedConmonArgs(ctr *Container, cuuid, bundlePath, pidPath // No case here should happen except JSONLogging, but keep this here in case the options are extended logrus.Errorf("%s logging specified but not supported. Choosing k8s-file logging instead", ctr.LogDriver()) fallthrough + case "": + // to get here, either a user would specify `--log-driver ""`, or this came from another place in libpod + // since the former case is obscure, and the latter case isn't an error, let's silently fallthrough + fallthrough case KubernetesLogging: logDriver = fmt.Sprintf("%s:%s", KubernetesLogging, logPath) } diff --git a/libpod/options.go b/libpod/options.go index 81d3aa64f..7fbd0016a 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -8,7 +8,8 @@ import ( "syscall" "github.com/containers/image/manifest" - config2 "github.com/containers/libpod/libpod/define" + "github.com/containers/libpod/libpod/define" + "github.com/containers/libpod/libpod/events" "github.com/containers/libpod/pkg/namespaces" "github.com/containers/libpod/pkg/rootless" "github.com/containers/libpod/pkg/util" @@ -20,7 +21,7 @@ import ( var ( nameRegex = regexp.MustCompile("^[a-zA-Z0-9][a-zA-Z0-9_.-]*$") - regexError = errors.Wrapf(config2.ErrInvalidArg, "names must match [a-zA-Z0-9][a-zA-Z0-9_.-]*") + regexError = errors.Wrapf(define.ErrInvalidArg, "names must match [a-zA-Z0-9][a-zA-Z0-9_.-]*") ) // Runtime Creation Options @@ -31,7 +32,7 @@ var ( func WithStorageConfig(config storage.StoreOptions) RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } setField := false @@ -105,7 +106,7 @@ func WithStorageConfig(config storage.StoreOptions) RuntimeOption { func WithDefaultTransport(defaultTransport string) RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } rt.config.ImageDefaultTransport = defaultTransport @@ -121,7 +122,7 @@ func WithDefaultTransport(defaultTransport string) RuntimeOption { func WithSignaturePolicy(path string) RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } rt.config.SignaturePolicyPath = path @@ -137,11 +138,11 @@ func WithSignaturePolicy(path string) RuntimeOption { func WithStateType(storeType RuntimeStateStore) RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } if storeType == InvalidStateStore { - return errors.Wrapf(config2.ErrInvalidArg, "must provide a valid state store type") + return errors.Wrapf(define.ErrInvalidArg, "must provide a valid state store type") } rt.config.StateType = storeType @@ -154,11 +155,11 @@ func WithStateType(storeType RuntimeStateStore) RuntimeOption { func WithOCIRuntime(runtime string) RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } if runtime == "" { - return errors.Wrapf(config2.ErrInvalidArg, "must provide a valid path") + return errors.Wrapf(define.ErrInvalidArg, "must provide a valid path") } rt.config.OCIRuntime = runtime @@ -173,11 +174,11 @@ func WithOCIRuntime(runtime string) RuntimeOption { func WithConmonPath(path string) RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } if path == "" { - return errors.Wrapf(config2.ErrInvalidArg, "must provide a valid path") + return errors.Wrapf(define.ErrInvalidArg, "must provide a valid path") } rt.config.ConmonPath = []string{path} @@ -190,7 +191,7 @@ func WithConmonPath(path string) RuntimeOption { func WithConmonEnv(environment []string) RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } rt.config.ConmonEnvVars = make([]string, len(environment)) @@ -205,7 +206,7 @@ func WithConmonEnv(environment []string) RuntimeOption { func WithNetworkCmdPath(path string) RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } rt.config.NetworkCmdPath = path @@ -220,11 +221,11 @@ func WithNetworkCmdPath(path string) RuntimeOption { func WithCgroupManager(manager string) RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } if manager != CgroupfsCgroupsManager && manager != SystemdCgroupsManager { - return errors.Wrapf(config2.ErrInvalidArg, "CGroup manager must be one of %s and %s", + return errors.Wrapf(define.ErrInvalidArg, "CGroup manager must be one of %s and %s", CgroupfsCgroupsManager, SystemdCgroupsManager) } @@ -239,7 +240,7 @@ func WithCgroupManager(manager string) RuntimeOption { func WithStaticDir(dir string) RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } rt.config.StaticDir = dir @@ -253,12 +254,12 @@ func WithStaticDir(dir string) RuntimeOption { func WithHooksDir(hooksDirs ...string) RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } for _, hooksDir := range hooksDirs { if hooksDir == "" { - return errors.Wrap(config2.ErrInvalidArg, "empty-string hook directories are not supported") + return errors.Wrap(define.ErrInvalidArg, "empty-string hook directories are not supported") } } @@ -274,11 +275,11 @@ func WithHooksDir(hooksDirs ...string) RuntimeOption { func WithDefaultMountsFile(mountsFile string) RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } if mountsFile == "" { - return config2.ErrInvalidArg + return define.ErrInvalidArg } rt.config.DefaultMountsFile = mountsFile return nil @@ -291,7 +292,7 @@ func WithDefaultMountsFile(mountsFile string) RuntimeOption { func WithTmpDir(dir string) RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } rt.config.TmpDir = dir rt.configuredFrom.libpodTmpDirSet = true @@ -314,7 +315,7 @@ func WithNoStore() RuntimeOption { func WithMaxLogSize(limit int64) RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } rt.config.MaxLogSize = limit @@ -328,7 +329,7 @@ func WithMaxLogSize(limit int64) RuntimeOption { func WithNoPivotRoot() RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } rt.config.NoPivotRoot = true @@ -341,7 +342,7 @@ func WithNoPivotRoot() RuntimeOption { func WithCNIConfigDir(dir string) RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } rt.config.CNIConfigDir = dir @@ -354,7 +355,7 @@ func WithCNIConfigDir(dir string) RuntimeOption { func WithCNIPluginDir(dir string) RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } rt.config.CNIPluginDir = []string{dir} @@ -374,7 +375,7 @@ func WithCNIPluginDir(dir string) RuntimeOption { func WithNamespace(ns string) RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } rt.config.Namespace = ns @@ -390,7 +391,7 @@ func WithNamespace(ns string) RuntimeOption { func WithVolumePath(volPath string) RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } rt.config.VolumePath = volPath @@ -408,7 +409,7 @@ func WithVolumePath(volPath string) RuntimeOption { func WithDefaultInfraImage(img string) RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } rt.config.InfraImage = img @@ -422,7 +423,7 @@ func WithDefaultInfraImage(img string) RuntimeOption { func WithDefaultInfraCommand(cmd string) RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } rt.config.InfraCommand = cmd @@ -438,7 +439,7 @@ func WithDefaultInfraCommand(cmd string) RuntimeOption { func WithRenumber() RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } rt.doRenumber = true @@ -453,7 +454,7 @@ func WithRenumber() RuntimeOption { func WithMigrate() RuntimeOption { return func(rt *Runtime) error { if rt.valid { - return config2.ErrRuntimeFinalized + return define.ErrRuntimeFinalized } rt.doMigrate = true @@ -462,13 +463,32 @@ func WithMigrate() RuntimeOption { } } +// WithEventsLogger sets the events backend to use. +// Currently supported values are "file" for file backend and "journald" for +// journald backend. +func WithEventsLogger(logger string) RuntimeOption { + return func(rt *Runtime) error { + if rt.valid { + return define.ErrRuntimeFinalized + } + + if !events.IsValidEventer(logger) { + return errors.Wrapf(define.ErrInvalidArg, "%q is not a valid events backend", logger) + } + + rt.config.EventsLogger = logger + + return nil + } +} + // Container Creation Options // WithShmDir sets the directory that should be mounted on /dev/shm. func WithShmDir(dir string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } ctr.config.ShmDir = dir @@ -480,7 +500,7 @@ func WithShmDir(dir string) CtrCreateOption { func WithSystemd() CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } ctr.config.Systemd = true @@ -492,7 +512,7 @@ func WithSystemd() CtrCreateOption { func WithShmSize(size int64) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } ctr.config.ShmSize = size @@ -504,7 +524,7 @@ func WithShmSize(size int64) CtrCreateOption { func WithPrivileged(privileged bool) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } ctr.config.Privileged = privileged @@ -516,7 +536,7 @@ func WithPrivileged(privileged bool) CtrCreateOption { func WithSecLabels(labelOpts []string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } ctr.config.LabelOpts = labelOpts return nil @@ -528,7 +548,7 @@ func WithSecLabels(labelOpts []string) CtrCreateOption { func WithUser(user string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } ctr.config.User = user @@ -544,14 +564,14 @@ func WithUser(user string) CtrCreateOption { func WithRootFSFromImage(imageID string, imageName string, useImageVolumes bool) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if ctr.config.RootfsImageID != "" || ctr.config.RootfsImageName != "" { - return errors.Wrapf(config2.ErrInvalidArg, "container already configured with root filesystem") + return errors.Wrapf(define.ErrInvalidArg, "container already configured with root filesystem") } if ctr.config.Rootfs != "" { - return errors.Wrapf(config2.ErrInvalidArg, "cannot set both an image ID and a rootfs for a container") + return errors.Wrapf(define.ErrInvalidArg, "cannot set both an image ID and a rootfs for a container") } ctr.config.RootfsImageID = imageID @@ -566,7 +586,7 @@ func WithRootFSFromImage(imageID string, imageName string, useImageVolumes bool) func WithStdin() CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } ctr.config.Stdin = true @@ -582,11 +602,11 @@ func WithStdin() CtrCreateOption { func (r *Runtime) WithPod(pod *Pod) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if pod == nil { - return config2.ErrInvalidArg + return define.ErrInvalidArg } ctr.config.Pod = pod.ID() @@ -599,7 +619,7 @@ func (r *Runtime) WithPod(pod *Pod) CtrCreateOption { func WithLabels(labels map[string]string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } ctr.config.Labels = make(map[string]string) @@ -615,7 +635,7 @@ func WithLabels(labels map[string]string) CtrCreateOption { func WithName(name string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } // Check the name against a regex @@ -633,13 +653,13 @@ func WithName(name string) CtrCreateOption { func WithStopSignal(signal syscall.Signal) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if signal == 0 { - return errors.Wrapf(config2.ErrInvalidArg, "stop signal cannot be 0") + return errors.Wrapf(define.ErrInvalidArg, "stop signal cannot be 0") } else if signal > 64 { - return errors.Wrapf(config2.ErrInvalidArg, "stop signal cannot be greater than 64 (SIGRTMAX)") + return errors.Wrapf(define.ErrInvalidArg, "stop signal cannot be greater than 64 (SIGRTMAX)") } ctr.config.StopSignal = uint(signal) @@ -653,7 +673,7 @@ func WithStopSignal(signal syscall.Signal) CtrCreateOption { func WithStopTimeout(timeout uint) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } ctr.config.StopTimeout = timeout @@ -666,7 +686,7 @@ func WithStopTimeout(timeout uint) CtrCreateOption { func WithIDMappings(idmappings storage.IDMappingOptions) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } ctr.config.IDMappings = idmappings @@ -678,7 +698,7 @@ func WithIDMappings(idmappings storage.IDMappingOptions) CtrCreateOption { func WithExitCommand(exitCommand []string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } ctr.config.ExitCommand = append(exitCommand, ctr.ID()) @@ -691,7 +711,7 @@ func WithExitCommand(exitCommand []string) CtrCreateOption { func WithUTSNSFromPod(p *Pod) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if err := validPodNSOption(p, ctr.config.Pod); err != nil { @@ -715,19 +735,19 @@ func WithUTSNSFromPod(p *Pod) CtrCreateOption { func WithIPCNSFrom(nsCtr *Container) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if !nsCtr.valid { - return config2.ErrCtrRemoved + return define.ErrCtrRemoved } if nsCtr.ID() == ctr.ID() { - return errors.Wrapf(config2.ErrInvalidArg, "must specify another container") + return errors.Wrapf(define.ErrInvalidArg, "must specify another container") } if ctr.config.Pod != "" && nsCtr.config.Pod != ctr.config.Pod { - return errors.Wrapf(config2.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID()) + return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID()) } ctr.config.IPCNsCtr = nsCtr.ID() @@ -743,19 +763,19 @@ func WithIPCNSFrom(nsCtr *Container) CtrCreateOption { func WithMountNSFrom(nsCtr *Container) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if !nsCtr.valid { - return config2.ErrCtrRemoved + return define.ErrCtrRemoved } if nsCtr.ID() == ctr.ID() { - return errors.Wrapf(config2.ErrInvalidArg, "must specify another container") + return errors.Wrapf(define.ErrInvalidArg, "must specify another container") } if ctr.config.Pod != "" && nsCtr.config.Pod != ctr.config.Pod { - return errors.Wrapf(config2.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID()) + return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID()) } ctr.config.MountNsCtr = nsCtr.ID() @@ -771,23 +791,23 @@ func WithMountNSFrom(nsCtr *Container) CtrCreateOption { func WithNetNSFrom(nsCtr *Container) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if !nsCtr.valid { - return config2.ErrCtrRemoved + return define.ErrCtrRemoved } if nsCtr.ID() == ctr.ID() { - return errors.Wrapf(config2.ErrInvalidArg, "must specify another container") + return errors.Wrapf(define.ErrInvalidArg, "must specify another container") } if ctr.config.CreateNetNS { - return errors.Wrapf(config2.ErrInvalidArg, "cannot join another container's net ns as we are making a new net ns") + return errors.Wrapf(define.ErrInvalidArg, "cannot join another container's net ns as we are making a new net ns") } if ctr.config.Pod != "" && nsCtr.config.Pod != ctr.config.Pod { - return errors.Wrapf(config2.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID()) + return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID()) } ctr.config.NetNsCtr = nsCtr.ID() @@ -803,19 +823,19 @@ func WithNetNSFrom(nsCtr *Container) CtrCreateOption { func WithPIDNSFrom(nsCtr *Container) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if !nsCtr.valid { - return config2.ErrCtrRemoved + return define.ErrCtrRemoved } if nsCtr.ID() == ctr.ID() { - return errors.Wrapf(config2.ErrInvalidArg, "must specify another container") + return errors.Wrapf(define.ErrInvalidArg, "must specify another container") } if ctr.config.Pod != "" && nsCtr.config.Pod != ctr.config.Pod { - return errors.Wrapf(config2.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID()) + return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID()) } ctr.config.PIDNsCtr = nsCtr.ID() @@ -831,19 +851,19 @@ func WithPIDNSFrom(nsCtr *Container) CtrCreateOption { func WithUserNSFrom(nsCtr *Container) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if !nsCtr.valid { - return config2.ErrCtrRemoved + return define.ErrCtrRemoved } if nsCtr.ID() == ctr.ID() { - return errors.Wrapf(config2.ErrInvalidArg, "must specify another container") + return errors.Wrapf(define.ErrInvalidArg, "must specify another container") } if ctr.config.Pod != "" && nsCtr.config.Pod != ctr.config.Pod { - return errors.Wrapf(config2.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID()) + return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID()) } ctr.config.UserNsCtr = nsCtr.ID() @@ -860,19 +880,19 @@ func WithUserNSFrom(nsCtr *Container) CtrCreateOption { func WithUTSNSFrom(nsCtr *Container) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if !nsCtr.valid { - return config2.ErrCtrRemoved + return define.ErrCtrRemoved } if nsCtr.ID() == ctr.ID() { - return errors.Wrapf(config2.ErrInvalidArg, "must specify another container") + return errors.Wrapf(define.ErrInvalidArg, "must specify another container") } if ctr.config.Pod != "" && nsCtr.config.Pod != ctr.config.Pod { - return errors.Wrapf(config2.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID()) + return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID()) } ctr.config.UTSNsCtr = nsCtr.ID() @@ -888,19 +908,19 @@ func WithUTSNSFrom(nsCtr *Container) CtrCreateOption { func WithCgroupNSFrom(nsCtr *Container) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if !nsCtr.valid { - return config2.ErrCtrRemoved + return define.ErrCtrRemoved } if nsCtr.ID() == ctr.ID() { - return errors.Wrapf(config2.ErrInvalidArg, "must specify another container") + return errors.Wrapf(define.ErrInvalidArg, "must specify another container") } if ctr.config.Pod != "" && nsCtr.config.Pod != ctr.config.Pod { - return errors.Wrapf(config2.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID()) + return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, nsCtr.ID()) } ctr.config.CgroupNsCtr = nsCtr.ID() @@ -914,22 +934,22 @@ func WithCgroupNSFrom(nsCtr *Container) CtrCreateOption { func WithDependencyCtrs(ctrs []*Container) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } deps := make([]string, 0, len(ctrs)) for _, dep := range ctrs { if !dep.valid { - return errors.Wrapf(config2.ErrCtrRemoved, "container %s is not valid", dep.ID()) + return errors.Wrapf(define.ErrCtrRemoved, "container %s is not valid", dep.ID()) } if dep.ID() == ctr.ID() { - return errors.Wrapf(config2.ErrInvalidArg, "must specify another container") + return errors.Wrapf(define.ErrInvalidArg, "must specify another container") } if ctr.config.Pod != "" && dep.config.Pod != ctr.config.Pod { - return errors.Wrapf(config2.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, dep.ID()) + return errors.Wrapf(define.ErrInvalidArg, "container has joined pod %s and dependency container %s is not a member of the pod", ctr.config.Pod, dep.ID()) } deps = append(deps, dep.ID()) @@ -948,11 +968,11 @@ func WithDependencyCtrs(ctrs []*Container) CtrCreateOption { func WithNetNS(portMappings []ocicni.PortMapping, postConfigureNetNS bool, netmode string, networks []string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if ctr.config.NetNsCtr != "" { - return errors.Wrapf(config2.ErrInvalidArg, "container is already set to join another container's net ns, cannot create a new net ns") + return errors.Wrapf(define.ErrInvalidArg, "container is already set to join another container's net ns, cannot create a new net ns") } ctr.config.PostConfigureNetNS = postConfigureNetNS @@ -973,15 +993,15 @@ func WithNetNS(portMappings []ocicni.PortMapping, postConfigureNetNS bool, netmo func WithStaticIP(ip net.IP) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if !ctr.config.CreateNetNS { - return errors.Wrapf(config2.ErrInvalidArg, "cannot set a static IP if the container is not creating a network namespace") + return errors.Wrapf(define.ErrInvalidArg, "cannot set a static IP if the container is not creating a network namespace") } if len(ctr.config.Networks) != 0 { - return errors.Wrapf(config2.ErrInvalidArg, "cannot set a static IP if joining additional CNI networks") + return errors.Wrapf(define.ErrInvalidArg, "cannot set a static IP if joining additional CNI networks") } ctr.config.StaticIP = ip @@ -994,15 +1014,15 @@ func WithStaticIP(ip net.IP) CtrCreateOption { func WithLogDriver(driver string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } switch driver { case "": - return errors.Wrapf(config2.ErrInvalidArg, "log driver must be set") + return errors.Wrapf(define.ErrInvalidArg, "log driver must be set") case JournaldLogging, KubernetesLogging, JSONLogging: break default: - return errors.Wrapf(config2.ErrInvalidArg, "invalid log driver") + return errors.Wrapf(define.ErrInvalidArg, "invalid log driver") } ctr.config.LogDriver = driver @@ -1015,10 +1035,10 @@ func WithLogDriver(driver string) CtrCreateOption { func WithLogPath(path string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if path == "" { - return errors.Wrapf(config2.ErrInvalidArg, "log path must be set") + return errors.Wrapf(define.ErrInvalidArg, "log path must be set") } ctr.config.LogPath = path @@ -1031,11 +1051,11 @@ func WithLogPath(path string) CtrCreateOption { func WithCgroupParent(parent string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if parent == "" { - return errors.Wrapf(config2.ErrInvalidArg, "cgroup parent cannot be empty") + return errors.Wrapf(define.ErrInvalidArg, "cgroup parent cannot be empty") } ctr.config.CgroupParent = parent @@ -1048,10 +1068,10 @@ func WithCgroupParent(parent string) CtrCreateOption { func WithDNSSearch(searchDomains []string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if ctr.config.UseImageResolvConf { - return errors.Wrapf(config2.ErrInvalidArg, "cannot add DNS search domains if container will not create /etc/resolv.conf") + return errors.Wrapf(define.ErrInvalidArg, "cannot add DNS search domains if container will not create /etc/resolv.conf") } ctr.config.DNSSearch = searchDomains return nil @@ -1062,16 +1082,16 @@ func WithDNSSearch(searchDomains []string) CtrCreateOption { func WithDNS(dnsServers []string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if ctr.config.UseImageResolvConf { - return errors.Wrapf(config2.ErrInvalidArg, "cannot add DNS servers if container will not create /etc/resolv.conf") + return errors.Wrapf(define.ErrInvalidArg, "cannot add DNS servers if container will not create /etc/resolv.conf") } var dns []net.IP for _, i := range dnsServers { result := net.ParseIP(i) if result == nil { - return errors.Wrapf(config2.ErrInvalidArg, "invalid IP address %s", i) + return errors.Wrapf(define.ErrInvalidArg, "invalid IP address %s", i) } dns = append(dns, result) } @@ -1084,10 +1104,10 @@ func WithDNS(dnsServers []string) CtrCreateOption { func WithDNSOption(dnsOptions []string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if ctr.config.UseImageResolvConf { - return errors.Wrapf(config2.ErrInvalidArg, "cannot add DNS options if container will not create /etc/resolv.conf") + return errors.Wrapf(define.ErrInvalidArg, "cannot add DNS options if container will not create /etc/resolv.conf") } ctr.config.DNSOption = dnsOptions return nil @@ -1098,11 +1118,11 @@ func WithDNSOption(dnsOptions []string) CtrCreateOption { func WithHosts(hosts []string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if ctr.config.UseImageHosts { - return errors.Wrapf(config2.ErrInvalidArg, "cannot add hosts if container will not create /etc/hosts") + return errors.Wrapf(define.ErrInvalidArg, "cannot add hosts if container will not create /etc/hosts") } ctr.config.HostAdd = hosts @@ -1115,7 +1135,7 @@ func WithHosts(hosts []string) CtrCreateOption { func WithConmonPidFile(path string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } ctr.config.ConmonPidFile = path return nil @@ -1127,7 +1147,7 @@ func WithConmonPidFile(path string) CtrCreateOption { func WithGroups(groups []string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } ctr.config.Groups = groups return nil @@ -1145,11 +1165,11 @@ func WithGroups(groups []string) CtrCreateOption { func WithUserVolumes(volumes []string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if volumes == nil { - return config2.ErrInvalidArg + return define.ErrInvalidArg } ctr.config.UserVolumes = make([]string, 0, len(volumes)) @@ -1166,7 +1186,7 @@ func WithUserVolumes(volumes []string) CtrCreateOption { func WithEntrypoint(entrypoint []string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } ctr.config.Entrypoint = make([]string, 0, len(entrypoint)) @@ -1183,7 +1203,7 @@ func WithEntrypoint(entrypoint []string) CtrCreateOption { func WithCommand(command []string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } ctr.config.Command = make([]string, 0, len(command)) @@ -1197,13 +1217,13 @@ func WithCommand(command []string) CtrCreateOption { func WithRootFS(rootfs string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if _, err := os.Stat(rootfs); err != nil { return errors.Wrapf(err, "error checking path %q", rootfs) } if ctr.config.RootfsImageID != "" { - return errors.Wrapf(config2.ErrInvalidArg, "cannot set both an image ID and a rootfs for a container") + return errors.Wrapf(define.ErrInvalidArg, "cannot set both an image ID and a rootfs for a container") } ctr.config.Rootfs = rootfs return nil @@ -1217,7 +1237,7 @@ func WithRootFS(rootfs string) CtrCreateOption { func WithCtrNamespace(ns string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } ctr.config.Namespace = ns @@ -1231,13 +1251,13 @@ func WithCtrNamespace(ns string) CtrCreateOption { func WithUseImageResolvConf() CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if len(ctr.config.DNSServer) != 0 || len(ctr.config.DNSSearch) != 0 || len(ctr.config.DNSOption) != 0 { - return errors.Wrapf(config2.ErrInvalidArg, "not creating resolv.conf conflicts with DNS options") + return errors.Wrapf(define.ErrInvalidArg, "not creating resolv.conf conflicts with DNS options") } ctr.config.UseImageResolvConf = true @@ -1251,11 +1271,11 @@ func WithUseImageResolvConf() CtrCreateOption { func WithUseImageHosts() CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } if len(ctr.config.HostAdd) != 0 { - return errors.Wrapf(config2.ErrInvalidArg, "not creating /etc/hosts conflicts with adding to the hosts file") + return errors.Wrapf(define.ErrInvalidArg, "not creating /etc/hosts conflicts with adding to the hosts file") } ctr.config.UseImageHosts = true @@ -1270,14 +1290,14 @@ func WithUseImageHosts() CtrCreateOption { func WithRestartPolicy(policy string) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } switch policy { case RestartPolicyNone, RestartPolicyNo, RestartPolicyOnFailure, RestartPolicyAlways: ctr.config.RestartPolicy = policy default: - return errors.Wrapf(config2.ErrInvalidArg, "%q is not a valid restart policy", policy) + return errors.Wrapf(define.ErrInvalidArg, "%q is not a valid restart policy", policy) } return nil @@ -1290,7 +1310,7 @@ func WithRestartPolicy(policy string) CtrCreateOption { func WithRestartRetries(tries uint) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } ctr.config.RestartRetries = tries @@ -1304,7 +1324,7 @@ func WithRestartRetries(tries uint) CtrCreateOption { func withIsInfra() CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } ctr.config.IsInfra = true @@ -1317,7 +1337,7 @@ func withIsInfra() CtrCreateOption { func WithNamedVolumes(volumes []*ContainerNamedVolume) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } destinations := make(map[string]bool) @@ -1327,7 +1347,7 @@ func WithNamedVolumes(volumes []*ContainerNamedVolume) CtrCreateOption { // If they don't we will automatically create them. if _, ok := destinations[vol.Dest]; ok { - return errors.Wrapf(config2.ErrInvalidArg, "two volumes found with destination %s", vol.Dest) + return errors.Wrapf(define.ErrInvalidArg, "two volumes found with destination %s", vol.Dest) } destinations[vol.Dest] = true @@ -1348,7 +1368,7 @@ func WithNamedVolumes(volumes []*ContainerNamedVolume) CtrCreateOption { func WithVolumeName(name string) VolumeCreateOption { return func(volume *Volume) error { if volume.valid { - return config2.ErrVolumeFinalized + return define.ErrVolumeFinalized } // Check the name against a regex @@ -1365,7 +1385,7 @@ func WithVolumeName(name string) VolumeCreateOption { func WithVolumeLabels(labels map[string]string) VolumeCreateOption { return func(volume *Volume) error { if volume.valid { - return config2.ErrVolumeFinalized + return define.ErrVolumeFinalized } volume.config.Labels = make(map[string]string) @@ -1381,7 +1401,7 @@ func WithVolumeLabels(labels map[string]string) VolumeCreateOption { func WithVolumeDriver(driver string) VolumeCreateOption { return func(volume *Volume) error { if volume.valid { - return config2.ErrVolumeFinalized + return define.ErrVolumeFinalized } volume.config.Driver = driver @@ -1394,7 +1414,7 @@ func WithVolumeDriver(driver string) VolumeCreateOption { func WithVolumeOptions(options map[string]string) VolumeCreateOption { return func(volume *Volume) error { if volume.valid { - return config2.ErrVolumeFinalized + return define.ErrVolumeFinalized } volume.config.Options = make(map[string]string) @@ -1410,7 +1430,7 @@ func WithVolumeOptions(options map[string]string) VolumeCreateOption { func WithVolumeUID(uid int) VolumeCreateOption { return func(volume *Volume) error { if volume.valid { - return config2.ErrVolumeFinalized + return define.ErrVolumeFinalized } volume.config.UID = uid @@ -1423,7 +1443,7 @@ func WithVolumeUID(uid int) VolumeCreateOption { func WithVolumeGID(gid int) VolumeCreateOption { return func(volume *Volume) error { if volume.valid { - return config2.ErrVolumeFinalized + return define.ErrVolumeFinalized } volume.config.GID = gid @@ -1439,7 +1459,7 @@ func WithVolumeGID(gid int) VolumeCreateOption { func withSetCtrSpecific() VolumeCreateOption { return func(volume *Volume) error { if volume.valid { - return config2.ErrVolumeFinalized + return define.ErrVolumeFinalized } volume.config.IsCtrSpecific = true @@ -1454,7 +1474,7 @@ func withSetCtrSpecific() VolumeCreateOption { func WithPodName(name string) PodCreateOption { return func(pod *Pod) error { if pod.valid { - return config2.ErrPodFinalized + return define.ErrPodFinalized } // Check the name against a regex @@ -1472,7 +1492,7 @@ func WithPodName(name string) PodCreateOption { func WithPodLabels(labels map[string]string) PodCreateOption { return func(pod *Pod) error { if pod.valid { - return config2.ErrPodFinalized + return define.ErrPodFinalized } pod.config.Labels = make(map[string]string) @@ -1488,7 +1508,7 @@ func WithPodLabels(labels map[string]string) PodCreateOption { func WithPodCgroupParent(path string) PodCreateOption { return func(pod *Pod) error { if pod.valid { - return config2.ErrPodFinalized + return define.ErrPodFinalized } pod.config.CgroupParent = path @@ -1504,7 +1524,7 @@ func WithPodCgroupParent(path string) PodCreateOption { func WithPodCgroups() PodCreateOption { return func(pod *Pod) error { if pod.valid { - return config2.ErrPodFinalized + return define.ErrPodFinalized } pod.config.UsePodCgroup = true @@ -1521,7 +1541,7 @@ func WithPodCgroups() PodCreateOption { func WithPodNamespace(ns string) PodCreateOption { return func(pod *Pod) error { if pod.valid { - return config2.ErrPodFinalized + return define.ErrPodFinalized } pod.config.Namespace = ns @@ -1537,7 +1557,7 @@ func WithPodNamespace(ns string) PodCreateOption { func WithPodIPC() PodCreateOption { return func(pod *Pod) error { if pod.valid { - return config2.ErrPodFinalized + return define.ErrPodFinalized } pod.config.UsePodIPC = true @@ -1553,7 +1573,7 @@ func WithPodIPC() PodCreateOption { func WithPodNet() PodCreateOption { return func(pod *Pod) error { if pod.valid { - return config2.ErrPodFinalized + return define.ErrPodFinalized } pod.config.UsePodNet = true @@ -1571,7 +1591,7 @@ func WithPodNet() PodCreateOption { func WithPodMount() PodCreateOption { return func(pod *Pod) error { if pod.valid { - return config2.ErrPodFinalized + return define.ErrPodFinalized } pod.config.UsePodMount = true @@ -1589,7 +1609,7 @@ func WithPodMount() PodCreateOption { func WithPodUser() PodCreateOption { return func(pod *Pod) error { if pod.valid { - return config2.ErrPodFinalized + return define.ErrPodFinalized } pod.config.UsePodUser = true @@ -1605,7 +1625,7 @@ func WithPodUser() PodCreateOption { func WithPodPID() PodCreateOption { return func(pod *Pod) error { if pod.valid { - return config2.ErrPodFinalized + return define.ErrPodFinalized } pod.config.UsePodPID = true @@ -1621,7 +1641,7 @@ func WithPodPID() PodCreateOption { func WithPodUTS() PodCreateOption { return func(pod *Pod) error { if pod.valid { - return config2.ErrPodFinalized + return define.ErrPodFinalized } pod.config.UsePodUTS = true @@ -1634,7 +1654,7 @@ func WithPodUTS() PodCreateOption { func WithInfraContainer() PodCreateOption { return func(pod *Pod) error { if pod.valid { - return config2.ErrPodFinalized + return define.ErrPodFinalized } pod.config.InfraContainer.HasInfraContainer = true @@ -1647,7 +1667,7 @@ func WithInfraContainer() PodCreateOption { func WithInfraContainerPorts(bindings []ocicni.PortMapping) PodCreateOption { return func(pod *Pod) error { if pod.valid { - return config2.ErrPodFinalized + return define.ErrPodFinalized } pod.config.InfraContainer.PortBindings = bindings return nil @@ -1658,7 +1678,7 @@ func WithInfraContainerPorts(bindings []ocicni.PortMapping) PodCreateOption { func WithHealthCheck(healthCheck *manifest.Schema2HealthConfig) CtrCreateOption { return func(ctr *Container) error { if ctr.valid { - return config2.ErrCtrFinalized + return define.ErrCtrFinalized } ctr.config.HealthCheckConfig = healthCheck return nil diff --git a/libpod/runtime.go b/libpod/runtime.go index ffdbc32f1..83799a52b 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -1,6 +1,7 @@ package libpod import ( + "bytes" "context" "fmt" "io/ioutil" @@ -8,6 +9,8 @@ import ( "os/exec" "os/user" "path/filepath" + "regexp" + "strconv" "strings" "sync" "syscall" @@ -52,7 +55,7 @@ const ( var ( // InstallPrefix is the prefix where podman will be installed. // It can be overridden at build time. - installPrefix = "/usr/local" + installPrefix = "/usr" // EtcDir is the sysconfdir where podman should look for system config files. // It can be overridden at build time. etcDir = "/etc" @@ -328,16 +331,19 @@ func defaultRuntimeConfig() (RuntimeConfig, error) { }, nil } -// SetXdgRuntimeDir ensures the XDG_RUNTIME_DIR env variable is set -// containers/image uses XDG_RUNTIME_DIR to locate the auth file. -// It internally calls EnableLinger() so that the user's processes are not +// SetXdgDirs ensures the XDG_RUNTIME_DIR env and XDG_CONFIG_HOME variables are set. +// containers/image uses XDG_RUNTIME_DIR to locate the auth file, XDG_CONFIG_HOME is +// use for the libpod.conf configuration file. +// SetXdgDirs internally calls EnableLinger() so that the user's processes are not // killed once the session is terminated. EnableLinger() also attempts to // get the runtime directory when XDG_RUNTIME_DIR is not specified. -func SetXdgRuntimeDir() error { +// This function should only be called when running rootless. +func SetXdgDirs() error { if !rootless.IsRootless() { return nil } + // Setup XDG_RUNTIME_DIR runtimeDir := os.Getenv("XDG_RUNTIME_DIR") runtimeDirLinger, err := rootless.EnableLinger() @@ -365,6 +371,16 @@ func SetXdgRuntimeDir() error { if err := os.Setenv("XDG_RUNTIME_DIR", runtimeDir); err != nil { return errors.Wrapf(err, "cannot set XDG_RUNTIME_DIR") } + + // Setup XDG_CONFIG_HOME + if cfgHomeDir := os.Getenv("XDG_CONFIG_HOME"); cfgHomeDir == "" { + if cfgHomeDir, err = util.GetRootlessConfigHomeDir(); err != nil { + return err + } + if err = os.Setenv("XDG_CONFIG_HOME", cfgHomeDir); err != nil { + return errors.Wrapf(err, "cannot set XDG_CONFIG_HOME") + } + } return nil } @@ -726,11 +742,43 @@ func getLockManager(runtime *Runtime) (lock.Manager, error) { return manager, nil } +// probeConmon calls conmon --version and verifies it is a new enough version for +// the runtime expectations podman currently has +func probeConmon(conmonBinary string) error { + cmd := exec.Command(conmonBinary, "--version") + var out bytes.Buffer + cmd.Stdout = &out + err := cmd.Run() + if err != nil { + return err + } + r := regexp.MustCompile(`^conmon version (?P<Major>\d+).(?P<Minor>\d+).(?P<Patch>\d+)`) + + matches := r.FindStringSubmatch(out.String()) + if len(matches) != 4 { + return errors.Wrapf(err, "conmon version changed format") + } + major, err := strconv.Atoi(matches[1]) + if err != nil || major < 1 { + return define.ErrConmonOutdated + } + // conmon used to be shipped with CRI-O, and was versioned along with it. + // even though the conmon that came with crio-1.9 to crio-1.15 has a higher + // version number than conmon 1.0.0, 1.0.0 is newer, so we need this check + minor, err := strconv.Atoi(matches[2]) + if err != nil || minor > 9 { + return define.ErrConmonOutdated + } + + return nil +} + // Make a new runtime based on the given configuration // Sets up containers/storage, state store, OCI runtime func makeRuntime(ctx context.Context, runtime *Runtime) (err error) { // Find a working conmon binary foundConmon := false + foundOutdatedConmon := false for _, path := range runtime.config.ConmonPath { stat, err := os.Stat(path) if err != nil { @@ -739,6 +787,11 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (err error) { if stat.IsDir() { continue } + if err := probeConmon(path); err != nil { + logrus.Warnf("conmon at %s invalid: %v", path, err) + foundOutdatedConmon = true + continue + } foundConmon = true runtime.conmonPath = path logrus.Debugf("using conmon: %q", path) @@ -748,13 +801,21 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (err error) { // Search the $PATH as last fallback if !foundConmon { if conmon, err := exec.LookPath("conmon"); err == nil { - foundConmon = true - runtime.conmonPath = conmon - logrus.Debugf("using conmon from $PATH: %q", conmon) + if err := probeConmon(conmon); err != nil { + logrus.Warnf("conmon at %s is invalid: %v", conmon, err) + foundOutdatedConmon = true + } else { + foundConmon = true + runtime.conmonPath = conmon + logrus.Debugf("using conmon from $PATH: %q", conmon) + } } } if !foundConmon { + if foundOutdatedConmon { + return errors.Wrapf(define.ErrConmonOutdated, "please update to v1.0.0 or later") + } return errors.Wrapf(define.ErrInvalidArg, "could not find a working conmon binary (configured options: %v)", runtime.config.ConmonPath) diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index e57ab4634..92b2faefb 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -52,6 +52,16 @@ func (r *Runtime) RestoreContainer(ctx context.Context, rSpec *spec.Spec, config if err != nil { return nil, errors.Wrapf(err, "error initializing container variables") } + // For an imported checkpoint no one has ever set the StartedTime. Set it now. + ctr.state.StartedTime = time.Now() + + // If the path to ConmonPidFile starts with the default value (RunRoot), then + // the user has not specified '--conmon-pidfile' during run or create (probably). + // In that case reset ConmonPidFile to be set to the default value later. + if strings.HasPrefix(ctr.config.ConmonPidFile, r.config.StorageConfig.RunRoot) { + ctr.config.ConmonPidFile = "" + } + return r.setupContainer(ctx, ctr) } @@ -394,14 +404,9 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool, // Check that the container's in a good state to be removed if c.state.State == config2.ContainerStateRunning { - if err := c.ociRuntime.stopContainer(c, c.StopTimeout()); err != nil { + if err := c.stop(c.StopTimeout()); err != nil { return errors.Wrapf(err, "cannot remove container %s as it could not be stopped", c.ID()) } - - // Need to update container state to make sure we know it's stopped - if err := c.waitForExitFileAndSync(); err != nil { - return err - } } // Check that all of our exec sessions have finished diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go index 4055734eb..20dee4080 100644 --- a/libpod/runtime_img.go +++ b/libpod/runtime_img.go @@ -28,6 +28,7 @@ import ( // RemoveImage deletes an image from local storage // Images being used by running containers can only be removed if force=true func (r *Runtime) RemoveImage(ctx context.Context, img *image.Image, force bool) (string, error) { + var returnMessage string r.lock.Lock() defer r.lock.Unlock() @@ -93,7 +94,11 @@ func (r *Runtime) RemoveImage(ctx context.Context, img *image.Image, force bool) err = errStorage } } - return img.ID(), err + for _, name := range img.Names() { + returnMessage = returnMessage + fmt.Sprintf("Untagged: %s\n", name) + } + returnMessage = returnMessage + fmt.Sprintf("Deleted: %s", img.ID()) + return returnMessage, err } // Remove containers that are in storage rather than Podman. |