summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/cliconfig/config.go1
-rw-r--r--cmd/podman/network_rm.go18
-rw-r--r--cmd/podman/sign.go32
-rw-r--r--completions/bash/podman2
-rw-r--r--contrib/varlink/io.podman.service5
-rw-r--r--contrib/varlink/io.podman.socket1
-rw-r--r--docs/podman-network-rm.1.md19
-rw-r--r--libpod/container_internal.go10
-rw-r--r--libpod/runtime_cstorage.go6
-rw-r--r--pkg/adapter/network.go68
-rw-r--r--pkg/network/devices.go16
-rw-r--r--pkg/network/files.go24
-rw-r--r--test/e2e/exec_test.go12
13 files changed, 188 insertions, 26 deletions
diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go
index bf88e853b..e0ce202cc 100644
--- a/cmd/podman/cliconfig/config.go
+++ b/cmd/podman/cliconfig/config.go
@@ -280,6 +280,7 @@ type NetworkListValues struct {
type NetworkRmValues struct {
PodmanCommand
+ Force bool
}
type NetworkInspectValues struct {
diff --git a/cmd/podman/network_rm.go b/cmd/podman/network_rm.go
index 50bd48cea..41e5dbdab 100644
--- a/cmd/podman/network_rm.go
+++ b/cmd/podman/network_rm.go
@@ -3,10 +3,13 @@
package main
import (
+ "fmt"
+
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/pkg/adapter"
"github.com/containers/libpod/pkg/rootless"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
@@ -31,6 +34,8 @@ func init() {
networkrmCommand.Command = _networkrmCommand
networkrmCommand.SetHelpTemplate(HelpTemplate())
networkrmCommand.SetUsageTemplate(UsageTemplate())
+ flags := networkrmCommand.Flags()
+ flags.BoolVarP(&networkrmCommand.Force, "force", "f", false, "remove any containers using network")
}
func networkrmCmd(c *cliconfig.NetworkRmValues) error {
@@ -40,9 +45,18 @@ func networkrmCmd(c *cliconfig.NetworkRmValues) error {
if len(c.InputArgs) < 1 {
return errors.Errorf("at least one network name is required")
}
- runtime, err := adapter.GetRuntimeNoStore(getContext(), &c.PodmanCommand)
+ runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand)
if err != nil {
return err
}
- return runtime.NetworkRemove(c)
+ deletes, rmErrors, lastErr := runtime.NetworkRemove(getContext(), c)
+ for _, d := range deletes {
+ fmt.Println(d)
+ }
+ // we only want to print errors if there is more
+ // than one
+ for network, removalErr := range rmErrors {
+ logrus.Errorf("unable to remove %q: %q", network, removalErr)
+ }
+ return lastErr
}
diff --git a/cmd/podman/sign.go b/cmd/podman/sign.go
index 63ba9b904..79bc3f02b 100644
--- a/cmd/podman/sign.go
+++ b/cmd/podman/sign.go
@@ -14,6 +14,7 @@ import (
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/trust"
"github.com/containers/libpod/pkg/util"
"github.com/pkg/errors"
@@ -130,22 +131,33 @@ func signCmd(c *cliconfig.SignValues) error {
return errors.Wrapf(err, "error pulling image %s", signimage)
}
- registryInfo := trust.HaveMatchRegistry(rawSource.Reference().DockerReference().String(), registryConfigs)
- if registryInfo != nil {
+ if rootless.IsRootless() {
if sigStoreDir == "" {
- sigStoreDir = registryInfo.SigStoreStaging
+ runtimeConfig, err := runtime.GetConfig()
+ if err != nil {
+ return err
+ }
+
+ sigStoreDir = filepath.Join(filepath.Dir(runtimeConfig.StorageConfig.GraphRoot), "sigstore")
+ }
+ } else {
+ registryInfo := trust.HaveMatchRegistry(rawSource.Reference().DockerReference().String(), registryConfigs)
+ if registryInfo != nil {
if sigStoreDir == "" {
- sigStoreDir = registryInfo.SigStore
+ sigStoreDir = registryInfo.SigStoreStaging
+ if sigStoreDir == "" {
+ sigStoreDir = registryInfo.SigStore
+ }
+ }
+ sigStoreDir, err = isValidSigStoreDir(sigStoreDir)
+ if err != nil {
+ return errors.Wrapf(err, "invalid signature storage %s", sigStoreDir)
}
}
- sigStoreDir, err = isValidSigStoreDir(sigStoreDir)
- if err != nil {
- return errors.Wrapf(err, "invalid signature storage %s", sigStoreDir)
+ if sigStoreDir == "" {
+ sigStoreDir = SignatureStoreDir
}
}
- if sigStoreDir == "" {
- sigStoreDir = SignatureStoreDir
- }
repos, err := newImage.RepoDigests()
if err != nil {
diff --git a/completions/bash/podman b/completions/bash/podman
index 041703810..4bc387871 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -1032,6 +1032,8 @@ _podman_network_rm() {
local options_with_args="
"
local boolean_options="
+ --force
+ -f
--help
-h
"
diff --git a/contrib/varlink/io.podman.service b/contrib/varlink/io.podman.service
index 725198e79..5be5329f4 100644
--- a/contrib/varlink/io.podman.service
+++ b/contrib/varlink/io.podman.service
@@ -6,8 +6,9 @@ Documentation=man:podman-varlink(1)
[Service]
Type=simple
-ExecStart=/usr/bin/podman varlink unix:%t/podman/io.podman
-KillMode=none
+ExecStart=/usr/bin/podman varlink unix:%t/podman/io.podman --timeout=60000
+TimeoutStopSec=30
+KillMode=process
[Install]
WantedBy=multi-user.target
diff --git a/contrib/varlink/io.podman.socket b/contrib/varlink/io.podman.socket
index f6a3ddc49..629a5dd20 100644
--- a/contrib/varlink/io.podman.socket
+++ b/contrib/varlink/io.podman.socket
@@ -8,3 +8,4 @@ SocketMode=0600
[Install]
WantedBy=sockets.target
+Also=multi-user.target
diff --git a/docs/podman-network-rm.1.md b/docs/podman-network-rm.1.md
index c95c93cd8..c71f0d8fd 100644
--- a/docs/podman-network-rm.1.md
+++ b/docs/podman-network-rm.1.md
@@ -9,13 +9,26 @@ podman\-network\-rm - Remove one or more CNI networks
## DESCRIPTION
Delete one or more Podman networks.
+## OPTIONS
+**--force**, **-f**
+
+The `force` option will remove all containers that use the named network. If the container is
+running, the container will be stopped and removed.
+
## EXAMPLE
-Delete the `podman9` network
+Delete the `cni-podman9` network
+
+```
+# podman network rm cni-podman9
+Deleted: cni-podman9
+```
+
+Delete the `fred` network and all containers associated with the network.
```
-# podman network rm podman
-Deleted: podman9
+# podman network rm -f fred
+Deleted: fred
```
## SEE ALSO
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index ac565fdad..0b5a8b946 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -163,7 +163,15 @@ func (c *Container) createExecBundle(sessionID string) (err error) {
// cleanup an exec session after its done
func (c *Container) cleanupExecBundle(sessionID string) error {
- return os.RemoveAll(c.execBundlePath(sessionID))
+ if err := os.RemoveAll(c.execBundlePath(sessionID)); err != nil && !os.IsNotExist(err) {
+ return err
+ }
+ // Clean up the sockets dir. Issue #3962
+ // Also ignore if it doesn't exist for some reason; hence the conditional return below
+ if err := os.RemoveAll(filepath.Join(c.ociRuntime.socketsDir, sessionID)); err != nil && !os.IsNotExist(err) {
+ return err
+ }
+ return nil
}
// the path to a containers exec session bundle
diff --git a/libpod/runtime_cstorage.go b/libpod/runtime_cstorage.go
index 586db5a1e..1e84aef4b 100644
--- a/libpod/runtime_cstorage.go
+++ b/libpod/runtime_cstorage.go
@@ -1,6 +1,8 @@
package libpod
import (
+ "time"
+
"github.com/containers/libpod/libpod/define"
"github.com/containers/storage"
"github.com/pkg/errors"
@@ -12,6 +14,8 @@ import (
type StorageContainer struct {
ID string
Names []string
+ Image string
+ CreateTime time.Time
PresentInLibpod bool
}
@@ -31,6 +35,8 @@ func (r *Runtime) ListStorageContainers() ([]*StorageContainer, error) {
storageCtr := new(StorageContainer)
storageCtr.ID = ctr.ID
storageCtr.Names = ctr.Names
+ storageCtr.Image = ctr.ImageID
+ storageCtr.CreateTime = ctr.Created
// Look up if container is in state
hasCtr, err := r.state.HasContainer(ctr.ID)
diff --git a/pkg/adapter/network.go b/pkg/adapter/network.go
index e4a160767..d407984ce 100644
--- a/pkg/adapter/network.go
+++ b/pkg/adapter/network.go
@@ -3,9 +3,9 @@
package adapter
import (
+ "context"
"encoding/json"
"fmt"
- "github.com/containers/libpod/pkg/util"
"io/ioutil"
"os"
"path/filepath"
@@ -14,6 +14,7 @@ import (
cniversion "github.com/containernetworking/cni/pkg/version"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/pkg/network"
+ "github.com/containers/libpod/pkg/util"
"github.com/pkg/errors"
)
@@ -85,16 +86,69 @@ func (r *LocalRuntime) NetworkInspect(cli *cliconfig.NetworkInspectValues) error
}
// NetworkRemove deletes one or more CNI networks
-func (r *LocalRuntime) NetworkRemove(cli *cliconfig.NetworkRmValues) error {
+func (r *LocalRuntime) NetworkRemove(ctx context.Context, cli *cliconfig.NetworkRmValues) ([]string, map[string]error, error) {
+ var (
+ networkRmSuccesses []string
+ lastError error
+ )
+ networkRmErrors := make(map[string]error)
+
for _, name := range cli.InputArgs {
- cniPath, err := network.GetCNIConfigPathByName(name)
+ containers, err := r.GetAllContainers()
if err != nil {
- return err
+ return networkRmSuccesses, networkRmErrors, err
}
- if err := os.Remove(cniPath); err != nil {
- return err
+ if err := r.removeNetwork(ctx, name, containers, cli.Force); err != nil {
+ if lastError != nil {
+ networkRmErrors[name] = lastError
+ }
+ lastError = err
+ } else {
+ networkRmSuccesses = append(networkRmSuccesses, fmt.Sprintf("Deleted: %s\n", name))
+ }
+ }
+ return networkRmSuccesses, networkRmErrors, lastError
+}
+
+// removeNetwork removes a single network and its containers given a force bool
+func (r *LocalRuntime) removeNetwork(ctx context.Context, name string, containers []*Container, force bool) error {
+ cniPath, err := network.GetCNIConfigPathByName(name)
+ if err != nil {
+ return err
+ }
+ // We need to iterate containers looking to see if they belong to the given network
+ for _, c := range containers {
+ if util.StringInSlice(name, c.Config().Networks) {
+ // if user passes force, we nuke containers
+ if force {
+ if err := r.RemoveContainer(ctx, c.Container, true, true); err != nil {
+ return err
+ }
+ } else {
+ // Without the the force option, we return an error
+ return errors.Errorf("%q has associated containers with it. use -f to forcibly delete containers", name)
+ }
+
}
- fmt.Printf("Deleted: %s\n", name)
+ }
+ // Before we delete the configuration file, we need to make sure we can read and parse
+ // it to get the network interface name so we can remove that too
+ interfaceName, err := network.GetInterfaceNameFromConfig(cniPath)
+ if err != nil {
+ return errors.Wrapf(err, "failed to find network interface name in %q", cniPath)
+ }
+ liveNetworkNames, err := network.GetLiveNetworkNames()
+ if err != nil {
+ return errors.Wrapf(err, "failed to get live network names")
+ }
+ if util.StringInSlice(interfaceName, liveNetworkNames) {
+ if err := network.RemoveInterface(interfaceName); err != nil {
+ return errors.Wrapf(err, "failed to delete the network interface %q", interfaceName)
+ }
+ }
+ // Remove the configuration file
+ if err := os.Remove(cniPath); err != nil {
+ return errors.Wrapf(err, "failed to remove network configuration file %q", cniPath)
}
return nil
}
diff --git a/pkg/network/devices.go b/pkg/network/devices.go
index 26101b6f7..85068a7d1 100644
--- a/pkg/network/devices.go
+++ b/pkg/network/devices.go
@@ -2,8 +2,10 @@ package network
import (
"fmt"
- "github.com/containers/libpod/pkg/util"
+ "os/exec"
+ "github.com/containers/libpod/pkg/util"
+ "github.com/containers/libpod/utils"
"github.com/sirupsen/logrus"
)
@@ -39,3 +41,15 @@ func GetFreeDeviceName() (string, error) {
}
return deviceName, nil
}
+
+// RemoveInterface removes an interface by the given name
+func RemoveInterface(interfaceName string) error {
+ // Make sure we have the ip command on the system
+ ipPath, err := exec.LookPath("ip")
+ if err != nil {
+ return err
+ }
+ // Delete the network interface
+ _, err = utils.ExecCmd(ipPath, []string{"link", "del", interfaceName}...)
+ return err
+}
diff --git a/pkg/network/files.go b/pkg/network/files.go
index 80fde5e17..d55ec2dfd 100644
--- a/pkg/network/files.go
+++ b/pkg/network/files.go
@@ -86,6 +86,7 @@ func GetNetworksFromFilesystem() ([]*allocator.Net, error) {
return nil, err
}
cniNetworks = append(cniNetworks, &ipamConf)
+ break
}
}
}
@@ -105,3 +106,26 @@ func GetNetworkNamesFromFileSystem() ([]string, error) {
}
return networkNames, nil
}
+
+// GetInterfaceNameFromConfig returns the interface name for the bridge plugin
+func GetInterfaceNameFromConfig(path string) (string, error) {
+ var name string
+ conf, err := libcni.ConfListFromFile(path)
+ if err != nil {
+ return "", err
+ }
+ for _, cniplugin := range conf.Plugins {
+ if cniplugin.Network.Type == "bridge" {
+ plugin := make(map[string]interface{})
+ if err := json.Unmarshal(cniplugin.Bytes, &plugin); err != nil {
+ return "", err
+ }
+ name = plugin["bridge"].(string)
+ break
+ }
+ }
+ if len(name) == 0 {
+ return "", errors.New("unable to find interface name for network")
+ }
+ return name, nil
+}
diff --git a/test/e2e/exec_test.go b/test/e2e/exec_test.go
index f3190978c..670269eab 100644
--- a/test/e2e/exec_test.go
+++ b/test/e2e/exec_test.go
@@ -120,6 +120,18 @@ var _ = Describe("Podman exec", func() {
Expect(session.ExitCode()).To(Equal(100))
})
+ It("podman exec pseudo-terminal sanity check", func() {
+ setup := podmanTest.Podman([]string{"run", "--detach", "--name", "test1", fedoraMinimal, "sleep", "+Inf"})
+ setup.WaitWithDefaultTimeout()
+ Expect(setup.ExitCode()).To(Equal(0))
+
+ session := podmanTest.Podman([]string{"exec", "--interactive", "--tty", "test1", "/usr/bin/stty", "--all"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ match, _ := session.GrepString(" onlcr")
+ Expect(match).Should(BeTrue())
+ })
+
It("podman exec simple command with user", func() {
setup := podmanTest.RunTopContainer("test1")
setup.WaitWithDefaultTimeout()