diff options
-rw-r--r-- | cmd/podman/networks/list.go | 11 | ||||
-rw-r--r-- | docs/source/markdown/podman-network-ls.1.md | 31 | ||||
-rw-r--r-- | libpod/network/files.go | 18 | ||||
-rw-r--r-- | libpod/network/netconflist.go | 10 | ||||
-rw-r--r-- | libpod/network/network.go | 11 | ||||
-rw-r--r-- | pkg/api/handlers/compat/networks.go | 14 | ||||
-rw-r--r-- | pkg/api/server/register_networks.go | 2 | ||||
-rw-r--r-- | test/apiv2/35-networks.at | 16 | ||||
-rw-r--r-- | test/e2e/network_test.go | 34 |
9 files changed, 124 insertions, 23 deletions
diff --git a/cmd/podman/networks/list.go b/cmd/podman/networks/list.go index 6e6bbb07d..16ae980dc 100644 --- a/cmd/podman/networks/list.go +++ b/cmd/podman/networks/list.go @@ -37,6 +37,7 @@ var ( var ( networkListOptions entities.NetworkListOptions filters []string + noTrunc bool ) func networkListFlags(flags *pflag.FlagSet) { @@ -45,6 +46,7 @@ func networkListFlags(flags *pflag.FlagSet) { _ = networklistCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat) flags.BoolVarP(&networkListOptions.Quiet, "quiet", "q", false, "display only names") + flags.BoolVar(&noTrunc, "no-trunc", false, "Do not truncate the network ID") filterFlagName := "filter" flags.StringArrayVarP(&filters, filterFlagName, "f", nil, "Provide filter values (e.g. 'name=podman')") @@ -96,6 +98,7 @@ func networkList(cmd *cobra.Command, args []string) error { "Version": "version", "Plugins": "plugins", "Labels": "labels", + "ID": "network id", }) renderHeaders := true row := "{{.Name}}\t{{.Version}}\t{{.Plugins}}\n" @@ -155,3 +158,11 @@ func (n ListPrintReports) Labels() string { } return strings.Join(list, ",") } + +func (n ListPrintReports) ID() string { + length := 12 + if noTrunc { + length = 64 + } + return network.GetNetworkID(n.Name)[:length] +} diff --git a/docs/source/markdown/podman-network-ls.1.md b/docs/source/markdown/podman-network-ls.1.md index fcba51190..a964c97e8 100644 --- a/docs/source/markdown/podman-network-ls.1.md +++ b/docs/source/markdown/podman-network-ls.1.md @@ -10,14 +10,6 @@ podman\-network\-ls - Display a summary of CNI networks Displays a list of existing podman networks. This command is not available for rootless users. ## OPTIONS -#### **--quiet**, **-q** - -The `quiet` option will restrict the output to only the network names. - -#### **--format** - -Pretty-print networks to JSON or using a Go template. - #### **--filter**, **-f** Filter output based on conditions given. @@ -30,10 +22,33 @@ Valid filters are listed below: | **Filter** | **Description** | | ---------- | ------------------------------------------------------------------------------------- | | name | [Name] Network name (accepts regex) | +| id | [ID] Full or partial network ID | | label | [Key] or [Key=Value] Label assigned to a network | | plugin | [Plugin] CNI plugins included in a network (e.g `bridge`,`portmap`,`firewall`,`tuning`,`dnsname`,`macvlan`) | | driver | [Driver] Only `bridge` is supported | +#### **--format** + +Change the default output format. This can be of a supported type like 'json' +or a Go template. +Valid placeholders for the Go template are listed below: + +| **Placeholder** | **Description** | +| --------------- | --------------------------------| +| .ID | Network ID | +| .Name | Network name | +| .Plugins | Network Plugins | +| .Labels | Network labels | +| .Version | CNI Version of the config file | + +#### **--no-trunc** + +Do not truncate the network ID. The network ID is not displayed by default and must be specified with **--format**. + +#### **--quiet**, **-q** + +The `quiet` option will restrict the output to only the network names. + ## EXAMPLE Display networks diff --git a/libpod/network/files.go b/libpod/network/files.go index 83cb1c23a..33cf01064 100644 --- a/libpod/network/files.go +++ b/libpod/network/files.go @@ -50,13 +50,15 @@ func LoadCNIConfsFromDir(dir string) ([]*libcni.NetworkConfigList, error) { return configs, nil } -// GetCNIConfigPathByName finds a CNI network by name and +// GetCNIConfigPathByNameOrID finds a CNI network by name and // returns its configuration file path -func GetCNIConfigPathByName(config *config.Config, name string) (string, error) { +func GetCNIConfigPathByNameOrID(config *config.Config, name string) (string, error) { files, err := libcni.ConfFiles(GetCNIConfDir(config), []string{".conflist"}) if err != nil { return "", err } + idMatch := 0 + file := "" for _, confFile := range files { conf, err := libcni.ConfListFromFile(confFile) if err != nil { @@ -65,6 +67,16 @@ func GetCNIConfigPathByName(config *config.Config, name string) (string, error) if conf.Name == name { return confFile, nil } + if strings.HasPrefix(GetNetworkID(conf.Name), name) { + idMatch++ + file = confFile + } + } + if idMatch == 1 { + return file, nil + } + if idMatch > 1 { + return "", errors.Errorf("more than one result for network ID %s", name) } return "", errors.Wrap(define.ErrNoSuchNetwork, fmt.Sprintf("unable to find network configuration for %s", name)) } @@ -72,7 +84,7 @@ func GetCNIConfigPathByName(config *config.Config, name string) (string, error) // ReadRawCNIConfByName reads the raw CNI configuration for a CNI // network by name func ReadRawCNIConfByName(config *config.Config, name string) ([]byte, error) { - confFile, err := GetCNIConfigPathByName(config, name) + confFile, err := GetCNIConfigPathByNameOrID(config, name) if err != nil { return nil, err } diff --git a/libpod/network/netconflist.go b/libpod/network/netconflist.go index a5fec5e80..d61b96ecb 100644 --- a/libpod/network/netconflist.go +++ b/libpod/network/netconflist.go @@ -230,8 +230,16 @@ func IfPassesFilter(netconf *libcni.NetworkConfigList, filters map[string][]stri } } + case "id": + // matches part of one id + for _, filterValue := range filterValues { + if strings.Contains(GetNetworkID(netconf.Name), filterValue) { + result = true + break + } + } + // TODO: add dangling filter - // TODO TODO: add id filter if we support ids default: return false, errors.Errorf("invalid filter %q", key) diff --git a/libpod/network/network.go b/libpod/network/network.go index 0febb52f6..89f0b67ac 100644 --- a/libpod/network/network.go +++ b/libpod/network/network.go @@ -1,6 +1,8 @@ package network import ( + "crypto/sha256" + "encoding/hex" "encoding/json" "net" "os" @@ -175,7 +177,7 @@ func RemoveNetwork(config *config.Config, name string) error { return err } defer l.releaseCNILock() - cniPath, err := GetCNIConfigPathByName(config, name) + cniPath, err := GetCNIConfigPathByNameOrID(config, name) if err != nil { return err } @@ -229,3 +231,10 @@ func Exists(config *config.Config, name string) (bool, error) { } return true, nil } + +// GetNetworkID return the network ID for a given name. +// It is just the sha256 hash but this should be good enough. +func GetNetworkID(name string) string { + hash := sha256.Sum256([]byte(name)) + return hex.EncodeToString(hash[:]) +} diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go index 762f88a68..b4f3aa2f1 100644 --- a/pkg/api/handlers/compat/networks.go +++ b/pkg/api/handlers/compat/networks.go @@ -50,7 +50,7 @@ func InspectNetwork(w http.ResponseWriter, r *http.Request) { utils.NetworkNotFound(w, name, err) return } - report, err := getNetworkResourceByName(name, runtime, nil) + report, err := getNetworkResourceByNameOrID(name, runtime, nil) if err != nil { utils.InternalServerError(w, err) return @@ -58,7 +58,7 @@ func InspectNetwork(w http.ResponseWriter, r *http.Request) { utils.WriteResponse(w, http.StatusOK, report) } -func getNetworkResourceByName(name string, runtime *libpod.Runtime, filters map[string][]string) (*types.NetworkResource, error) { +func getNetworkResourceByNameOrID(nameOrID string, runtime *libpod.Runtime, filters map[string][]string) (*types.NetworkResource, error) { var ( ipamConfigs []dockerNetwork.IPAMConfig ) @@ -68,7 +68,7 @@ func getNetworkResourceByName(name string, runtime *libpod.Runtime, filters map[ } containerEndpoints := map[string]types.EndpointResource{} // Get the network path so we can get created time - networkConfigPath, err := network.GetCNIConfigPathByName(config, name) + networkConfigPath, err := network.GetCNIConfigPathByNameOrID(config, nameOrID) if err != nil { return nil, err } @@ -116,7 +116,7 @@ func getNetworkResourceByName(name string, runtime *libpod.Runtime, filters map[ if err != nil { return nil, err } - if netData, ok := data.NetworkSettings.Networks[name]; ok { + if netData, ok := data.NetworkSettings.Networks[conf.Name]; ok { containerEndpoint := types.EndpointResource{ Name: netData.NetworkID, EndpointID: netData.EndpointID, @@ -128,8 +128,8 @@ func getNetworkResourceByName(name string, runtime *libpod.Runtime, filters map[ } } report := types.NetworkResource{ - Name: name, - ID: name, + Name: conf.Name, + ID: network.GetNetworkID(conf.Name), Created: time.Unix(int64(stat.Ctim.Sec), int64(stat.Ctim.Nsec)), // nolint: unconvert Scope: "", Driver: network.DefaultNetworkDriver, @@ -199,7 +199,7 @@ func ListNetworks(w http.ResponseWriter, r *http.Request) { var reports []*types.NetworkResource logrus.Errorf("netNames: %q", strings.Join(netNames, ", ")) for _, name := range netNames { - report, err := getNetworkResourceByName(name, runtime, query.Filters) + report, err := getNetworkResourceByNameOrID(name, runtime, query.Filters) if err != nil { utils.InternalServerError(w, err) return diff --git a/pkg/api/server/register_networks.go b/pkg/api/server/register_networks.go index 193b05e6d..e6c85d244 100644 --- a/pkg/api/server/register_networks.go +++ b/pkg/api/server/register_networks.go @@ -68,6 +68,7 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // description: | // JSON encoded value of the filters (a map[string][]string) to process on the network list. Currently available filters: // - name=[name] Matches network name (accepts regex). + // - id=[id] Matches for full or partial ID. // - driver=[driver] Only bridge is supported. // - label=[key] or label=[key=value] Matches networks based on the presence of a label alone or a label and a value. // produces: @@ -225,6 +226,7 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error { // description: | // JSON encoded value of the filters (a map[string][]string) to process on the network list. Available filters: // - name=[name] Matches network name (accepts regex). + // - id=[id] Matches for full or partial ID. // - driver=[driver] Only bridge is supported. // - label=[key] or label=[key=value] Matches networks based on the presence of a label alone or a label and a value. // - plugin=[plugin] Matches CNI plugins included in a network (e.g `bridge`,`portmap`,`firewall`,`tuning`,`dnsname`,`macvlan`) diff --git a/test/apiv2/35-networks.at b/test/apiv2/35-networks.at index d9556d59f..0ce56ee3c 100644 --- a/test/apiv2/35-networks.at +++ b/test/apiv2/35-networks.at @@ -38,9 +38,19 @@ length=2 # filters={"label":["abc"]} t GET networks?filters=%7B%22label%22%3A%5B%22abc%22%5D%7D 200 \ length=1 -# invalid filter filters={"id":["abc"]} -t GET networks?filters=%7B%22id%22%3A%5B%22abc%22%5D%7D 500 \ -.cause='invalid filter "id"' +# id filter filters={"id":["a7662f44d65029fd4635c91feea3d720a57cef52e2a9fcc7772b69072cc1ccd1"]} +t GET networks?filters=%7B%22id%22%3A%5B%22a7662f44d65029fd4635c91feea3d720a57cef52e2a9fcc7772b69072cc1ccd1%22%5D%7D 200 \ +length=1 \ +.[0].Name=network1 \ +.[0].Id=a7662f44d65029fd4635c91feea3d720a57cef52e2a9fcc7772b69072cc1ccd1 +# invalid filter filters={"dangling":["1"]} +t GET networks?filters=%7B%22dangling%22%3A%5B%221%22%5D%7D 500 \ +.cause='invalid filter "dangling"' + +# network inspect docker +t GET networks/a7662f44d65029fd4635c91feea3d720a57cef52e2a9fcc7772b69072cc1ccd1 200 \ +.Name=network1 \ +.Id=a7662f44d65029fd4635c91feea3d720a57cef52e2a9fcc7772b69072cc1ccd1 # clean the network t DELETE libpod/networks/network1 200 \ diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go index ad6af61c7..ffc914bc2 100644 --- a/test/e2e/network_test.go +++ b/test/e2e/network_test.go @@ -135,6 +135,40 @@ var _ = Describe("Podman network", func() { Expect(session.LineInOutputContains(name)).To(BeFalse()) }) + It("podman network ID test", func() { + net := "networkIDTest" + // the network id should be the sha256 hash of the network name + netID := "6073aefe03cdf8f29be5b23ea9795c431868a3a22066a6290b187691614fee84" + session := podmanTest.Podman([]string{"network", "create", net}) + session.WaitWithDefaultTimeout() + defer podmanTest.removeCNINetwork(net) + Expect(session.ExitCode()).To(BeZero()) + + session = podmanTest.Podman([]string{"network", "ls", "--format", "{{.Name}} {{.ID}}", "--filter", "id=" + netID}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(BeZero()) + Expect(session.OutputToString()).To(ContainSubstring(net + " " + netID[:12])) + + session = podmanTest.Podman([]string{"network", "ls", "--format", "{{.Name}} {{.ID}}", "--filter", "id=" + netID[10:50], "--no-trunc"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(BeZero()) + Expect(session.OutputToString()).To(ContainSubstring(net + " " + netID)) + + session = podmanTest.Podman([]string{"network", "inspect", netID[:40]}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(BeZero()) + Expect(session.OutputToString()).To(ContainSubstring(net)) + + session = podmanTest.Podman([]string{"network", "inspect", netID[1:]}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).ToNot(BeZero()) + Expect(session.ErrorToString()).To(ContainSubstring("no such network")) + + session = podmanTest.Podman([]string{"network", "rm", netID}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(BeZero()) + }) + rm_func := func(rm string) { It(fmt.Sprintf("podman network %s no args", rm), func() { session := podmanTest.Podman([]string{"network", rm}) |