spiegel_podman/cmd/podman/common/netflags.go
Paul Holzinger f441190d10 Allow multiple --network flags for podman run/create
We allow a container to be connected to several cni networks
but only if they are listed comma sperated. This is not intuitive
for users especially since the flag parsing allows multiple string
flags but only would take the last value. see: spf13/pflag#72

Also get rid of the extra parsing logic for pods. The invalid options
are already handled by `pkg/specgen`.

A test is added to prevent a future regression.

Signed-off-by: Paul Holzinger <paul.holzinger@web.de>
2020-11-20 17:02:48 +01:00

230 lines
5.8 KiB
Go

package common
import (
"net"
"strings"
"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v2/cmd/podman/parse"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/containers/podman/v2/pkg/specgen"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
func DefineNetFlags(cmd *cobra.Command) {
netFlags := cmd.Flags()
addHostFlagName := "add-host"
netFlags.StringSlice(
addHostFlagName, []string{},
"Add a custom host-to-IP mapping (host:ip) (default [])",
)
_ = cmd.RegisterFlagCompletionFunc(addHostFlagName, completion.AutocompleteNone)
dnsFlagName := "dns"
netFlags.StringSlice(
dnsFlagName, containerConfig.DNSServers(),
"Set custom DNS servers",
)
_ = cmd.RegisterFlagCompletionFunc(dnsFlagName, completion.AutocompleteNone)
dnsOptFlagName := "dns-opt"
netFlags.StringSlice(
dnsOptFlagName, containerConfig.DNSOptions(),
"Set custom DNS options",
)
_ = cmd.RegisterFlagCompletionFunc(dnsOptFlagName, completion.AutocompleteNone)
dnsSearchFlagName := "dns-search"
netFlags.StringSlice(
dnsSearchFlagName, containerConfig.DNSSearches(),
"Set custom DNS search domains",
)
_ = cmd.RegisterFlagCompletionFunc(dnsSearchFlagName, completion.AutocompleteNone)
ipFlagName := "ip"
netFlags.String(
ipFlagName, "",
"Specify a static IPv4 address for the container",
)
_ = cmd.RegisterFlagCompletionFunc(ipFlagName, completion.AutocompleteNone)
macAddressFlagName := "mac-address"
netFlags.String(
macAddressFlagName, "",
"Container MAC address (e.g. 92:d0:c6:0a:29:33)",
)
_ = cmd.RegisterFlagCompletionFunc(macAddressFlagName, completion.AutocompleteNone)
networkFlagName := "network"
netFlags.StringArray(
networkFlagName, []string{containerConfig.NetNS()},
"Connect a container to a network",
)
_ = cmd.RegisterFlagCompletionFunc(networkFlagName, AutocompleteNetworks)
networkAliasFlagName := "network-alias"
netFlags.StringSlice(
networkAliasFlagName, []string{},
"Add network-scoped alias for the container",
)
_ = cmd.RegisterFlagCompletionFunc(networkAliasFlagName, completion.AutocompleteNone)
publishFlagName := "publish"
netFlags.StringSliceP(
publishFlagName, "p", []string{},
"Publish a container's port, or a range of ports, to the host (default [])",
)
_ = cmd.RegisterFlagCompletionFunc(publishFlagName, completion.AutocompleteNone)
netFlags.Bool(
"no-hosts", false,
"Do not create /etc/hosts within the container, instead use the version from the image",
)
}
func NetFlagsToNetOptions(cmd *cobra.Command) (*entities.NetOptions, error) {
var (
err error
)
opts := entities.NetOptions{}
opts.AddHosts, err = cmd.Flags().GetStringSlice("add-host")
if err != nil {
return nil, err
}
// Verify the additional hosts are in correct format
for _, host := range opts.AddHosts {
if _, err := parse.ValidateExtraHost(host); err != nil {
return nil, err
}
}
if cmd.Flags().Changed("dns") {
servers, err := cmd.Flags().GetStringSlice("dns")
if err != nil {
return nil, err
}
for _, d := range servers {
if d == "none" {
opts.UseImageResolvConf = true
if len(servers) > 1 {
return nil, errors.Errorf("%s is not allowed to be specified with other DNS ip addresses", d)
}
break
}
dns := net.ParseIP(d)
if dns == nil {
return nil, errors.Errorf("%s is not an ip address", d)
}
opts.DNSServers = append(opts.DNSServers, dns)
}
}
if cmd.Flags().Changed("dns-opt") {
options, err := cmd.Flags().GetStringSlice("dns-opt")
if err != nil {
return nil, err
}
opts.DNSOptions = options
}
if cmd.Flags().Changed("dns-search") {
dnsSearches, err := cmd.Flags().GetStringSlice("dns-search")
if err != nil {
return nil, err
}
// Validate domains are good
for _, dom := range dnsSearches {
if dom == "." {
if len(dnsSearches) > 1 {
return nil, errors.Errorf("cannot pass additional search domains when also specifying '.'")
}
continue
}
if _, err := parse.ValidateDomain(dom); err != nil {
return nil, err
}
}
opts.DNSSearch = dnsSearches
}
m, err := cmd.Flags().GetString("mac-address")
if err != nil {
return nil, err
}
if len(m) > 0 {
mac, err := net.ParseMAC(m)
if err != nil {
return nil, err
}
opts.StaticMAC = &mac
}
inputPorts, err := cmd.Flags().GetStringSlice("publish")
if err != nil {
return nil, err
}
if len(inputPorts) > 0 {
opts.PublishPorts, err = createPortBindings(inputPorts)
if err != nil {
return nil, err
}
}
ip, err := cmd.Flags().GetString("ip")
if err != nil {
return nil, err
}
if ip != "" {
staticIP := net.ParseIP(ip)
if staticIP == nil {
return nil, errors.Errorf("%s is not an ip address", ip)
}
if staticIP.To4() == nil {
return nil, errors.Wrapf(define.ErrInvalidArg, "%s is not an IPv4 address", ip)
}
opts.StaticIP = &staticIP
}
opts.NoHosts, err = cmd.Flags().GetBool("no-hosts")
if err != nil {
return nil, err
}
if cmd.Flags().Changed("network") {
networks, err := cmd.Flags().GetStringArray("network")
if err != nil {
return nil, err
}
for i, network := range networks {
parts := strings.SplitN(network, ":", 2)
ns, cniNets, err := specgen.ParseNetworkNamespace(network)
if err != nil {
return nil, err
}
if i > 0 && (len(cniNets) == 0 || len(opts.CNINetworks) == 0) {
return nil, errors.Errorf("network conflict between type %s and %s", opts.Network.NSMode, ns.NSMode)
}
if len(parts) > 1 {
opts.NetworkOptions = make(map[string][]string)
opts.NetworkOptions[parts[0]] = strings.Split(parts[1], ",")
cniNets = nil
}
opts.Network = ns
opts.CNINetworks = append(opts.CNINetworks, cniNets...)
}
}
aliases, err := cmd.Flags().GetStringSlice("network-alias")
if err != nil {
return nil, err
}
if len(aliases) > 0 {
opts.Aliases = aliases
}
return &opts, err
}