diff options
Diffstat (limited to 'libpod')
-rw-r--r-- | libpod/container_api.go | 4 | ||||
-rw-r--r-- | libpod/network/cni/config_test.go | 22 | ||||
-rw-r--r-- | libpod/network/cni/network.go | 22 | ||||
-rw-r--r-- | libpod/oci_attach_linux.go | 17 | ||||
-rw-r--r-- | libpod/oci_conmon_exec_linux.go | 7 | ||||
-rw-r--r-- | libpod/oci_conmon_linux.go | 10 | ||||
-rw-r--r-- | libpod/pod_api.go | 3 | ||||
-rw-r--r-- | libpod/reset.go | 7 | ||||
-rw-r--r-- | libpod/runtime.go | 3 | ||||
-rw-r--r-- | libpod/runtime_ctr.go | 22 | ||||
-rw-r--r-- | libpod/runtime_img.go | 3 | ||||
-rw-r--r-- | libpod/runtime_pod.go | 7 | ||||
-rw-r--r-- | libpod/runtime_pod_linux.go | 6 | ||||
-rw-r--r-- | libpod/runtime_volume.go | 7 | ||||
-rw-r--r-- | libpod/runtime_volume_linux.go | 4 |
15 files changed, 80 insertions, 64 deletions
diff --git a/libpod/container_api.go b/libpod/container_api.go index 50be0eea4..38223316e 100644 --- a/libpod/container_api.go +++ b/libpod/container_api.go @@ -184,7 +184,7 @@ func (c *Container) StopWithTimeout(timeout uint) error { return define.ErrCtrStopped } - if !c.ensureState(define.ContainerStateCreated, define.ContainerStateRunning) { + if !c.ensureState(define.ContainerStateCreated, define.ContainerStateRunning, define.ContainerStateStopping) { return errors.Wrapf(define.ErrCtrStateInvalid, "can only stop created or running containers. %s is in state %s", c.ID(), c.state.State.String()) } @@ -690,7 +690,7 @@ func (c *Container) Sync() error { // If runtime knows about the container, update its status in runtime // And then save back to disk - if c.ensureState(define.ContainerStateCreated, define.ContainerStateRunning, define.ContainerStatePaused, define.ContainerStateStopped) { + if c.ensureState(define.ContainerStateCreated, define.ContainerStateRunning, define.ContainerStatePaused, define.ContainerStateStopped, define.ContainerStateStopping) { oldState := c.state.State if err := c.ociRuntime.UpdateContainerStatus(c); err != nil { return err diff --git a/libpod/network/cni/config_test.go b/libpod/network/cni/config_test.go index 288cf4626..5b0feb859 100644 --- a/libpod/network/cni/config_test.go +++ b/libpod/network/cni/config_test.go @@ -1020,28 +1020,6 @@ var _ = Describe("Config", func() { Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("subnet 10.10.0.0/24 is already used on the host or by another config")) }) - - It("remove network should not error when config file does not exists on disk", func() { - name := "mynet" - network := types.Network{Name: name} - _, err := libpodNet.NetworkCreate(network) - Expect(err).To(BeNil()) - - path := filepath.Join(cniConfDir, name+".conflist") - Expect(path).To(BeARegularFile()) - - err = os.Remove(path) - Expect(err).To(BeNil()) - Expect(path).ToNot(BeARegularFile()) - - err = libpodNet.NetworkRemove(name) - Expect(err).To(BeNil()) - - nets, err := libpodNet.NetworkList() - Expect(err).To(BeNil()) - Expect(nets).To(HaveLen(1)) - Expect(nets).ToNot(ContainElement(HaveNetworkName(name))) - }) }) Context("network load valid existing ones", func() { diff --git a/libpod/network/cni/network.go b/libpod/network/cni/network.go index 02801641e..a37a84373 100644 --- a/libpod/network/cni/network.go +++ b/libpod/network/cni/network.go @@ -10,6 +10,7 @@ import ( "net" "os" "strings" + "time" "github.com/containernetworking/cni/libcni" "github.com/containers/podman/v3/libpod/define" @@ -40,6 +41,9 @@ type cniNetwork struct { // lock is a internal lock for critical operations lock lockfile.Locker + // modTime is the timestamp when the config dir was modified + modTime time.Time + // networks is a map with loaded networks, the key is the network name networks map[string]*network } @@ -113,10 +117,22 @@ func (n *cniNetwork) Drivers() []string { } func (n *cniNetwork) loadNetworks() error { - // skip loading networks if they are already loaded - if n.networks != nil { + // check the mod time of the config dir + f, err := os.Stat(n.cniConfigDir) + if err != nil { + return err + } + modTime := f.ModTime() + + // skip loading networks if they are already loaded and + // if the config dir was not modified since the last call + if n.networks != nil && modTime.Equal(n.modTime) { return nil } + // make sure the remove all networks before we reload them + n.networks = nil + n.modTime = modTime + // FIXME: do we have to support other file types as well, e.g. .conf? files, err := libcni.ConfFiles(n.cniConfigDir, []string{".conflist"}) if err != nil { @@ -153,7 +169,7 @@ func (n *cniNetwork) loadNetworks() error { logrus.Errorf("CNI config list %s could not be converted to a libpod config, skipping: %v", file, err) continue } - logrus.Tracef("Successfully loaded network %s: %v", net.Name, net) + logrus.Debugf("Successfully loaded network %s: %v", net.Name, net) networkInfo := network{ filename: file, cniNet: conf, diff --git a/libpod/oci_attach_linux.go b/libpod/oci_attach_linux.go index d4d4a1076..1f2a28ead 100644 --- a/libpod/oci_attach_linux.go +++ b/libpod/oci_attach_linux.go @@ -93,7 +93,7 @@ func (c *Container) attach(streams *define.AttachStreams, keys string, resize <- if attachRdy != nil { attachRdy <- true } - return readStdio(streams, receiveStdoutError, stdinDone) + return readStdio(conn, streams, receiveStdoutError, stdinDone) } // Attach to the given container's exec session @@ -174,7 +174,7 @@ func (c *Container) attachToExec(streams *define.AttachStreams, keys *string, se return err } - return readStdio(streams, receiveStdoutError, stdinDone) + return readStdio(conn, streams, receiveStdoutError, stdinDone) } func processDetachKeys(keys string) ([]byte, error) { @@ -217,11 +217,6 @@ func setupStdioChannels(streams *define.AttachStreams, conn *net.UnixConn, detac var err error if streams.AttachInput { _, err = utils.CopyDetachable(conn, streams.InputStream, detachKeys) - if err == nil { - if connErr := conn.CloseWrite(); connErr != nil { - logrus.Errorf("Unable to close conn: %q", connErr) - } - } } stdinDone <- err }() @@ -274,7 +269,7 @@ func redirectResponseToOutputStreams(outputStream, errorStream io.Writer, writeO return err } -func readStdio(streams *define.AttachStreams, receiveStdoutError, stdinDone chan error) error { +func readStdio(conn *net.UnixConn, streams *define.AttachStreams, receiveStdoutError, stdinDone chan error) error { var err error select { case err = <-receiveStdoutError: @@ -283,6 +278,12 @@ func readStdio(streams *define.AttachStreams, receiveStdoutError, stdinDone chan if err == define.ErrDetach { return err } + if err == nil { + // copy stdin is done, close it + if connErr := conn.CloseWrite(); connErr != nil { + logrus.Errorf("Unable to close conn: %v", connErr) + } + } if streams.AttachOutput || streams.AttachError { return <-receiveStdoutError } diff --git a/libpod/oci_conmon_exec_linux.go b/libpod/oci_conmon_exec_linux.go index 822377bfe..654306f92 100644 --- a/libpod/oci_conmon_exec_linux.go +++ b/libpod/oci_conmon_exec_linux.go @@ -609,9 +609,6 @@ func attachExecHTTP(c *Container, sessionID string, r *http.Request, w http.Resp _, err := utils.CopyDetachable(conn, httpBuf, detachKeys) logrus.Debugf("STDIN copy completed") stdinChan <- err - if connErr := conn.CloseWrite(); connErr != nil { - logrus.Errorf("Unable to close conn: %v", connErr) - } }() } @@ -654,6 +651,10 @@ func attachExecHTTP(c *Container, sessionID string, r *http.Request, w http.Resp if err != nil { return err } + // copy stdin is done, close it + if connErr := conn.CloseWrite(); connErr != nil { + logrus.Errorf("Unable to close conn: %v", connErr) + } case <-cancel: return nil } diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go index 71a7b29fa..0369a9977 100644 --- a/libpod/oci_conmon_linux.go +++ b/libpod/oci_conmon_linux.go @@ -351,6 +351,12 @@ func (r *ConmonOCIRuntime) UpdateContainerStatus(ctr *Container) error { return ctr.handleExitFile(exitFile, fi) } + // Handle ContainerStateStopping - keep it unless the container + // transitioned to no longer running. + if oldState == define.ContainerStateStopping && (ctr.state.State == define.ContainerStatePaused || ctr.state.State == define.ContainerStateRunning) { + ctr.state.State = define.ContainerStateStopping + } + return nil } @@ -701,6 +707,10 @@ func (r *ConmonOCIRuntime) HTTPAttach(ctr *Container, req *http.Request, w http. if err != nil { return err } + // copy stdin is done, close it + if connErr := conn.CloseWrite(); connErr != nil { + logrus.Errorf("Unable to close conn: %v", connErr) + } case <-cancel: return nil } diff --git a/libpod/pod_api.go b/libpod/pod_api.go index 4ae02fb40..feb8ff250 100644 --- a/libpod/pod_api.go +++ b/libpod/pod_api.go @@ -37,7 +37,8 @@ func (p *Pod) startInitContainers(ctx context.Context) error { if initCon.config.InitContainerType == define.OneShotInitContainer { icLock := initCon.lock icLock.Lock() - if err := p.runtime.removeContainer(ctx, initCon, false, false, true); err != nil { + var time *uint + if err := p.runtime.removeContainer(ctx, initCon, false, false, true, time); err != nil { icLock.Unlock() return errors.Wrapf(err, "failed to remove once init container %s", initCon.ID()) } diff --git a/libpod/reset.go b/libpod/reset.go index 7b25ed680..5d9bb0e90 100644 --- a/libpod/reset.go +++ b/libpod/reset.go @@ -18,12 +18,13 @@ import ( // Reset removes all storage func (r *Runtime) Reset(ctx context.Context) error { + var timeout *uint pods, err := r.GetAllPods() if err != nil { return err } for _, p := range pods { - if err := r.RemovePod(ctx, p, true, true); err != nil { + if err := r.RemovePod(ctx, p, true, true, timeout); err != nil { if errors.Cause(err) == define.ErrNoSuchPod { continue } @@ -37,7 +38,7 @@ func (r *Runtime) Reset(ctx context.Context) error { } for _, c := range ctrs { - if err := r.RemoveContainer(ctx, c, true, true); err != nil { + if err := r.RemoveContainer(ctx, c, true, true, timeout); err != nil { if err := r.RemoveStorageContainer(c.ID(), true); err != nil { if errors.Cause(err) == define.ErrNoSuchCtr { continue @@ -61,7 +62,7 @@ func (r *Runtime) Reset(ctx context.Context) error { return err } for _, v := range volumes { - if err := r.RemoveVolume(ctx, v, true); err != nil { + if err := r.RemoveVolume(ctx, v, true, timeout); err != nil { if errors.Cause(err) == define.ErrNoSuchVolume { continue } diff --git a/libpod/runtime.go b/libpod/runtime.go index 27885bf5c..855f3a9f9 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -489,8 +489,7 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (retErr error) { DefaultNetwork: runtime.config.Network.DefaultNetwork, DefaultSubnet: runtime.config.Network.DefaultSubnet, IsMachine: runtime.config.Engine.MachineEnabled, - // TODO use cni.lock - LockFile: filepath.Join(runtime.config.Network.NetworkConfigDir, "cni1.lock"), + LockFile: filepath.Join(runtime.config.Network.NetworkConfigDir, "cni.lock"), }) if err != nil { return errors.Wrapf(err, "could not create network interface") diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go index 00979a500..2256ba57c 100644 --- a/libpod/runtime_ctr.go +++ b/libpod/runtime_ctr.go @@ -535,10 +535,10 @@ func (r *Runtime) setupContainer(ctx context.Context, ctr *Container) (_ *Contai // If removeVolume is specified, named volumes used by the container will // be removed also if and only if the container is the sole user // Otherwise, RemoveContainer will return an error if the container is running -func (r *Runtime) RemoveContainer(ctx context.Context, c *Container, force bool, removeVolume bool) error { +func (r *Runtime) RemoveContainer(ctx context.Context, c *Container, force bool, removeVolume bool, timeout *uint) error { r.lock.Lock() defer r.lock.Unlock() - return r.removeContainer(ctx, c, force, removeVolume, false) + return r.removeContainer(ctx, c, force, removeVolume, false, timeout) } // Internal function to remove a container. @@ -546,7 +546,7 @@ func (r *Runtime) RemoveContainer(ctx context.Context, c *Container, force bool, // removePod is used only when removing pods. It instructs Podman to ignore // infra container protections, and *not* remove from the database (as pod // remove will handle that). -func (r *Runtime) removeContainer(ctx context.Context, c *Container, force, removeVolume, removePod bool) error { +func (r *Runtime) removeContainer(ctx context.Context, c *Container, force, removeVolume, removePod bool, timeout *uint) error { if !c.valid { if ok, _ := r.state.HasContainer(c.ID()); !ok { // Container probably already removed @@ -642,9 +642,13 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force, remo // Check that the container's in a good state to be removed. if c.state.State == define.ContainerStateRunning { + time := c.StopTimeout() + if timeout != nil { + time = *timeout + } // Ignore ErrConmonDead - we couldn't retrieve the container's // exit code properly, but it's still stopped. - if err := c.stop(c.StopTimeout()); err != nil && errors.Cause(err) != define.ErrConmonDead { + if err := c.stop(time); err != nil && errors.Cause(err) != define.ErrConmonDead { return errors.Wrapf(err, "cannot remove container %s as it could not be stopped", c.ID()) } @@ -751,7 +755,7 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force, remo if !volume.Anonymous() { continue } - if err := runtime.removeVolume(ctx, volume, false); err != nil && errors.Cause(err) != define.ErrNoSuchVolume { + if err := runtime.removeVolume(ctx, volume, false, timeout); err != nil && errors.Cause(err) != define.ErrNoSuchVolume { logrus.Errorf("Cleanup volume (%s): %v", v, err) } } @@ -782,6 +786,7 @@ func (r *Runtime) EvictContainer(ctx context.Context, idOrName string, removeVol // remove will handle that). func (r *Runtime) evictContainer(ctx context.Context, idOrName string, removeVolume bool) (string, error) { var err error + var timeout *uint if !r.valid { return "", define.ErrRuntimeStopped @@ -797,7 +802,7 @@ func (r *Runtime) evictContainer(ctx context.Context, idOrName string, removeVol if err == nil { logrus.Infof("Container %s successfully retrieved from state, attempting normal removal", id) // Assume force = true for the evict case - err = r.removeContainer(ctx, tmpCtr, true, removeVolume, false) + err = r.removeContainer(ctx, tmpCtr, true, removeVolume, false, timeout) if !tmpCtr.valid { // If the container is marked invalid, remove succeeded // in kicking it out of the state - no need to continue. @@ -892,7 +897,7 @@ func (r *Runtime) evictContainer(ctx context.Context, idOrName string, removeVol if !volume.Anonymous() { continue } - if err := r.removeVolume(ctx, volume, false); err != nil && err != define.ErrNoSuchVolume && err != define.ErrVolumeBeingUsed { + if err := r.removeVolume(ctx, volume, false, timeout); err != nil && err != define.ErrNoSuchVolume && err != define.ErrVolumeBeingUsed { logrus.Errorf("Cleanup volume (%s): %v", v, err) } } @@ -1089,7 +1094,8 @@ func (r *Runtime) PruneContainers(filterFuncs []ContainerFilter) ([]*reports.Pru preports = append(preports, report) continue } - err = r.RemoveContainer(context.Background(), c, false, false) + var time *uint + err = r.RemoveContainer(context.Background(), c, false, false, time) if err != nil { report.Err = err } else { diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go index 1915a5c4d..52ac0d4d7 100644 --- a/libpod/runtime_img.go +++ b/libpod/runtime_img.go @@ -37,7 +37,8 @@ func (r *Runtime) RemoveContainersForImageCallback(ctx context.Context) libimage } for _, ctr := range ctrs { if ctr.config.RootfsImageID == imageID { - if err := r.removeContainer(ctx, ctr, true, false, false); err != nil { + var timeout *uint + if err := r.removeContainer(ctx, ctr, true, false, false, timeout); err != nil { return errors.Wrapf(err, "error removing image %s: container %s using image could not be removed", imageID, ctr.ID()) } } diff --git a/libpod/runtime_pod.go b/libpod/runtime_pod.go index b142472e8..2389ee6d9 100644 --- a/libpod/runtime_pod.go +++ b/libpod/runtime_pod.go @@ -26,7 +26,7 @@ type PodFilter func(*Pod) bool // If force is specified with removeCtrs, all containers will be stopped before // being removed // Otherwise, the pod will not be removed if any containers are running -func (r *Runtime) RemovePod(ctx context.Context, p *Pod, removeCtrs, force bool) error { +func (r *Runtime) RemovePod(ctx context.Context, p *Pod, removeCtrs, force bool, timeout *uint) error { r.lock.Lock() defer r.lock.Unlock() @@ -45,7 +45,7 @@ func (r *Runtime) RemovePod(ctx context.Context, p *Pod, removeCtrs, force bool) p.lock.Lock() defer p.lock.Unlock() - return r.removePod(ctx, p, removeCtrs, force) + return r.removePod(ctx, p, removeCtrs, force, timeout) } // GetPod retrieves a pod by its ID @@ -196,7 +196,8 @@ func (r *Runtime) PrunePods(ctx context.Context) (map[string]error, error) { return response, nil } for _, pod := range pods { - err := r.removePod(context.TODO(), pod, true, false) + var timeout *uint + err := r.removePod(context.TODO(), pod, true, false, timeout) response[pod.ID()] = err } return response, nil diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go index 5036dd680..9c6f1539f 100644 --- a/libpod/runtime_pod_linux.go +++ b/libpod/runtime_pod_linux.go @@ -168,7 +168,7 @@ func (r *Runtime) SavePod(pod *Pod) error { return nil } -func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) error { +func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool, timeout *uint) error { if err := p.updatePod(); err != nil { return err } @@ -255,7 +255,7 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) ctrNamedVolumes[vol.Name] = vol } - if err := r.removeContainer(ctx, ctr, force, false, true); err != nil { + if err := r.removeContainer(ctx, ctr, force, false, true, timeout); err != nil { if removalErr == nil { removalErr = err } else { @@ -281,7 +281,7 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool) if !volume.Anonymous() { continue } - if err := r.removeVolume(ctx, volume, false); err != nil { + if err := r.removeVolume(ctx, volume, false, timeout); err != nil { if errors.Cause(err) == define.ErrNoSuchVolume || errors.Cause(err) == define.ErrVolumeRemoved { continue } diff --git a/libpod/runtime_volume.go b/libpod/runtime_volume.go index 5f8f9ca1e..2b3ad10b4 100644 --- a/libpod/runtime_volume.go +++ b/libpod/runtime_volume.go @@ -21,7 +21,7 @@ type VolumeCreateOption func(*Volume) error type VolumeFilter func(*Volume) bool // RemoveVolume removes a volumes -func (r *Runtime) RemoveVolume(ctx context.Context, v *Volume, force bool) error { +func (r *Runtime) RemoveVolume(ctx context.Context, v *Volume, force bool, timeout *uint) error { r.lock.Lock() defer r.lock.Unlock() @@ -36,7 +36,7 @@ func (r *Runtime) RemoveVolume(ctx context.Context, v *Volume, force bool) error return nil } } - return r.removeVolume(ctx, v, force) + return r.removeVolume(ctx, v, force, timeout) } // GetVolume retrieves a volume given its full name. @@ -149,7 +149,8 @@ func (r *Runtime) PruneVolumes(ctx context.Context, filterFuncs []VolumeFilter) } report.Size = volSize report.Id = vol.Name() - if err := r.RemoveVolume(ctx, vol, false); err != nil { + var timeout *uint + if err := r.RemoveVolume(ctx, vol, false, timeout); err != nil { if errors.Cause(err) != define.ErrVolumeBeingUsed && errors.Cause(err) != define.ErrVolumeRemoved { report.Err = err } else { diff --git a/libpod/runtime_volume_linux.go b/libpod/runtime_volume_linux.go index def6ca411..b08693529 100644 --- a/libpod/runtime_volume_linux.go +++ b/libpod/runtime_volume_linux.go @@ -189,7 +189,7 @@ func makeVolumeInPluginIfNotExist(name string, options map[string]string, plugin } // removeVolume removes the specified volume from state as well tears down its mountpoint and storage -func (r *Runtime) removeVolume(ctx context.Context, v *Volume, force bool) error { +func (r *Runtime) removeVolume(ctx context.Context, v *Volume, force bool, timeout *uint) error { if !v.valid { if ok, _ := r.state.HasVolume(v.Name()); !ok { return nil @@ -234,7 +234,7 @@ func (r *Runtime) removeVolume(ctx context.Context, v *Volume, force bool) error // containers? // I'm inclined to say no, in case someone accidentally // wipes a container they're using... - if err := r.removeContainer(ctx, ctr, false, false, false); err != nil { + if err := r.removeContainer(ctx, ctr, false, false, false, timeout); err != nil { return errors.Wrapf(err, "error removing container %s that depends on volume %s", ctr.ID(), v.Name()) } } |