aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/networks/connect.go33
-rw-r--r--docs/source/markdown/podman-network-connect.1.md16
-rw-r--r--libpod/networking_linux.go28
-rw-r--r--pkg/api/handlers/compat/networks.go52
-rw-r--r--pkg/api/handlers/libpod/networks.go2
-rw-r--r--pkg/bindings/network/network.go25
-rw-r--r--pkg/bindings/network/types.go13
-rw-r--r--pkg/bindings/network/types_connect_options.go33
-rw-r--r--pkg/domain/entities/network.go6
-rw-r--r--pkg/domain/infra/abi/network.go2
-rw-r--r--pkg/domain/infra/tunnel/network.go3
-rw-r--r--test/e2e/network_connect_disconnect_test.go8
12 files changed, 133 insertions, 88 deletions
diff --git a/cmd/podman/networks/connect.go b/cmd/podman/networks/connect.go
index 0d62a45df..b0ffbfe6d 100644
--- a/cmd/podman/networks/connect.go
+++ b/cmd/podman/networks/connect.go
@@ -1,9 +1,12 @@
package network
import (
+ "net"
+
"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v3/cmd/podman/common"
"github.com/containers/podman/v3/cmd/podman/registry"
+ "github.com/containers/podman/v3/libpod/network/types"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/spf13/cobra"
)
@@ -23,13 +26,28 @@ var (
var (
networkConnectOptions entities.NetworkConnectOptions
+ ipv4 net.IP
+ ipv6 net.IP
+ macAddress string
)
func networkConnectFlags(cmd *cobra.Command) {
flags := cmd.Flags()
aliasFlagName := "alias"
- flags.StringSliceVar(&networkConnectOptions.Aliases, aliasFlagName, []string{}, "network scoped alias for container")
+ flags.StringSliceVar(&networkConnectOptions.Aliases, aliasFlagName, nil, "network scoped alias for container")
_ = cmd.RegisterFlagCompletionFunc(aliasFlagName, completion.AutocompleteNone)
+
+ ipAddressFlagName := "ip"
+ flags.IPVar(&ipv4, ipAddressFlagName, nil, "set a static ipv4 address for this container network")
+ _ = cmd.RegisterFlagCompletionFunc(ipAddressFlagName, completion.AutocompleteNone)
+
+ ipv6AddressFlagName := "ip6"
+ flags.IPVar(&ipv6, ipv6AddressFlagName, nil, "set a static ipv6 address for this container network")
+ _ = cmd.RegisterFlagCompletionFunc(ipv6AddressFlagName, completion.AutocompleteNone)
+
+ macAddressFlagName := "mac-address"
+ flags.StringVar(&macAddress, macAddressFlagName, "", "set a static mac address for this container network")
+ _ = cmd.RegisterFlagCompletionFunc(macAddressFlagName, completion.AutocompleteNone)
}
func init() {
@@ -42,5 +60,18 @@ func init() {
func networkConnect(cmd *cobra.Command, args []string) error {
networkConnectOptions.Container = args[1]
+ if macAddress != "" {
+ mac, err := net.ParseMAC(macAddress)
+ if err != nil {
+ return err
+ }
+ networkConnectOptions.StaticMAC = types.HardwareAddr(mac)
+ }
+ for _, ip := range []net.IP{ipv4, ipv6} {
+ if ip != nil {
+ networkConnectOptions.StaticIPs = append(networkConnectOptions.StaticIPs, ip)
+ }
+ }
+
return registry.ContainerEngine().NetworkConnect(registry.Context(), args[0], networkConnectOptions)
}
diff --git a/docs/source/markdown/podman-network-connect.1.md b/docs/source/markdown/podman-network-connect.1.md
index b998d4b7e..c3eef4038 100644
--- a/docs/source/markdown/podman-network-connect.1.md
+++ b/docs/source/markdown/podman-network-connect.1.md
@@ -11,12 +11,21 @@ Connects a container to a network. A container can be connected to a network by
Once connected, the container can communicate with other containers in the same network.
## OPTIONS
-#### **--alias**
+#### **--alias**=*name*
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 specified as input.
NOTE: A container will only have access to aliases on the first network that it joins. This is a limitation
that will be removed in a later release.
+#### **--ip**=*address*
+Set a static ipv4 address for this container on this network.
+
+#### **--ip6**=*address*
+Set a static ipv6 address for this container on this network.
+
+#### **--mac-address**=*address*
+Set a static mac address for this container on this network.
+
## EXAMPLE
Connect a container named *web* to a network named *test*
@@ -29,6 +38,11 @@ Connect a container name *web* to a network named *test* with two aliases: web1
podman network connect --alias web1 --alias web2 test web
```
+Connect a container name *web* to a network named *test* with a static ip.
+```
+podman network connect --ip 10.89.1.13 test web
+```
+
## SEE ALSO
**[podman(1)](podman.1.md)**, **[podman-network(1)](podman-network.1.md)**, **[podman-network-disconnect(1)](podman-network-disconnect.1.md)**
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index 3f56be855..a931774f8 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -1170,7 +1170,7 @@ func (c *Container) NetworkDisconnect(nameOrID, netName string, force bool) erro
}
// ConnectNetwork connects a container to a given network
-func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) error {
+func (c *Container) NetworkConnect(nameOrID, netName string, netOpts types.PerNetworkOptions) error {
// only the bridge mode supports cni networks
if err := isBridgeNetMode(c.config.NetMode); err != nil {
return err
@@ -1202,22 +1202,20 @@ func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) e
if err != nil {
return err
}
- if !network.DNSEnabled && len(aliases) > 0 {
+ if !network.DNSEnabled && len(netOpts.Aliases) > 0 {
return errors.Wrapf(define.ErrInvalidArg, "cannot set network aliases for network %q because dns is disabled", netName)
}
+ // always add the short id as alias for docker compat
+ netOpts.Aliases = append(netOpts.Aliases, c.config.ID[:12])
- eth := getFreeInterfaceName(networks)
- if eth == "" {
- return errors.New("could not find free network interface name")
- }
-
- perNetOpt := types.PerNetworkOptions{
- // always add the short id as alias to match docker
- Aliases: append(aliases, c.config.ID[:12]),
- InterfaceName: eth,
+ if netOpts.InterfaceName == "" {
+ netOpts.InterfaceName = getFreeInterfaceName(networks)
+ if netOpts.InterfaceName == "" {
+ return errors.New("could not find free network interface name")
+ }
}
- if err := c.runtime.state.NetworkConnect(c, netName, perNetOpt); err != nil {
+ if err := c.runtime.state.NetworkConnect(c, netName, netOpts); err != nil {
return err
}
c.newNetworkEvent(events.NetworkConnect, netName)
@@ -1234,7 +1232,7 @@ func (c *Container) NetworkConnect(nameOrID, netName string, aliases []string) e
}
opts.PortMappings = c.convertPortMappings()
opts.Networks = map[string]types.PerNetworkOptions{
- netName: perNetOpt,
+ netName: netOpts,
}
results, err := c.runtime.setUpNetwork(c.state.NetNS.Path(), opts)
@@ -1290,12 +1288,12 @@ func (r *Runtime) DisconnectContainerFromNetwork(nameOrID, netName string, force
}
// ConnectContainerToNetwork connects a container to a CNI network
-func (r *Runtime) ConnectContainerToNetwork(nameOrID, netName string, aliases []string) error {
+func (r *Runtime) ConnectContainerToNetwork(nameOrID, netName string, netOpts types.PerNetworkOptions) error {
ctr, err := r.LookupContainer(nameOrID)
if err != nil {
return err
}
- return ctr.NetworkConnect(nameOrID, netName, aliases)
+ return ctr.NetworkConnect(nameOrID, netName, netOpts)
}
// normalizeNetworkName takes a network name, a partial or a full network ID and returns the network name.
diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go
index 8aab29658..db3af7d0b 100644
--- a/pkg/api/handlers/compat/networks.go
+++ b/pkg/api/handlers/compat/networks.go
@@ -299,20 +299,66 @@ func Connect(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value(api.RuntimeKey).(*libpod.Runtime)
var (
- aliases []string
netConnect types.NetworkConnect
)
if err := json.NewDecoder(r.Body).Decode(&netConnect); err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Decode()"))
return
}
+
+ netOpts := nettypes.PerNetworkOptions{}
+
name := utils.GetName(r)
if netConnect.EndpointConfig != nil {
if netConnect.EndpointConfig.Aliases != nil {
- aliases = netConnect.EndpointConfig.Aliases
+ netOpts.Aliases = netConnect.EndpointConfig.Aliases
+ }
+
+ // if IP address is provided
+ if len(netConnect.EndpointConfig.IPAddress) > 0 {
+ staticIP := net.ParseIP(netConnect.EndpointConfig.IPAddress)
+ if staticIP == nil {
+ utils.Error(w, "failed to parse the ip address", http.StatusInternalServerError,
+ errors.Errorf("failed to parse the ip address %q", netConnect.EndpointConfig.IPAddress))
+ return
+ }
+ netOpts.StaticIPs = append(netOpts.StaticIPs, staticIP)
+ }
+
+ if netConnect.EndpointConfig.IPAMConfig != nil {
+ // if IPAMConfig.IPv4Address is provided
+ if len(netConnect.EndpointConfig.IPAMConfig.IPv4Address) > 0 {
+ staticIP := net.ParseIP(netConnect.EndpointConfig.IPAMConfig.IPv4Address)
+ if staticIP == nil {
+ utils.Error(w, "failed to parse the ipv4 address", http.StatusInternalServerError,
+ errors.Errorf("failed to parse the ipv4 address %q", netConnect.EndpointConfig.IPAMConfig.IPv4Address))
+ return
+ }
+ netOpts.StaticIPs = append(netOpts.StaticIPs, staticIP)
+ }
+ // if IPAMConfig.IPv6Address is provided
+ if len(netConnect.EndpointConfig.IPAMConfig.IPv6Address) > 0 {
+ staticIP := net.ParseIP(netConnect.EndpointConfig.IPAMConfig.IPv6Address)
+ if staticIP == nil {
+ utils.Error(w, "failed to parse the ipv6 address", http.StatusInternalServerError,
+ errors.Errorf("failed to parse the ipv6 address %q", netConnect.EndpointConfig.IPAMConfig.IPv6Address))
+ return
+ }
+ netOpts.StaticIPs = append(netOpts.StaticIPs, staticIP)
+ }
+ }
+ // If MAC address is provided
+ if len(netConnect.EndpointConfig.MacAddress) > 0 {
+ staticMac, err := net.ParseMAC(netConnect.EndpointConfig.MacAddress)
+ if err != nil {
+ utils.Error(w, "failed to parse the mac address", http.StatusInternalServerError,
+ errors.Errorf("failed to parse the mac address %q", netConnect.EndpointConfig.IPAMConfig.IPv6Address))
+ return
+ }
+ netOpts.StaticMAC = nettypes.HardwareAddr(staticMac)
}
}
- err := runtime.ConnectContainerToNetwork(netConnect.Container, name, aliases)
+ err := runtime.ConnectContainerToNetwork(netConnect.Container, name, netOpts)
if err != nil {
if errors.Cause(err) == define.ErrNoSuchCtr {
utils.ContainerNotFound(w, netConnect.Container, err)
diff --git a/pkg/api/handlers/libpod/networks.go b/pkg/api/handlers/libpod/networks.go
index 1f7f2e26c..a28c3c57c 100644
--- a/pkg/api/handlers/libpod/networks.go
+++ b/pkg/api/handlers/libpod/networks.go
@@ -125,7 +125,7 @@ func Connect(w http.ResponseWriter, r *http.Request) {
return
}
name := utils.GetName(r)
- err := runtime.ConnectContainerToNetwork(netConnect.Container, name, netConnect.Aliases)
+ err := runtime.ConnectContainerToNetwork(netConnect.Container, name, netConnect.PerNetworkOptions)
if err != nil {
if errors.Cause(err) == define.ErrNoSuchCtr {
utils.ContainerNotFound(w, netConnect.Container, err)
diff --git a/pkg/bindings/network/network.go b/pkg/bindings/network/network.go
index 172598be1..66e01a016 100644
--- a/pkg/bindings/network/network.go
+++ b/pkg/bindings/network/network.go
@@ -3,7 +3,6 @@ package network
import (
"context"
"net/http"
- "net/url"
"strings"
"github.com/containers/podman/v3/libpod/network/types"
@@ -110,8 +109,6 @@ func Disconnect(ctx context.Context, networkName string, ContainerNameOrID strin
if err != nil {
return err
}
- // No params are used for disconnect
- params := url.Values{}
// Disconnect sends everything in body
disconnect := struct {
Container string
@@ -128,7 +125,7 @@ func Disconnect(ctx context.Context, networkName string, ContainerNameOrID strin
return err
}
stringReader := strings.NewReader(body)
- response, err := conn.DoRequest(ctx, stringReader, http.MethodPost, "/networks/%s/disconnect", params, nil, networkName)
+ response, err := conn.DoRequest(ctx, stringReader, http.MethodPost, "/networks/%s/disconnect", nil, nil, networkName)
if err != nil {
return err
}
@@ -138,32 +135,26 @@ func Disconnect(ctx context.Context, networkName string, ContainerNameOrID strin
}
// Connect adds a container to a network
-func Connect(ctx context.Context, networkName string, ContainerNameOrID string, options *ConnectOptions) error {
+func Connect(ctx context.Context, networkName string, containerNameOrID string, options *types.PerNetworkOptions) error {
if options == nil {
- options = new(ConnectOptions)
+ options = new(types.PerNetworkOptions)
}
conn, err := bindings.GetClient(ctx)
if err != nil {
return err
}
- // No params are used in connect
- params := url.Values{}
// Connect sends everything in body
- connect := struct {
- Container string
- Aliases []string
- }{
- Container: ContainerNameOrID,
- }
- if aliases := options.GetAliases(); options.Changed("Aliases") {
- connect.Aliases = aliases
+ connect := entities.NetworkConnectOptions{
+ Container: containerNameOrID,
+ PerNetworkOptions: *options,
}
+
body, err := jsoniter.MarshalToString(connect)
if err != nil {
return err
}
stringReader := strings.NewReader(body)
- response, err := conn.DoRequest(ctx, stringReader, http.MethodPost, "/networks/%s/connect", params, nil, networkName)
+ response, err := conn.DoRequest(ctx, stringReader, http.MethodPost, "/networks/%s/connect", nil, nil, networkName)
if err != nil {
return err
}
diff --git a/pkg/bindings/network/types.go b/pkg/bindings/network/types.go
index 8088de061..b82c0e438 100644
--- a/pkg/bindings/network/types.go
+++ b/pkg/bindings/network/types.go
@@ -1,6 +1,8 @@
package network
-import "net"
+import (
+ "net"
+)
//go:generate go run ../generator/generator.go CreateOptions
// CreateOptions are optional options for creating networks
@@ -61,15 +63,6 @@ type DisconnectOptions struct {
Force *bool
}
-//go:generate go run ../generator/generator.go ConnectOptions
-// ConnectOptions are optional options for connecting
-// containers from a network
-type ConnectOptions struct {
- // Aliases are names the container will be known as
- // when using the dns plugin
- Aliases *[]string
-}
-
//go:generate go run ../generator/generator.go ExistsOptions
// ExistsOptions are optional options for checking
// if a network exists
diff --git a/pkg/bindings/network/types_connect_options.go b/pkg/bindings/network/types_connect_options.go
deleted file mode 100644
index b7a465999..000000000
--- a/pkg/bindings/network/types_connect_options.go
+++ /dev/null
@@ -1,33 +0,0 @@
-// Code generated by go generate; DO NOT EDIT.
-package network
-
-import (
- "net/url"
-
- "github.com/containers/podman/v3/pkg/bindings/internal/util"
-)
-
-// Changed returns true if named field has been set
-func (o *ConnectOptions) Changed(fieldName string) bool {
- return util.Changed(o, fieldName)
-}
-
-// ToParams formats struct fields to be passed to API service
-func (o *ConnectOptions) ToParams() (url.Values, error) {
- return util.ToParams(o)
-}
-
-// WithAliases set field Aliases to given value
-func (o *ConnectOptions) WithAliases(value []string) *ConnectOptions {
- o.Aliases = &value
- return o
-}
-
-// GetAliases returns value of field Aliases
-func (o *ConnectOptions) GetAliases() []string {
- if o.Aliases == nil {
- var z []string
- return z
- }
- return *o.Aliases
-}
diff --git a/pkg/domain/entities/network.go b/pkg/domain/entities/network.go
index d7389a699..34b89ae7d 100644
--- a/pkg/domain/entities/network.go
+++ b/pkg/domain/entities/network.go
@@ -2,6 +2,8 @@ package entities
import (
"net"
+
+ "github.com/containers/podman/v3/libpod/network/types"
)
// NetworkListOptions describes options for listing networks in cli
@@ -67,8 +69,8 @@ type NetworkDisconnectOptions struct {
// NetworkConnectOptions describes options for connecting
// a container to a network
type NetworkConnectOptions struct {
- Aliases []string
- Container string
+ Container string `json:"container"`
+ types.PerNetworkOptions
}
// NetworkPruneReport containers the name of network and an error
diff --git a/pkg/domain/infra/abi/network.go b/pkg/domain/infra/abi/network.go
index 49c7dc60d..c7b12663c 100644
--- a/pkg/domain/infra/abi/network.go
+++ b/pkg/domain/infra/abi/network.go
@@ -124,7 +124,7 @@ func (ic *ContainerEngine) NetworkDisconnect(ctx context.Context, networkname st
}
func (ic *ContainerEngine) NetworkConnect(ctx context.Context, networkname string, options entities.NetworkConnectOptions) error {
- return ic.Libpod.ConnectContainerToNetwork(options.Container, networkname, options.Aliases)
+ return ic.Libpod.ConnectContainerToNetwork(options.Container, networkname, options.PerNetworkOptions)
}
// NetworkExists checks if the given network exists
diff --git a/pkg/domain/infra/tunnel/network.go b/pkg/domain/infra/tunnel/network.go
index 069982d30..b5050345a 100644
--- a/pkg/domain/infra/tunnel/network.go
+++ b/pkg/domain/infra/tunnel/network.go
@@ -81,8 +81,7 @@ func (ic *ContainerEngine) NetworkDisconnect(ctx context.Context, networkname st
// NetworkConnect removes a container from a given network
func (ic *ContainerEngine) NetworkConnect(ctx context.Context, networkname string, opts entities.NetworkConnectOptions) error {
- options := new(network.ConnectOptions).WithAliases(opts.Aliases)
- return network.Connect(ic.ClientCtx, networkname, opts.Container, options)
+ return network.Connect(ic.ClientCtx, networkname, opts.Container, &opts.PerNetworkOptions)
}
// NetworkExists checks if the given network exists
diff --git a/test/e2e/network_connect_disconnect_test.go b/test/e2e/network_connect_disconnect_test.go
index 2205a1263..be94ecb2d 100644
--- a/test/e2e/network_connect_disconnect_test.go
+++ b/test/e2e/network_connect_disconnect_test.go
@@ -176,12 +176,14 @@ var _ = Describe("Podman network connect and disconnect", func() {
// Create a second network
newNetName := "aliasTest" + stringid.GenerateNonCryptoID()
- session = podmanTest.Podman([]string{"network", "create", newNetName})
+ session = podmanTest.Podman([]string{"network", "create", newNetName, "--subnet", "10.11.100.0/24"})
session.WaitWithDefaultTimeout()
Expect(session).Should(Exit(0))
defer podmanTest.removeCNINetwork(newNetName)
- connect := podmanTest.Podman([]string{"network", "connect", newNetName, "test"})
+ ip := "10.11.100.99"
+ mac := "44:11:44:11:44:11"
+ connect := podmanTest.Podman([]string{"network", "connect", "--ip", ip, "--mac-address", mac, newNetName, "test"})
connect.WaitWithDefaultTimeout()
Expect(connect).Should(Exit(0))
Expect(connect.ErrorToString()).Should(Equal(""))
@@ -200,6 +202,8 @@ var _ = Describe("Podman network connect and disconnect", func() {
exec = podmanTest.Podman([]string{"exec", "-it", "test", "ip", "addr", "show", "eth1"})
exec.WaitWithDefaultTimeout()
Expect(exec).Should(Exit(0))
+ Expect(exec.OutputToString()).Should(ContainSubstring(ip))
+ Expect(exec.OutputToString()).Should(ContainSubstring(mac))
// make sure no logrus errors are shown https://github.com/containers/podman/issues/9602
rm := podmanTest.Podman([]string{"rm", "--time=0", "-f", "test"})