mirror of https://github.com/containers/podman.git
add network connect|disconnect compat endpoints
this enables the ability to connect and disconnect a container from a given network. it is only for the compatibility layer. some code had to be refactored to avoid circular imports. additionally, tests are being deferred temporarily due to some incompatibility/bug in either docker-py or our stack. Signed-off-by: baude <bbaude@redhat.com>
This commit is contained in:
parent
286d356db0
commit
a3e0b7d117
|
@ -0,0 +1,47 @@
|
|||
package network
|
||||
|
||||
import (
|
||||
"github.com/containers/common/pkg/completion"
|
||||
"github.com/containers/podman/v2/cmd/podman/common"
|
||||
"github.com/containers/podman/v2/cmd/podman/registry"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
networkConnectDescription = `Add container to a network`
|
||||
networkConnectCommand = &cobra.Command{
|
||||
Use: "connect [options] NETWORK CONTAINER",
|
||||
Short: "network connect",
|
||||
Long: networkConnectDescription,
|
||||
RunE: networkConnect,
|
||||
Example: `podman network connect web secondary`,
|
||||
Args: cobra.ExactArgs(2),
|
||||
ValidArgsFunction: common.AutocompleteNetworks,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
networkConnectOptions entities.NetworkConnectOptions
|
||||
)
|
||||
|
||||
func networkConnectFlags(cmd *cobra.Command) {
|
||||
flags := cmd.Flags()
|
||||
aliasFlagName := "alias"
|
||||
flags.StringSliceVar(&networkConnectOptions.Aliases, aliasFlagName, []string{}, "network scoped alias for container")
|
||||
_ = cmd.RegisterFlagCompletionFunc(aliasFlagName, completion.AutocompleteNone)
|
||||
}
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: networkConnectCommand,
|
||||
Parent: networkCmd,
|
||||
})
|
||||
networkConnectFlags(networkConnectCommand)
|
||||
}
|
||||
|
||||
func networkConnect(cmd *cobra.Command, args []string) error {
|
||||
networkConnectOptions.Container = args[1]
|
||||
return registry.ContainerEngine().NetworkConnect(registry.Context(), args[0], networkConnectOptions)
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package network
|
||||
|
||||
import (
|
||||
"github.com/containers/podman/v2/cmd/podman/common"
|
||||
"github.com/containers/podman/v2/cmd/podman/registry"
|
||||
"github.com/containers/podman/v2/pkg/domain/entities"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
var (
|
||||
networkDisconnectDescription = `Remove container from a network`
|
||||
networkDisconnectCommand = &cobra.Command{
|
||||
Use: "disconnect [options] NETWORK CONTAINER",
|
||||
Short: "network rm",
|
||||
Long: networkDisconnectDescription,
|
||||
RunE: networkDisconnect,
|
||||
Example: `podman network disconnect web secondary`,
|
||||
Args: cobra.ExactArgs(2),
|
||||
ValidArgsFunction: common.AutocompleteNetworks,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
networkDisconnectOptions entities.NetworkDisconnectOptions
|
||||
)
|
||||
|
||||
func networkDisconnectFlags(flags *pflag.FlagSet) {
|
||||
flags.BoolVarP(&networkDisconnectOptions.Force, "force", "f", false, "force removal of container from network")
|
||||
}
|
||||
|
||||
func init() {
|
||||
registry.Commands = append(registry.Commands, registry.CliCommand{
|
||||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
|
||||
Command: networkDisconnectCommand,
|
||||
Parent: networkCmd,
|
||||
})
|
||||
flags := networkDisconnectCommand.Flags()
|
||||
networkDisconnectFlags(flags)
|
||||
}
|
||||
|
||||
func networkDisconnect(cmd *cobra.Command, args []string) error {
|
||||
networkDisconnectOptions.Container = args[1]
|
||||
return registry.ContainerEngine().NetworkDisconnect(registry.Context(), args[0], networkDisconnectOptions)
|
||||
}
|
|
@ -47,6 +47,8 @@
|
|||
| [podman-mount(1)](https://podman.readthedocs.io/en/latest/markdown/podman-mount.1.html) | Mount a working container's root filesystem |
|
||||
| [podman-network(1)](https://podman.readthedocs.io/en/latest/network.html) | Manage Podman CNI networks |
|
||||
| [podman-network-create(1)](https://podman.readthedocs.io/en/latest/markdown/podman-network-create.1.html) | Create a CNI network |
|
||||
| [podman-network-connect(1)](https://podman.readthedocs.io/en/latest/markdown/podman-network-connect.1.html) | Connect a container to a CNI network |
|
||||
| [podman-network-disconnect(1)](https://podman.readthedocs.io/en/latest/markdown/podman-network-dosconnect.1.html) | Disconnect a container from a CNI network |
|
||||
| [podman-network-inspect(1)](https://podman.readthedocs.io/en/latest/markdown/podman-network-inspect.1.html) | Displays the raw CNI network configuration for one or more networks |
|
||||
| [podman-network-ls(1)](https://podman.readthedocs.io/en/latest/markdown/podman-network-ls.1.html) | Display a summary of CNI networks |
|
||||
| [podman-network-rm(1)](https://podman.readthedocs.io/en/latest/markdown/podman-network-rm.1.html) | Remove one or more CNI networks |
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
% podman-network-connect(1)
|
||||
|
||||
## NAME
|
||||
podman\-network\-connect - Connect a container to a network
|
||||
|
||||
## SYNOPSIS
|
||||
**podman network connect** [*options*] network container
|
||||
|
||||
## DESCRIPTION
|
||||
Connects a container to a network. A container can be connected to a network by name or by ID.
|
||||
Once connected, the container can communicate with other containers in the same network.
|
||||
|
||||
## OPTIONS
|
||||
#### **--alias**
|
||||
Add network-scoped alias for the container. If the network is using the `dnsname` CNI plugin, these aliases
|
||||
can be used for name resolution on the given network. Multiple *--alias* options may be specificed as input.
|
||||
|
||||
## EXAMPLE
|
||||
|
||||
Connect a container named *web* to a network named *test*
|
||||
```
|
||||
podman network connect test web
|
||||
```
|
||||
|
||||
Connect a container name *web* to a network named *test* with two aliases: web1 and web2
|
||||
```
|
||||
podman network connect --alias web1 --alias web2 test web
|
||||
```
|
||||
|
||||
## SEE ALSO
|
||||
podman(1), podman-network(1), podman-network-disconnect(1), podman-network-inspect(1)
|
||||
|
||||
## HISTORY
|
||||
November 2020, Originally compiled by Brent Baude <bbaude@redhat.com>
|
|
@ -0,0 +1,29 @@
|
|||
% podman-network-disconnect(1)
|
||||
|
||||
## NAME
|
||||
podman\-network\-disconnect - Disconnect a container from a network
|
||||
|
||||
## SYNOPSIS
|
||||
**podman network disconnect** [*options*] network container
|
||||
|
||||
## DESCRIPTION
|
||||
Disconnects a container from a network.
|
||||
|
||||
## OPTIONS
|
||||
#### **--force**, **-f**
|
||||
|
||||
Force the container to disconnect from a network
|
||||
|
||||
## EXAMPLE
|
||||
Disconnect a container named *web* from a network called *test*.
|
||||
|
||||
```
|
||||
podman network disconnect test web
|
||||
```
|
||||
|
||||
|
||||
## SEE ALSO
|
||||
podman(1), podman-network(1), podman-network-connect(1)
|
||||
|
||||
## HISTORY
|
||||
November 2020, Originally compiled by Brent Baude <bbaude@redhat.com>
|
|
@ -13,7 +13,9 @@ The network command manages CNI networks for Podman. It is not supported for roo
|
|||
|
||||
| Command | Man Page | Description |
|
||||
| ------- | --------------------------------------------------- | ---------------------------------------------------------------------------- |
|
||||
| connect | [podman-network-connect(1)](podman-network-connect.1.md)| Connect a container to a network|
|
||||
| create | [podman-network-create(1)](podman-network-create.1.md)| Create a Podman CNI network|
|
||||
| disconnect | [podman-network-disconnect(1)](podman-network-disconnect.1.md)| Disconnect a container from a network|
|
||||
| inspect | [podman-network-inspect(1)](podman-network-inspect.1.md)| Displays the raw CNI network configuration for one or more networks|
|
||||
| ls | [podman-network-ls(1)](podman-network-ls.1.md)| Display a summary of CNI networks |
|
||||
| rm | [podman-network-rm(1)](podman-network-rm.1.md)| Remove one or more CNI networks |
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
Network
|
||||
=======
|
||||
|
||||
:doc:`connect <markdown/podman-network-connect.1>` network connect
|
||||
|
||||
:doc:`create <markdown/podman-network-create.1>` network create
|
||||
|
||||
:doc:`disconnect <markdown/podman-network-disconnect.1>` network disconnect
|
||||
|
||||
:doc:`inspect <markdown/podman-network-inspect.1>` network inspect
|
||||
|
||||
:doc:`ls <markdown/podman-network-ls.1>` network list
|
||||
|
|
|
@ -206,6 +206,10 @@ type ContainerState struct {
|
|||
// and not delegated to the OCI runtime.
|
||||
ExtensionStageHooks map[string][]spec.Hook `json:"extensionStageHooks,omitempty"`
|
||||
|
||||
// NetInterfaceDescriptions describe the relationship between a CNI
|
||||
// network and an interface names
|
||||
NetInterfaceDescriptions ContainerNetworkDescriptions `json:"networkDescriptions,omitempty"`
|
||||
|
||||
// containerPlatformState holds platform-specific container state.
|
||||
containerPlatformState
|
||||
}
|
||||
|
@ -244,6 +248,10 @@ type ContainerImageVolume struct {
|
|||
ReadWrite bool `json:"rw"`
|
||||
}
|
||||
|
||||
// ContainerNetworkDescriptions describes the relationship between the CNI
|
||||
// network and the ethN where N is an integer
|
||||
type ContainerNetworkDescriptions map[string]int
|
||||
|
||||
// Config accessors
|
||||
// Unlocked
|
||||
|
||||
|
@ -1102,3 +1110,19 @@ func (c *Container) networksByNameIndex() (map[string]int, error) {
|
|||
}
|
||||
return networkNamesByIndex, nil
|
||||
}
|
||||
|
||||
// add puts the new given CNI network name into the tracking map
|
||||
// and assigns it a new integer based on the map length
|
||||
func (d ContainerNetworkDescriptions) add(networkName string) {
|
||||
d[networkName] = len(d)
|
||||
}
|
||||
|
||||
// getInterfaceByName returns a formatted interface name for a given
|
||||
// network along with a bool as to whether the network existed
|
||||
func (d ContainerNetworkDescriptions) getInterfaceByName(networkName string) (string, bool) {
|
||||
val, exists := d[networkName]
|
||||
if !exists {
|
||||
return "", exists
|
||||
}
|
||||
return fmt.Sprintf("eth%d", val), exists
|
||||
}
|
||||
|
|
|
@ -178,4 +178,7 @@ var (
|
|||
// ErrStoreNotInitialized indicates that the container storage was never
|
||||
// initialized.
|
||||
ErrStoreNotInitialized = errors.New("the container storage was never initialized")
|
||||
|
||||
// ErrNoNetwork indicates that a container has no net namespace, like network=none
|
||||
ErrNoNetwork = errors.New("container has no network namespace")
|
||||
)
|
||||
|
|
|
@ -50,6 +50,18 @@ func (c *Container) newContainerExitedEvent(exitCode int32) {
|
|||
}
|
||||
}
|
||||
|
||||
// netNetworkEvent creates a new event based on a network connect/disconnect
|
||||
func (c *Container) newNetworkEvent(status events.Status, netName string) {
|
||||
e := events.NewEvent(status)
|
||||
e.ID = c.ID()
|
||||
e.Name = c.Name()
|
||||
e.Type = events.Network
|
||||
e.Network = netName
|
||||
if err := c.runtime.eventer.Write(e); err != nil {
|
||||
logrus.Errorf("unable to write pod event: %q", err)
|
||||
}
|
||||
}
|
||||
|
||||
// newPodEvent creates a new event for a libpod pod
|
||||
func (p *Pod) newPodEvent(status events.Status) {
|
||||
e := events.NewEvent(status)
|
||||
|
|
|
@ -30,6 +30,8 @@ type Event struct {
|
|||
Image string `json:",omitempty"`
|
||||
// Name where applicable
|
||||
Name string `json:",omitempty"`
|
||||
// Network is the network name in a network event
|
||||
Network string `json:"network,omitempty"`
|
||||
// Status describes the event that occurred
|
||||
Status Status
|
||||
// Time the event occurred
|
||||
|
@ -101,6 +103,8 @@ const (
|
|||
Container Type = "container"
|
||||
// Image - event is related to images
|
||||
Image Type = "image"
|
||||
// Network - event is related to networks
|
||||
Network Type = "network"
|
||||
// Pod - event is related to pods
|
||||
Pod Type = "pod"
|
||||
// System - event is related to Podman whole and not to any specific
|
||||
|
@ -141,6 +145,10 @@ const (
|
|||
LoadFromArchive Status = "loadfromarchive"
|
||||
// Mount ...
|
||||
Mount Status = "mount"
|
||||
// NetworkConnect
|
||||
NetworkConnect Status = "connect"
|
||||
// NetworkDisconnect
|
||||
NetworkDisconnect Status = "disconnect"
|
||||
// Pause ...
|
||||
Pause Status = "pause"
|
||||
// Prune ...
|
||||
|
|
|
@ -77,6 +77,8 @@ func (e *Event) ToHumanReadable() string {
|
|||
}
|
||||
}
|
||||
humanFormat += ")"
|
||||
case Network:
|
||||
humanFormat = fmt.Sprintf("%s %s %s %s (container=%s, name=%s)", e.Time, e.Type, e.Status, e.ID, e.ID, e.Network)
|
||||
case Image:
|
||||
humanFormat = fmt.Sprintf("%s %s %s %s %s", e.Time, e.Type, e.Status, e.ID, e.Name)
|
||||
case System:
|
||||
|
@ -115,6 +117,8 @@ func StringToType(name string) (Type, error) {
|
|||
return Container, nil
|
||||
case Image.String():
|
||||
return Image, nil
|
||||
case Network.String():
|
||||
return Network, nil
|
||||
case Pod.String():
|
||||
return Pod, nil
|
||||
case System.String():
|
||||
|
@ -162,6 +166,10 @@ func StringToStatus(name string) (Status, error) {
|
|||
return LoadFromArchive, nil
|
||||
case Mount.String():
|
||||
return Mount, nil
|
||||
case NetworkConnect.String():
|
||||
return NetworkConnect, nil
|
||||
case NetworkDisconnect.String():
|
||||
return NetworkDisconnect, nil
|
||||
case Pause.String():
|
||||
return Pause, nil
|
||||
case Prune.String():
|
||||
|
|
|
@ -56,6 +56,9 @@ func (e EventJournalD) Write(ee Event) error {
|
|||
}
|
||||
m["PODMAN_LABELS"] = string(b)
|
||||
}
|
||||
case Network:
|
||||
m["PODMAN_ID"] = ee.ID
|
||||
m["PODMAN_NETWORK_NAME"] = ee.Network
|
||||
case Volume:
|
||||
m["PODMAN_NAME"] = ee.Name
|
||||
}
|
||||
|
@ -197,6 +200,9 @@ func newEventFromJournalEntry(entry *sdjournal.JournalEntry) (*Event, error) { /
|
|||
newEvent.Details = Details{Attributes: labels}
|
||||
}
|
||||
}
|
||||
case Network:
|
||||
newEvent.ID = entry.Fields["PODMAN_ID"]
|
||||
newEvent.Network = entry.Fields["PODMAN_NETWORK_NAME"]
|
||||
case Image:
|
||||
newEvent.ID = entry.Fields["PODMAN_ID"]
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ func (e EventLogFile) Read(ctx context.Context, options ReadOptions) error {
|
|||
return err
|
||||
}
|
||||
switch event.Type {
|
||||
case Image, Volume, Pod, System, Container:
|
||||
case Image, Volume, Pod, System, Container, Network:
|
||||
// no-op
|
||||
default:
|
||||
return errors.Errorf("event type %s is not valid in %s", event.Type.String(), e.options.LogFilePath)
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
cnitypes "github.com/containernetworking/cni/pkg/types/current"
|
||||
"github.com/containernetworking/plugins/pkg/ns"
|
||||
"github.com/containers/podman/v2/libpod/define"
|
||||
"github.com/containers/podman/v2/libpod/events"
|
||||
"github.com/containers/podman/v2/libpod/network"
|
||||
"github.com/containers/podman/v2/pkg/errorhandling"
|
||||
"github.com/containers/podman/v2/pkg/netns"
|
||||
|
@ -34,16 +35,16 @@ import (
|
|||
)
|
||||
|
||||
// Get an OCICNI network config
|
||||
func (r *Runtime) getPodNetwork(id, name, nsPath string, networks []string, ports []ocicni.PortMapping, staticIP net.IP, staticMAC net.HardwareAddr) ocicni.PodNetwork {
|
||||
func (r *Runtime) getPodNetwork(id, name, nsPath string, networks []string, ports []ocicni.PortMapping, staticIP net.IP, staticMAC net.HardwareAddr, netDescriptions ContainerNetworkDescriptions) ocicni.PodNetwork {
|
||||
var networkKey string
|
||||
if len(networks) > 0 {
|
||||
// This is inconsistent for >1 network, but it's probably the
|
||||
// This is inconsistent for >1 ctrNetwork, but it's probably the
|
||||
// best we can do.
|
||||
networkKey = networks[0]
|
||||
} else {
|
||||
networkKey = r.netPlugin.GetDefaultNetworkName()
|
||||
}
|
||||
network := ocicni.PodNetwork{
|
||||
ctrNetwork := ocicni.PodNetwork{
|
||||
Name: name,
|
||||
Namespace: name, // TODO is there something else we should put here? We don't know about Kube namespaces
|
||||
ID: id,
|
||||
|
@ -55,9 +56,12 @@ func (r *Runtime) getPodNetwork(id, name, nsPath string, networks []string, port
|
|||
|
||||
// If we have extra networks, add them
|
||||
if len(networks) > 0 {
|
||||
network.Networks = make([]ocicni.NetAttachment, len(networks))
|
||||
ctrNetwork.Networks = make([]ocicni.NetAttachment, len(networks))
|
||||
for i, netName := range networks {
|
||||
network.Networks[i].Name = netName
|
||||
ctrNetwork.Networks[i].Name = netName
|
||||
if eth, exists := netDescriptions.getInterfaceByName(netName); exists {
|
||||
ctrNetwork.Networks[i].Ifname = eth
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,8 +70,8 @@ func (r *Runtime) getPodNetwork(id, name, nsPath string, networks []string, port
|
|||
// it's just the default.
|
||||
if len(networks) == 0 {
|
||||
// If len(networks) == 0 this is guaranteed to be the
|
||||
// default network.
|
||||
network.Networks = []ocicni.NetAttachment{{Name: networkKey}}
|
||||
// default ctrNetwork.
|
||||
ctrNetwork.Networks = []ocicni.NetAttachment{{Name: networkKey}}
|
||||
}
|
||||
var rt ocicni.RuntimeConfig = ocicni.RuntimeConfig{PortMappings: ports}
|
||||
if staticIP != nil {
|
||||
|
@ -76,12 +80,12 @@ func (r *Runtime) getPodNetwork(id, name, nsPath string, networks []string, port
|
|||
if staticMAC != nil {
|
||||
rt.MAC = staticMAC.String()
|
||||
}
|
||||
network.RuntimeConfig = map[string]ocicni.RuntimeConfig{
|
||||
ctrNetwork.RuntimeConfig = map[string]ocicni.RuntimeConfig{
|
||||
networkKey: rt,
|
||||
}
|
||||
}
|
||||
|
||||
return network
|
||||
return ctrNetwork
|
||||
}
|
||||
|
||||
// Create and configure a new network namespace for a container
|
||||
|
@ -110,7 +114,12 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Re
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
podNetwork := r.getPodNetwork(ctr.ID(), podName, ctrNS.Path(), networks, ctr.config.PortMappings, requestedIP, requestedMAC)
|
||||
|
||||
// Update container map of interface descriptions
|
||||
if err := ctr.setupNetworkDescriptions(networks); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
podNetwork := r.getPodNetwork(ctr.ID(), podName, ctrNS.Path(), networks, ctr.config.PortMappings, requestedIP, requestedMAC, ctr.state.NetInterfaceDescriptions)
|
||||
aliases, err := ctr.runtime.state.GetAllNetworkAliases(ctr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -760,7 +769,7 @@ func (r *Runtime) teardownNetNS(ctr *Container) error {
|
|||
requestedMAC = ctr.config.StaticMAC
|
||||
}
|
||||
|
||||
podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), networks, ctr.config.PortMappings, requestedIP, requestedMAC)
|
||||
podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), networks, ctr.config.PortMappings, requestedIP, requestedMAC, ContainerNetworkDescriptions{})
|
||||
|
||||
if err := r.netPlugin.TearDownPod(podNetwork); err != nil {
|
||||
return errors.Wrapf(err, "error tearing down CNI namespace configuration for container %s", ctr.ID())
|
||||
|
@ -934,6 +943,29 @@ func (c *Container) getContainerNetworkInfo() (*define.InspectNetworkSettings, e
|
|||
return settings, nil
|
||||
}
|
||||
|
||||
// setupNetworkDescriptions adds networks and eth values to the container's
|
||||
// network descriptions
|
||||
func (c *Container) setupNetworkDescriptions(networks []string) error {
|
||||
// if the map is nil and we have networks
|
||||
if c.state.NetInterfaceDescriptions == nil && len(networks) > 0 {
|
||||
c.state.NetInterfaceDescriptions = make(ContainerNetworkDescriptions)
|
||||
}
|
||||
origLen := len(c.state.NetInterfaceDescriptions)
|
||||
for _, n := range networks {
|
||||
// if the network is not in the map, add it
|
||||
if _, exists := c.state.NetInterfaceDescriptions[n]; !exists {
|
||||
c.state.NetInterfaceDescriptions.add(n)
|
||||
}
|
||||
}
|
||||
// if the map changed, we need to save the container state
|
||||
if origLen != len(c.state.NetInterfaceDescriptions) {
|
||||
if err := c.save(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// resultToBasicNetworkConfig produces an InspectBasicNetworkConfig from a CNI
|
||||
// result
|
||||
func resultToBasicNetworkConfig(result *cnitypes.Result) (define.InspectBasicNetworkConfig, error) {
|
||||
|
@ -984,19 +1016,14 @@ func (w *logrusDebugWriter) Write(p []byte) (int, error) {
|
|||
return len(p), nil
|
||||
}
|
||||
|
||||
// DisconnectContainerFromNetwork removes a container from its CNI network
|
||||
func (r *Runtime) DisconnectContainerFromNetwork(nameOrID, netName string, force bool) error {
|
||||
ctr, err := r.LookupContainer(nameOrID)
|
||||
// NetworkDisconnect removes a container from the network
|
||||
func (c *Container) NetworkDisconnect(nameOrID, netName string, force bool) error {
|
||||
networks, err := c.networksByNameIndex()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
networks, err := ctr.networksByNameIndex()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
exists, err := network.Exists(r.config, netName)
|
||||
exists, err := network.Exists(c.runtime.config, netName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1009,48 +1036,48 @@ func (r *Runtime) DisconnectContainerFromNetwork(nameOrID, netName string, force
|
|||
return errors.Errorf("container %s is not connected to network %s", nameOrID, netName)
|
||||
}
|
||||
|
||||
ctr.lock.Lock()
|
||||
defer ctr.lock.Unlock()
|
||||
if err := ctr.syncContainer(); err != nil {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
if err := c.syncContainer(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
podConfig := r.getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), []string{netName}, ctr.config.PortMappings, nil, nil)
|
||||
if err := r.netPlugin.TearDownPod(podConfig); err != nil {
|
||||
if c.state.State != define.ContainerStateRunning {
|
||||
return errors.Wrapf(define.ErrCtrStateInvalid, "cannot disconnect container %s from networks as it is not running", nameOrID)
|
||||
}
|
||||
if c.state.NetNS == nil {
|
||||
return errors.Wrapf(define.ErrNoNetwork, "unable to disconnect %s from %s", nameOrID, netName)
|
||||
}
|
||||
podConfig := c.runtime.getPodNetwork(c.ID(), c.Name(), c.state.NetNS.Path(), []string{netName}, c.config.PortMappings, nil, nil, c.state.NetInterfaceDescriptions)
|
||||
if err := c.runtime.netPlugin.TearDownPod(podConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.state.NetworkDisconnect(ctr, netName); err != nil {
|
||||
if err := c.runtime.state.NetworkDisconnect(c, netName); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// update network status
|
||||
networkStatus := ctr.state.NetworkStatus
|
||||
// if len is one and we confirmed earlier that the container is in
|
||||
// fact connected to the network, then just return an empty slice
|
||||
if len(networkStatus) == 1 {
|
||||
ctr.state.NetworkStatus = make([]*cnitypes.Result, 0)
|
||||
} else {
|
||||
// clip out the index of the network
|
||||
networkStatus[len(networkStatus)-1], networkStatus[index] = networkStatus[index], networkStatus[len(networkStatus)-1]
|
||||
// shorten the slice by one
|
||||
ctr.state.NetworkStatus = networkStatus[:len(networkStatus)-1]
|
||||
networkStatus := c.state.NetworkStatus
|
||||
// clip out the index of the network
|
||||
tmpNetworkStatus := make([]*cnitypes.Result, len(networkStatus)-1)
|
||||
for k, v := range networkStatus {
|
||||
if index != k {
|
||||
tmpNetworkStatus = append(tmpNetworkStatus, v)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
c.state.NetworkStatus = tmpNetworkStatus
|
||||
c.newNetworkEvent(events.NetworkDisconnect, netName)
|
||||
return c.save()
|
||||
}
|
||||
|
||||
// ConnectContainerToNetwork connects a container to a CNI network
|
||||
func (r *Runtime) ConnectContainerToNetwork(nameOrID, netName string, aliases []string) error {
|
||||
ctr, err := r.LookupContainer(nameOrID)
|
||||
// ConnnectNetwork connects a container to a given network
|
||||
func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) error {
|
||||
networks, err := c.networksByNameIndex()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
networks, err := ctr.networksByNameIndex()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
exists, err := network.Exists(r.config, netName)
|
||||
exists, err := network.Exists(c.runtime.config, netName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1058,25 +1085,34 @@ func (r *Runtime) ConnectContainerToNetwork(nameOrID, netName string, aliases []
|
|||
return errors.Wrap(define.ErrNoSuchNetwork, netName)
|
||||
}
|
||||
|
||||
_, nameExists := networks[netName]
|
||||
if !nameExists && len(networks) > 0 {
|
||||
return errors.Errorf("container %s is not connected to network %s", nameOrID, netName)
|
||||
}
|
||||
|
||||
ctr.lock.Lock()
|
||||
defer ctr.lock.Unlock()
|
||||
if err := ctr.syncContainer(); err != nil {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
if err := c.syncContainer(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := r.state.NetworkConnect(ctr, netName, aliases); err != nil {
|
||||
if c.state.State != define.ContainerStateRunning {
|
||||
return errors.Wrapf(define.ErrCtrStateInvalid, "cannot connect container %s to networks as it is not running", nameOrID)
|
||||
}
|
||||
if c.state.NetNS == nil {
|
||||
return errors.Wrapf(define.ErrNoNetwork, "unable to connect %s to %s", nameOrID, netName)
|
||||
}
|
||||
if err := c.runtime.state.NetworkConnect(c, netName, aliases); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
podConfig := r.getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), []string{netName}, ctr.config.PortMappings, nil, nil)
|
||||
ctrNetworks, err := c.networks()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Update network descriptions
|
||||
if err := c.setupNetworkDescriptions(ctrNetworks); err != nil {
|
||||
return err
|
||||
}
|
||||
podConfig := c.runtime.getPodNetwork(c.ID(), c.Name(), c.state.NetNS.Path(), []string{netName}, c.config.PortMappings, nil, nil, c.state.NetInterfaceDescriptions)
|
||||
podConfig.Aliases = make(map[string][]string, 1)
|
||||
podConfig.Aliases[netName] = aliases
|
||||
results, err := r.netPlugin.SetUpPod(podConfig)
|
||||
results, err := c.runtime.netPlugin.SetUpPod(podConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1094,11 +1130,11 @@ func (r *Runtime) ConnectContainerToNetwork(nameOrID, netName string, aliases []
|
|||
}
|
||||
|
||||
// update network status
|
||||
networkStatus := ctr.state.NetworkStatus
|
||||
networkStatus := c.state.NetworkStatus
|
||||
// if len is one and we confirmed earlier that the container is in
|
||||
// fact connected to the network, then just return an empty slice
|
||||
if len(networkStatus) == 0 {
|
||||
ctr.state.NetworkStatus = append(ctr.state.NetworkStatus, networkResults...)
|
||||
c.state.NetworkStatus = append(c.state.NetworkStatus, networkResults...)
|
||||
} else {
|
||||
// build a list of network names so we can sort and
|
||||
// get the new name's index
|
||||
|
@ -1117,5 +1153,30 @@ func (r *Runtime) ConnectContainerToNetwork(nameOrID, netName string, aliases []
|
|||
copy(networkStatus[index+1:], networkStatus[index:])
|
||||
networkStatus[index] = networkResults[0]
|
||||
}
|
||||
return nil
|
||||
c.newNetworkEvent(events.NetworkConnect, netName)
|
||||
return c.save()
|
||||
}
|
||||
|
||||
// DisconnectContainerFromNetwork removes a container from its CNI network
|
||||
func (r *Runtime) DisconnectContainerFromNetwork(nameOrID, netName string, force bool) error {
|
||||
if rootless.IsRootless() {
|
||||
return errors.New("network connect is not enabled for rootless containers")
|
||||
}
|
||||
ctr, err := r.LookupContainer(nameOrID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ctr.NetworkDisconnect(nameOrID, netName, force)
|
||||
}
|
||||
|
||||
// ConnectContainerToNetwork connects a container to a CNI network
|
||||
func (r *Runtime) ConnectContainerToNetwork(nameOrID, netName string, aliases []string) error {
|
||||
if rootless.IsRootless() {
|
||||
return errors.New("network disconnect is not enabled for rootless containers")
|
||||
}
|
||||
ctr, err := r.LookupContainer(nameOrID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ctr.NetworkConnect(nameOrID, netName, aliases)
|
||||
}
|
||||
|
|
|
@ -131,3 +131,29 @@ func InspectNetwork(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
utils.WriteResponse(w, http.StatusOK, reports)
|
||||
}
|
||||
|
||||
// Connect adds a container to a network
|
||||
func Connect(w http.ResponseWriter, r *http.Request) {
|
||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||
|
||||
var netConnect entities.NetworkConnectOptions
|
||||
if err := json.NewDecoder(r.Body).Decode(&netConnect); err != nil {
|
||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
|
||||
return
|
||||
}
|
||||
name := utils.GetName(r)
|
||||
err := runtime.ConnectContainerToNetwork(netConnect.Container, name, netConnect.Aliases)
|
||||
if err != nil {
|
||||
if errors.Cause(err) == define.ErrNoSuchCtr {
|
||||
utils.ContainerNotFound(w, netConnect.Container, err)
|
||||
return
|
||||
}
|
||||
if errors.Cause(err) == define.ErrNoSuchNetwork {
|
||||
utils.Error(w, "network not found", http.StatusNotFound, err)
|
||||
return
|
||||
}
|
||||
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
utils.WriteResponse(w, http.StatusOK, "OK")
|
||||
}
|
||||
|
|
|
@ -253,5 +253,59 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error {
|
|||
// 500:
|
||||
// $ref: "#/responses/InternalError"
|
||||
r.HandleFunc(VersionedPath("/libpod/networks/create"), s.APIHandler(libpod.CreateNetwork)).Methods(http.MethodPost)
|
||||
// swagger:operation POST /libpod/networks/{name}/connect libpod libpodConnectNetwork
|
||||
// ---
|
||||
// tags:
|
||||
// - networks
|
||||
// summary: Connect container to network
|
||||
// description: Connect a container to a network.
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - in: path
|
||||
// name: name
|
||||
// type: string
|
||||
// required: true
|
||||
// description: the name of the network
|
||||
// - in: body
|
||||
// name: create
|
||||
// description: attributes for connecting a container to a network
|
||||
// schema:
|
||||
// $ref: "#/definitions/NetworkConnectRequest"
|
||||
// responses:
|
||||
// 200:
|
||||
// description: OK
|
||||
// 404:
|
||||
// $ref: "#/responses/NoSuchNetwork"
|
||||
// 500:
|
||||
// $ref: "#/responses/InternalError"
|
||||
r.HandleFunc(VersionedPath("/libpod/networks/{name}/connect"), s.APIHandler(libpod.Connect)).Methods(http.MethodPost)
|
||||
// swagger:operation POST /libpod/networks/{name}/disconnect libpod libpodDisconnectNetwork
|
||||
// ---
|
||||
// tags:
|
||||
// - networks
|
||||
// summary: Disconnect container from network
|
||||
// description: Disconnect a container from a network.
|
||||
// produces:
|
||||
// - application/json
|
||||
// parameters:
|
||||
// - in: path
|
||||
// name: name
|
||||
// type: string
|
||||
// required: true
|
||||
// description: the name of the network
|
||||
// - in: body
|
||||
// name: create
|
||||
// description: attributes for disconnecting a container from a network
|
||||
// schema:
|
||||
// $ref: "#/definitions/NetworkDisconnectRequest"
|
||||
// responses:
|
||||
// 200:
|
||||
// description: OK
|
||||
// 404:
|
||||
// $ref: "#/responses/NoSuchNetwork"
|
||||
// 500:
|
||||
// $ref: "#/responses/InternalError"
|
||||
r.HandleFunc(VersionedPath("/libpod/networks/{name}/disconnect"), s.APIHandler(compat.Disconnect)).Methods(http.MethodPost)
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -88,3 +88,41 @@ func List(ctx context.Context, options entities.NetworkListOptions) ([]*entities
|
|||
}
|
||||
return netList, response.Process(&netList)
|
||||
}
|
||||
|
||||
// Disconnect removes a container from a given network
|
||||
func Disconnect(ctx context.Context, networkName string, options entities.NetworkDisconnectOptions) error {
|
||||
conn, err := bindings.GetClient(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params := url.Values{}
|
||||
body, err := jsoniter.MarshalToString(options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stringReader := strings.NewReader(body)
|
||||
response, err := conn.DoRequest(stringReader, http.MethodPost, "/networks/%s/disconnect", params, nil, networkName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return response.Process(nil)
|
||||
}
|
||||
|
||||
// Connect adds a container to a network
|
||||
func Connect(ctx context.Context, networkName string, options entities.NetworkConnectOptions) error {
|
||||
conn, err := bindings.GetClient(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params := url.Values{}
|
||||
body, err := jsoniter.MarshalToString(options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stringReader := strings.NewReader(body)
|
||||
response, err := conn.DoRequest(stringReader, http.MethodPost, "/networks/%s/connect", params, nil, networkName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return response.Process(nil)
|
||||
}
|
||||
|
|
|
@ -50,7 +50,9 @@ type ContainerEngine interface {
|
|||
SystemPrune(ctx context.Context, options SystemPruneOptions) (*SystemPruneReport, error)
|
||||
HealthCheckRun(ctx context.Context, nameOrID string, options HealthCheckOptions) (*define.HealthCheckResults, error)
|
||||
Info(ctx context.Context) (*define.Info, error)
|
||||
NetworkConnect(ctx context.Context, networkname string, options NetworkConnectOptions) error
|
||||
NetworkCreate(ctx context.Context, name string, options NetworkCreateOptions) (*NetworkCreateReport, error)
|
||||
NetworkDisconnect(ctx context.Context, networkname string, options NetworkDisconnectOptions) error
|
||||
NetworkInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]NetworkInspectReport, []error, error)
|
||||
NetworkList(ctx context.Context, options NetworkListOptions) ([]*NetworkListReport, error)
|
||||
NetworkRm(ctx context.Context, namesOrIds []string, options NetworkRmOptions) ([]*NetworkRmReport, error)
|
||||
|
|
|
@ -49,3 +49,17 @@ type NetworkCreateOptions struct {
|
|||
type NetworkCreateReport struct {
|
||||
Filename string
|
||||
}
|
||||
|
||||
// NetworkDisconnectOptions describes options for disconnecting
|
||||
// containers from networks
|
||||
type NetworkDisconnectOptions struct {
|
||||
Container string
|
||||
Force bool
|
||||
}
|
||||
|
||||
// NetworkConnectOptions describes options for connecting
|
||||
// a container to a network
|
||||
type NetworkConnectOptions struct {
|
||||
Aliases []string
|
||||
Container string
|
||||
}
|
||||
|
|
|
@ -138,3 +138,12 @@ func ifPassesFilterTest(netconf *libcni.NetworkConfigList, filter []string) bool
|
|||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// NetworkDisconnect removes a container from a given network
|
||||
func (ic *ContainerEngine) NetworkDisconnect(ctx context.Context, networkname string, options entities.NetworkDisconnectOptions) error {
|
||||
return ic.Libpod.DisconnectContainerFromNetwork(options.Container, networkname, options.Force)
|
||||
}
|
||||
|
||||
func (ic *ContainerEngine) NetworkConnect(ctx context.Context, networkname string, options entities.NetworkConnectOptions) error {
|
||||
return ic.Libpod.ConnectContainerToNetwork(options.Container, networkname, options.Aliases)
|
||||
}
|
||||
|
|
|
@ -55,3 +55,13 @@ func (ic *ContainerEngine) NetworkRm(ctx context.Context, namesOrIds []string, o
|
|||
func (ic *ContainerEngine) NetworkCreate(ctx context.Context, name string, options entities.NetworkCreateOptions) (*entities.NetworkCreateReport, error) {
|
||||
return network.Create(ic.ClientCxt, options, &name)
|
||||
}
|
||||
|
||||
// NetworkDisconnect removes a container from a given network
|
||||
func (ic *ContainerEngine) NetworkDisconnect(ctx context.Context, networkname string, options entities.NetworkDisconnectOptions) error {
|
||||
return network.Disconnect(ic.ClientCxt, networkname, options)
|
||||
}
|
||||
|
||||
// NetworkConnect removes a container from a given network
|
||||
func (ic *ContainerEngine) NetworkConnect(ctx context.Context, networkname string, options entities.NetworkConnectOptions) error {
|
||||
return network.Connect(ic.ClientCxt, networkname, options)
|
||||
}
|
||||
|
|
|
@ -341,4 +341,157 @@ var _ = Describe("Podman network", func() {
|
|||
c3.WaitWithDefaultTimeout()
|
||||
Expect(c3.ExitCode()).To(BeZero())
|
||||
})
|
||||
|
||||
It("bad network name in disconnect should result in error", func() {
|
||||
SkipIfRootless("network connect and disconnect are only rootfull")
|
||||
dis := podmanTest.Podman([]string{"network", "disconnect", "foobar", "test"})
|
||||
dis.WaitWithDefaultTimeout()
|
||||
Expect(dis.ExitCode()).ToNot(BeZero())
|
||||
|
||||
})
|
||||
|
||||
It("bad container name in network disconnect should result in error", func() {
|
||||
SkipIfRootless("network connect and disconnect are only rootfull")
|
||||
netName := "aliasTest" + stringid.GenerateNonCryptoID()
|
||||
session := podmanTest.Podman([]string{"network", "create", netName})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
defer podmanTest.removeCNINetwork(netName)
|
||||
|
||||
dis := podmanTest.Podman([]string{"network", "disconnect", netName, "foobar"})
|
||||
dis.WaitWithDefaultTimeout()
|
||||
Expect(dis.ExitCode()).ToNot(BeZero())
|
||||
|
||||
})
|
||||
|
||||
It("podman network disconnect with invalid container state should result in error", func() {
|
||||
SkipIfRootless("network connect and disconnect are only rootfull")
|
||||
netName := "aliasTest" + stringid.GenerateNonCryptoID()
|
||||
session := podmanTest.Podman([]string{"network", "create", netName})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
defer podmanTest.removeCNINetwork(netName)
|
||||
|
||||
ctr := podmanTest.Podman([]string{"create", "--name", "test", "--network", netName, ALPINE, "top"})
|
||||
ctr.WaitWithDefaultTimeout()
|
||||
Expect(ctr.ExitCode()).To(BeZero())
|
||||
|
||||
dis := podmanTest.Podman([]string{"network", "disconnect", netName, "test"})
|
||||
dis.WaitWithDefaultTimeout()
|
||||
Expect(dis.ExitCode()).ToNot(BeZero())
|
||||
})
|
||||
|
||||
It("podman network disconnect", func() {
|
||||
SkipIfRootless("network connect and disconnect are only rootfull")
|
||||
netName := "aliasTest" + stringid.GenerateNonCryptoID()
|
||||
session := podmanTest.Podman([]string{"network", "create", netName})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
defer podmanTest.removeCNINetwork(netName)
|
||||
|
||||
ctr := podmanTest.Podman([]string{"run", "-dt", "--name", "test", "--network", netName, ALPINE, "top"})
|
||||
ctr.WaitWithDefaultTimeout()
|
||||
Expect(ctr.ExitCode()).To(BeZero())
|
||||
|
||||
exec := podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth0"})
|
||||
exec.WaitWithDefaultTimeout()
|
||||
Expect(exec.ExitCode()).To(BeZero())
|
||||
|
||||
dis := podmanTest.Podman([]string{"network", "disconnect", netName, "test"})
|
||||
dis.WaitWithDefaultTimeout()
|
||||
Expect(dis.ExitCode()).To(BeZero())
|
||||
|
||||
exec = podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth0"})
|
||||
exec.WaitWithDefaultTimeout()
|
||||
Expect(exec.ExitCode()).ToNot(BeZero())
|
||||
})
|
||||
|
||||
It("bad network name in connect should result in error", func() {
|
||||
SkipIfRootless("network connect and disconnect are only rootfull")
|
||||
dis := podmanTest.Podman([]string{"network", "connect", "foobar", "test"})
|
||||
dis.WaitWithDefaultTimeout()
|
||||
Expect(dis.ExitCode()).ToNot(BeZero())
|
||||
|
||||
})
|
||||
|
||||
It("bad container name in network connect should result in error", func() {
|
||||
SkipIfRootless("network connect and disconnect are only rootfull")
|
||||
netName := "aliasTest" + stringid.GenerateNonCryptoID()
|
||||
session := podmanTest.Podman([]string{"network", "create", netName})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
defer podmanTest.removeCNINetwork(netName)
|
||||
|
||||
dis := podmanTest.Podman([]string{"network", "connect", netName, "foobar"})
|
||||
dis.WaitWithDefaultTimeout()
|
||||
Expect(dis.ExitCode()).ToNot(BeZero())
|
||||
|
||||
})
|
||||
|
||||
It("podman connect on a container that already is connected to the network should error", func() {
|
||||
SkipIfRootless("network connect and disconnect are only rootfull")
|
||||
netName := "aliasTest" + stringid.GenerateNonCryptoID()
|
||||
session := podmanTest.Podman([]string{"network", "create", netName})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
defer podmanTest.removeCNINetwork(netName)
|
||||
|
||||
ctr := podmanTest.Podman([]string{"create", "--name", "test", "--network", netName, ALPINE, "top"})
|
||||
ctr.WaitWithDefaultTimeout()
|
||||
Expect(ctr.ExitCode()).To(BeZero())
|
||||
|
||||
con := podmanTest.Podman([]string{"network", "connect", netName, "test"})
|
||||
con.WaitWithDefaultTimeout()
|
||||
Expect(con.ExitCode()).ToNot(BeZero())
|
||||
})
|
||||
|
||||
It("podman network connect with invalid container state should result in error", func() {
|
||||
SkipIfRootless("network connect and disconnect are only rootfull")
|
||||
netName := "aliasTest" + stringid.GenerateNonCryptoID()
|
||||
session := podmanTest.Podman([]string{"network", "create", netName})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
defer podmanTest.removeCNINetwork(netName)
|
||||
|
||||
ctr := podmanTest.Podman([]string{"create", "--name", "test", "--network", netName, ALPINE, "top"})
|
||||
ctr.WaitWithDefaultTimeout()
|
||||
Expect(ctr.ExitCode()).To(BeZero())
|
||||
|
||||
dis := podmanTest.Podman([]string{"network", "connect", netName, "test"})
|
||||
dis.WaitWithDefaultTimeout()
|
||||
Expect(dis.ExitCode()).ToNot(BeZero())
|
||||
})
|
||||
|
||||
It("podman network connect", func() {
|
||||
SkipIfRemote("This requires a pending PR to be merged before it will work")
|
||||
SkipIfRootless("network connect and disconnect are only rootfull")
|
||||
netName := "aliasTest" + stringid.GenerateNonCryptoID()
|
||||
session := podmanTest.Podman([]string{"network", "create", netName})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
defer podmanTest.removeCNINetwork(netName)
|
||||
|
||||
ctr := podmanTest.Podman([]string{"run", "-dt", "--name", "test", "--network", netName, ALPINE, "top"})
|
||||
ctr.WaitWithDefaultTimeout()
|
||||
Expect(ctr.ExitCode()).To(BeZero())
|
||||
|
||||
exec := podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth0"})
|
||||
exec.WaitWithDefaultTimeout()
|
||||
Expect(exec.ExitCode()).To(BeZero())
|
||||
|
||||
// Create a second network
|
||||
newNetName := "aliasTest" + stringid.GenerateNonCryptoID()
|
||||
session = podmanTest.Podman([]string{"network", "create", newNetName})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(BeZero())
|
||||
defer podmanTest.removeCNINetwork(newNetName)
|
||||
|
||||
connect := podmanTest.Podman([]string{"network", "connect", newNetName, "test"})
|
||||
connect.WaitWithDefaultTimeout()
|
||||
Expect(connect.ExitCode()).To(BeZero())
|
||||
|
||||
exec = podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth1"})
|
||||
exec.WaitWithDefaultTimeout()
|
||||
Expect(exec.ExitCode()).To(BeZero())
|
||||
})
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue