Files
podman/cmd/podman/common/netflags.go
Daniel J Walsh 21841dc381 Default to --dns-option to match Docker and Buildah
[NO NEW TESTS NEEDED] Existing tests cover this.

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
2022-09-16 06:14:35 -04:00

287 lines
8.0 KiB
Go

package common
import (
"errors"
"fmt"
"net"
"github.com/containers/common/libnetwork/types"
"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v4/cmd/podman/parse"
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/pkg/domain/entities"
"github.com/containers/podman/v4/pkg/specgen"
"github.com/containers/podman/v4/pkg/specgenutil"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
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-option"
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)
ip6FlagName := "ip6"
netFlags.String(
ip6FlagName, "",
"Specify a static IPv6 address for the container",
)
_ = cmd.RegisterFlagCompletionFunc(ip6FlagName, 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, nil,
"Connect a container to a network",
)
_ = cmd.RegisterFlagCompletionFunc(networkFlagName, AutocompleteNetworkFlag)
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", containerConfig.Containers.NoHosts,
"Do not create /etc/hosts within the container, instead use the version from the image",
)
}
// NetFlagsToNetOptions parses the network flags for the given cmd.
func NetFlagsToNetOptions(opts *entities.NetOptions, flags pflag.FlagSet) (*entities.NetOptions, error) {
var (
err error
)
if opts == nil {
opts = &entities.NetOptions{}
}
if flags.Changed("add-host") {
opts.AddHosts, err = 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 flags.Changed("dns") {
servers, err := 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, fmt.Errorf("%s is not allowed to be specified with other DNS ip addresses", d)
}
break
}
dns := net.ParseIP(d)
if dns == nil {
return nil, fmt.Errorf("%s is not an ip address", d)
}
opts.DNSServers = append(opts.DNSServers, dns)
}
}
if flags.Changed("dns-option") {
options, err := flags.GetStringSlice("dns-option")
if err != nil {
return nil, err
}
opts.DNSOptions = options
}
if flags.Changed("dns-search") {
dnsSearches, err := 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.New("cannot pass additional search domains when also specifying '.'")
}
continue
}
if _, err := parse.ValidateDomain(dom); err != nil {
return nil, err
}
}
opts.DNSSearch = dnsSearches
}
if flags.Changed("publish") {
inputPorts, err := flags.GetStringSlice("publish")
if err != nil {
return nil, err
}
if len(inputPorts) > 0 {
opts.PublishPorts, err = specgenutil.CreatePortBindings(inputPorts)
if err != nil {
return nil, err
}
}
}
opts.NoHosts, err = flags.GetBool("no-hosts")
if err != nil {
return nil, err
}
// parse the network only when network was changed
// otherwise we send default to server so that the server
// can pick the correct default instead of the client
if flags.Changed("network") {
network, err := flags.GetStringArray("network")
if err != nil {
return nil, err
}
ns, networks, options, err := specgen.ParseNetworkFlag(network)
if err != nil {
return nil, err
}
opts.NetworkOptions = options
opts.Network = ns
opts.Networks = networks
}
if flags.Changed("ip") || flags.Changed("ip6") || flags.Changed("mac-address") || flags.Changed("network-alias") {
// if there is no network we add the default
if len(opts.Networks) == 0 {
opts.Networks = map[string]types.PerNetworkOptions{
"default": {},
}
}
for _, ipFlagName := range []string{"ip", "ip6"} {
ip, err := flags.GetString(ipFlagName)
if err != nil {
return nil, err
}
if ip != "" {
// if pod create --infra=false
if infra, err := flags.GetBool("infra"); err == nil && !infra {
return nil, fmt.Errorf("cannot set --%s without infra container: %w", ipFlagName, define.ErrInvalidArg)
}
staticIP := net.ParseIP(ip)
if staticIP == nil {
return nil, fmt.Errorf("%q is not an ip address", ip)
}
if !opts.Network.IsBridge() && !opts.Network.IsDefault() {
return nil, fmt.Errorf("--%s can only be set when the network mode is bridge: %w", ipFlagName, define.ErrInvalidArg)
}
if len(opts.Networks) != 1 {
return nil, fmt.Errorf("--%s can only be set for a single network: %w", ipFlagName, define.ErrInvalidArg)
}
for name, netOpts := range opts.Networks {
netOpts.StaticIPs = append(netOpts.StaticIPs, staticIP)
opts.Networks[name] = netOpts
}
}
}
m, err := flags.GetString("mac-address")
if err != nil {
return nil, err
}
if len(m) > 0 {
// if pod create --infra=false
if infra, err := flags.GetBool("infra"); err == nil && !infra {
return nil, fmt.Errorf("cannot set --mac without infra container: %w", define.ErrInvalidArg)
}
mac, err := net.ParseMAC(m)
if err != nil {
return nil, err
}
if !opts.Network.IsBridge() && !opts.Network.IsDefault() {
return nil, fmt.Errorf("--mac-address can only be set when the network mode is bridge: %w", define.ErrInvalidArg)
}
if len(opts.Networks) != 1 {
return nil, fmt.Errorf("--mac-address can only be set for a single network: %w", define.ErrInvalidArg)
}
for name, netOpts := range opts.Networks {
netOpts.StaticMAC = types.HardwareAddr(mac)
opts.Networks[name] = netOpts
}
}
aliases, err := flags.GetStringSlice("network-alias")
if err != nil {
return nil, err
}
if len(aliases) > 0 {
// if pod create --infra=false
if infra, err := flags.GetBool("infra"); err == nil && !infra {
return nil, fmt.Errorf("cannot set --network-alias without infra container: %w", define.ErrInvalidArg)
}
if !opts.Network.IsBridge() && !opts.Network.IsDefault() {
return nil, fmt.Errorf("--network-alias can only be set when the network mode is bridge: %w", define.ErrInvalidArg)
}
for name, netOpts := range opts.Networks {
netOpts.Aliases = aliases
opts.Networks[name] = netOpts
}
}
}
return opts, err
}