summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container.go3
-rw-r--r--libpod/container_api.go5
-rw-r--r--libpod/container_internal.go18
-rw-r--r--libpod/container_internal_linux.go31
-rw-r--r--libpod/events/config.go10
-rw-r--r--libpod/events/journal_linux.go5
-rw-r--r--libpod/events/logfile.go5
-rw-r--r--libpod/events/nullout.go8
-rw-r--r--libpod/info.go2
-rw-r--r--libpod/kube.go12
-rw-r--r--libpod/networking_linux.go60
-rw-r--r--libpod/oci_internal_linux.go16
-rw-r--r--libpod/oci_linux.go8
-rw-r--r--libpod/runtime.go2
-rw-r--r--libpod/runtime_pod_infra_linux.go4
15 files changed, 145 insertions, 44 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 ef9c3f006..abcfcb271 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -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_internal.go b/libpod/container_internal.go
index aba9c5b93..313f67963 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -1152,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..d06c19b8c 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -63,12 +63,12 @@ func (c *Container) unmountSHM(mount string) error {
// namespaces
func (c *Container) prepare() (err error) {
var (
- wg sync.WaitGroup
- netNS ns.NetNS
- networkStatus []*cnitypes.Result
- createNetNSErr, mountStorageErr error
- mountPoint string
- tmpStateLock sync.Mutex
+ wg sync.WaitGroup
+ netNS ns.NetNS
+ networkStatus []*cnitypes.Result
+ createNetNSErr, mountStorageErr, rootlessSetupErr error
+ mountPoint string
+ tmpStateLock sync.Mutex
)
wg.Add(2)
@@ -87,6 +87,11 @@ func (c *Container) prepare() (err error) {
c.state.NetNS = netNS
c.state.NetworkStatus = networkStatus
}
+
+ // Setup rootless networking, requires c.state.NetNS to be set
+ if rootless.IsRootless() {
+ rootlessSetupErr = c.runtime.setupRootlessNetNS(c)
+ }
}
}()
// Mount storage if not mounted
@@ -132,6 +137,10 @@ func (c *Container) prepare() (err error) {
return mountStorageErr
}
+ if rootlessSetupErr != nil {
+ return rootlessSetupErr
+ }
+
// Save the container
return c.save()
}
@@ -743,6 +752,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 +769,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/events/config.go b/libpod/events/config.go
index 96172d47b..453c64f8c 100644
--- a/libpod/events/config.go
+++ b/libpod/events/config.go
@@ -22,13 +22,13 @@ const (
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
@@ -53,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/journal_linux.go b/libpod/events/journal_linux.go
index d5bce4334..ae96e3b3b 100644
--- a/libpod/events/journal_linux.go
+++ b/libpod/events/journal_linux.go
@@ -146,3 +146,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 30d72b9fc..4b65b0ad0 100644
--- a/libpod/events/logfile.go
+++ b/libpod/events/logfile.go
@@ -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/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/networking_linux.go b/libpod/networking_linux.go
index bef3f7739..73e839bda 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -103,9 +103,6 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Re
// Create and configure a new network namespace for a container
func (r *Runtime) createNetNS(ctr *Container) (n ns.NetNS, q []*cnitypes.Result, err error) {
- if rootless.IsRootless() {
- return nil, nil, errors.New("cannot configure a new network namespace in rootless mode, only --network=slirp4netns is supported")
- }
ctrNS, err := netns.NewNS()
if err != nil {
return nil, nil, errors.Wrapf(err, "error creating network namespace for container %s", ctr.ID())
@@ -123,7 +120,10 @@ func (r *Runtime) createNetNS(ctr *Container) (n ns.NetNS, q []*cnitypes.Result,
logrus.Debugf("Made network namespace at %s for container %s", ctrNS.Path(), ctr.ID())
- networkStatus, err := r.configureNetNS(ctr, ctrNS)
+ networkStatus := []*cnitypes.Result{}
+ if !rootless.IsRootless() {
+ networkStatus, err = r.configureNetNS(ctr, ctrNS)
+ }
return ctrNS, networkStatus, err
}
@@ -151,9 +151,6 @@ func checkSlirpFlags(path string) (bool, bool, error) {
// Configure the network namespace for a rootless container
func (r *Runtime) setupRootlessNetNS(ctr *Container) (err error) {
- defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncR)
- defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncW)
-
path := r.config.NetworkCmdPath
if path == "" {
@@ -177,7 +174,7 @@ func (r *Runtime) setupRootlessNetNS(ctr *Container) (err error) {
cmdArgs := []string{}
if havePortMapping {
- cmdArgs = append(cmdArgs, "--api-socket", apiSocket, fmt.Sprintf("%d", ctr.state.PID))
+ cmdArgs = append(cmdArgs, "--api-socket", apiSocket)
}
dhp, mtu, err := checkSlirpFlags(path)
if err != nil {
@@ -189,13 +186,27 @@ func (r *Runtime) setupRootlessNetNS(ctr *Container) (err error) {
if mtu {
cmdArgs = append(cmdArgs, "--mtu", "65520")
}
- cmdArgs = append(cmdArgs, "-c", "-e", "3", "-r", "4", fmt.Sprintf("%d", ctr.state.PID), "tap0")
- cmd := exec.Command(path, cmdArgs...)
+ cmdArgs = append(cmdArgs, "-c", "-e", "3", "-r", "4")
+ if !ctr.config.PostConfigureNetNS {
+ ctr.rootlessSlirpSyncR, ctr.rootlessSlirpSyncW, err = os.Pipe()
+ if err != nil {
+ return errors.Wrapf(err, "failed to create rootless network sync pipe")
+ }
+ cmdArgs = append(cmdArgs, "--netns-type=path", ctr.state.NetNS.Path(), "tap0")
+ } else {
+ defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncR)
+ defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncW)
+ cmdArgs = append(cmdArgs, fmt.Sprintf("%d", ctr.state.PID), "tap0")
+ }
+ cmd := exec.Command(path, cmdArgs...)
+ logrus.Debugf("slirp4netns command: %s", strings.Join(cmd.Args, " "))
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
+
+ // Leak one end of the pipe in slirp4netns, the other will be sent to conmon
cmd.ExtraFiles = append(cmd.ExtraFiles, ctr.rootlessSlirpSyncR, syncW)
if err := cmd.Start(); err != nil {
@@ -410,22 +421,25 @@ func (r *Runtime) teardownNetNS(ctr *Container) error {
}
}
- logrus.Debugf("Tearing down network namespace at %s for container %s", ctr.state.NetNS.Path(), ctr.ID())
+ logrus.Debugf("Tearing down network namespace for container %s", ctr.ID())
- var requestedIP net.IP
- if ctr.requestedIP != nil {
- requestedIP = ctr.requestedIP
- // cancel request for a specific IP in case the container is reused later
- ctr.requestedIP = nil
- } else {
- requestedIP = ctr.config.StaticIP
- }
+ // rootless containers do not use the CNI plugin
+ if !rootless.IsRootless() {
+ var requestedIP net.IP
+ if ctr.requestedIP != nil {
+ requestedIP = ctr.requestedIP
+ // cancel request for a specific IP in case the container is reused later
+ ctr.requestedIP = nil
+ } else {
+ requestedIP = ctr.config.StaticIP
+ }
- podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), ctr.config.Networks, ctr.config.PortMappings, requestedIP)
+ podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), ctr.config.Networks, ctr.config.PortMappings, requestedIP)
- // The network may have already been torn down, so don't fail here, just log
- if err := r.netPlugin.TearDownPod(podNetwork); err != nil {
- return errors.Wrapf(err, "error tearing down CNI namespace configuration for container %s", ctr.ID())
+ // The network may have already been torn down, so don't fail here, just log
+ if err := r.netPlugin.TearDownPod(podNetwork); err != nil {
+ return errors.Wrapf(err, "error tearing down CNI namespace configuration for container %s", ctr.ID())
+ }
}
// First unmount the namespace
diff --git a/libpod/oci_internal_linux.go b/libpod/oci_internal_linux.go
index 0bcd021db..28e4b5b82 100644
--- a/libpod/oci_internal_linux.go
+++ b/libpod/oci_internal_linux.go
@@ -130,10 +130,16 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Containe
}
if ctr.config.NetMode.IsSlirp4netns() {
- ctr.rootlessSlirpSyncR, ctr.rootlessSlirpSyncW, err = os.Pipe()
- if err != nil {
- return errors.Wrapf(err, "failed to create rootless network sync pipe")
+ if ctr.config.PostConfigureNetNS {
+ ctr.rootlessSlirpSyncR, ctr.rootlessSlirpSyncW, err = os.Pipe()
+ if err != nil {
+ return errors.Wrapf(err, "failed to create rootless network sync pipe")
+ }
+ } else {
+ defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncR)
+ defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncW)
}
+
// Leak one end in conmon, the other one will be leaked into slirp4netns
cmd.ExtraFiles = append(cmd.ExtraFiles, ctr.rootlessSlirpSyncW)
}
@@ -278,6 +284,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/oci_linux.go b/libpod/oci_linux.go
index 45365203e..4d8e36516 100644
--- a/libpod/oci_linux.go
+++ b/libpod/oci_linux.go
@@ -405,6 +405,14 @@ func (r *OCIRuntime) stopContainer(ctr *Container, timeout uint) error {
stopSignal = uint(syscall.SIGTERM)
}
+ defer func() {
+ // cleanup container networking
+ err = ctr.cleanupNetwork()
+ if err != nil {
+ logrus.Errorf("Error cleaning up container: %s network: %v", ctr.ID(), err)
+ }
+ }()
+
if timeout > 0 {
if err := r.killContainer(ctr, stopSignal); err != nil {
// Is the container gone?
diff --git a/libpod/runtime.go b/libpod/runtime.go
index ffdbc32f1..b66b68cfd 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -52,7 +52,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"
diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go
index da35b7f93..20b841296 100644
--- a/libpod/runtime_pod_infra_linux.go
+++ b/libpod/runtime_pod_infra_linux.go
@@ -95,7 +95,9 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, imgID
if isRootless {
netmode = "slirp4netns"
}
- options = append(options, WithNetNS(p.config.InfraContainer.PortBindings, isRootless, netmode, networks))
+ // PostConfigureNetNS should not be set since user namespace sharing is not implemented
+ // and rootless networking no longer supports post configuration setup
+ options = append(options, WithNetNS(p.config.InfraContainer.PortBindings, false, netmode, networks))
return r.newContainer(ctx, g.Config, options...)
}