spiegel_podman/cmd/podman/common/netflags.go
Paul Holzinger b5d1d89a37 Add shell completion with cobra
Allow automatic generation for shell completion scripts
with the internal cobra functions (requires v1.0.0+).

This should replace the handwritten completion scripts
and even adds support for fish. With this approach it is
less likley that completions and code are out of sync.

We can now create the scripts with
- podman completion bash
- podman completion zsh
- podman completion fish

To test the completion run:
source <(podman completion bash)

The same works for podman-remote and podman --remote and
it will complete your remote containers/images with
the correct endpoints values from --url/--connection.

The completion logic is written in go and provided by the
cobra library. The completion functions lives in
`cmd/podman/completion/completion.go`.

The unit test at cmd/podman/shell_completion_test.go checks
if each command and flag has an autocompletion function set.
This prevents that commands and flags have no shell completion set.

This commit does not replace the current autocompletion scripts.

Closes #6440

Signed-off-by: Paul Holzinger <paul.holzinger@web.de>
2020-11-12 11:38:31 +01:00

226 lines
5.5 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.String(
networkFlagName, 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") {
network, err := cmd.Flags().GetString("network")
if err != nil {
return nil, err
}
parts := strings.SplitN(network, ":", 2)
ns, cniNets, err := specgen.ParseNetworkNamespace(network)
if err != nil {
return nil, err
}
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 = cniNets
}
aliases, err := cmd.Flags().GetStringSlice("network-alias")
if err != nil {
return nil, err
}
if len(aliases) > 0 {
opts.Aliases = aliases
}
return &opts, err
}