summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/podman/networks/create.go12
-rw-r--r--cmd/podman/networks/list.go27
-rw-r--r--docs/source/markdown/podman-network-create.1.md4
-rw-r--r--docs/source/markdown/podman-network-ls.1.md18
-rw-r--r--libpod/network/create.go4
-rw-r--r--libpod/network/files.go30
-rw-r--r--libpod/network/netconflist.go80
-rw-r--r--pkg/api/handlers/compat/networks.go47
-rw-r--r--pkg/api/handlers/libpod/networks.go4
-rw-r--r--pkg/api/server/register_networks.go15
-rw-r--r--pkg/bindings/network/network.go9
-rw-r--r--pkg/domain/entities/network.go8
-rw-r--r--pkg/domain/infra/abi/network.go45
-rw-r--r--test/apiv2/35-networks.at19
-rw-r--r--test/e2e/network_test.go59
15 files changed, 285 insertions, 96 deletions
diff --git a/cmd/podman/networks/create.go b/cmd/podman/networks/create.go
index 17de2c95d..938b8da77 100644
--- a/cmd/podman/networks/create.go
+++ b/cmd/podman/networks/create.go
@@ -6,9 +6,11 @@ import (
"github.com/containers/common/pkg/completion"
"github.com/containers/podman/v2/cmd/podman/common"
+ "github.com/containers/podman/v2/cmd/podman/parse"
"github.com/containers/podman/v2/cmd/podman/registry"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -27,6 +29,7 @@ var (
var (
networkCreateOptions entities.NetworkCreateOptions
+ labels []string
)
func networkCreateFlags(cmd *cobra.Command) {
@@ -50,6 +53,10 @@ func networkCreateFlags(cmd *cobra.Command) {
flags.StringVar(&networkCreateOptions.MacVLAN, macvlanFlagName, "", "create a Macvlan connection based on this device")
_ = cmd.RegisterFlagCompletionFunc(macvlanFlagName, completion.AutocompleteNone)
+ labelFlagName := "label"
+ flags.StringArrayVar(&labels, labelFlagName, nil, "set metadata on a network")
+ _ = cmd.RegisterFlagCompletionFunc(labelFlagName, completion.AutocompleteNone)
+
// TODO not supported yet
// flags.StringVar(&networkCreateOptions.IPamDriver, "ipam-driver", "", "IP Address Management Driver")
@@ -81,6 +88,11 @@ func networkCreate(cmd *cobra.Command, args []string) error {
}
name = args[0]
}
+ var err error
+ networkCreateOptions.Labels, err = parse.GetAllLabels([]string{}, labels)
+ if err != nil {
+ return errors.Wrap(err, "failed to parse labels")
+ }
response, err := registry.ContainerEngine().NetworkCreate(registry.Context(), name, networkCreateOptions)
if err != nil {
return err
diff --git a/cmd/podman/networks/list.go b/cmd/podman/networks/list.go
index dcba3f186..6e6bbb07d 100644
--- a/cmd/podman/networks/list.go
+++ b/cmd/podman/networks/list.go
@@ -16,6 +16,7 @@ import (
"github.com/containers/podman/v2/cmd/podman/validate"
"github.com/containers/podman/v2/libpod/network"
"github.com/containers/podman/v2/pkg/domain/entities"
+ "github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
@@ -35,17 +36,18 @@ var (
var (
networkListOptions entities.NetworkListOptions
+ filters []string
)
func networkListFlags(flags *pflag.FlagSet) {
formatFlagName := "format"
- flags.StringVarP(&networkListOptions.Format, formatFlagName, "f", "", "Pretty-print networks to JSON or using a Go template")
+ flags.StringVar(&networkListOptions.Format, formatFlagName, "", "Pretty-print networks to JSON or using a Go template")
_ = networklistCommand.RegisterFlagCompletionFunc(formatFlagName, common.AutocompleteJSONFormat)
flags.BoolVarP(&networkListOptions.Quiet, "quiet", "q", false, "display only names")
filterFlagName := "filter"
- flags.StringVarP(&networkListOptions.Filter, filterFlagName, "", "", "Provide filter values (e.g. 'name=podman')")
+ flags.StringArrayVarP(&filters, filterFlagName, "f", nil, "Provide filter values (e.g. 'name=podman')")
_ = networklistCommand.RegisterFlagCompletionFunc(filterFlagName, common.AutocompleteNetworkFilters)
}
@@ -61,14 +63,14 @@ func init() {
}
func networkList(cmd *cobra.Command, args []string) error {
- // validate the filter pattern.
- if len(networkListOptions.Filter) > 0 {
- tokens := strings.Split(networkListOptions.Filter, "=")
- if len(tokens) != 2 {
- return fmt.Errorf("invalid filter syntax : %s", networkListOptions.Filter)
+ networkListOptions.Filters = make(map[string][]string)
+ for _, f := range filters {
+ split := strings.SplitN(f, "=", 2)
+ if len(split) == 1 {
+ return errors.Errorf("invalid filter %q", f)
}
+ networkListOptions.Filters[split[0]] = append(networkListOptions.Filters[split[0]], split[1])
}
-
responses, err := registry.ContainerEngine().NetworkList(registry.Context(), networkListOptions)
if err != nil {
return err
@@ -93,6 +95,7 @@ func networkList(cmd *cobra.Command, args []string) error {
"CNIVersion": "version",
"Version": "version",
"Plugins": "plugins",
+ "Labels": "labels",
})
renderHeaders := true
row := "{{.Name}}\t{{.Version}}\t{{.Plugins}}\n"
@@ -144,3 +147,11 @@ func (n ListPrintReports) Version() string {
func (n ListPrintReports) Plugins() string {
return network.GetCNIPlugins(n.NetworkConfigList)
}
+
+func (n ListPrintReports) Labels() string {
+ list := make([]string, 0, len(n.NetworkListReport.Labels))
+ for k, v := range n.NetworkListReport.Labels {
+ list = append(list, k+"="+v)
+ }
+ return strings.Join(list, ",")
+}
diff --git a/docs/source/markdown/podman-network-create.1.md b/docs/source/markdown/podman-network-create.1.md
index cbf9d26dc..d787809cd 100644
--- a/docs/source/markdown/podman-network-create.1.md
+++ b/docs/source/markdown/podman-network-create.1.md
@@ -40,6 +40,10 @@ Restrict external access of this network
Allocate container IP from a range. The range must be a complete subnet and in CIDR notation. The *ip-range* option
must be used with a *subnet* option.
+#### **--label**
+
+Set metadata for a network (e.g., --label mykey=value).
+
#### **--macvlan**
Create a *Macvlan* based connection rather than a classic bridge. You must pass an interface name from the host for the
diff --git a/docs/source/markdown/podman-network-ls.1.md b/docs/source/markdown/podman-network-ls.1.md
index 34b40b3ae..fcba51190 100644
--- a/docs/source/markdown/podman-network-ls.1.md
+++ b/docs/source/markdown/podman-network-ls.1.md
@@ -14,13 +14,25 @@ Displays a list of existing podman networks. This command is not available for r
The `quiet` option will restrict the output to only the network names.
-#### **--format**, **-f**
+#### **--format**
Pretty-print networks to JSON or using a Go template.
-#### **--filter**
+#### **--filter**, **-f**
-Provide filter values (e.g. 'name=podman').
+Filter output based on conditions given.
+Multiple filters can be given with multiple uses of the --filter flag.
+Filters with the same key work inclusive with the only exception being
+`label` which is exclusive. Filters with different keys always work exclusive.
+
+Valid filters are listed below:
+
+| **Filter** | **Description** |
+| ---------- | ------------------------------------------------------------------------------------- |
+| name | [Name] Network name (accepts regex) |
+| 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 |
## EXAMPLE
diff --git a/libpod/network/create.go b/libpod/network/create.go
index 7e4fc574a..cac438963 100644
--- a/libpod/network/create.go
+++ b/libpod/network/create.go
@@ -169,7 +169,7 @@ func createBridge(name string, options entities.NetworkCreateOptions, runtimeCon
}
// create CNI plugin configuration
- ncList := NewNcList(name, version.Current())
+ ncList := NewNcList(name, version.Current(), options.Labels)
var plugins []CNIPlugins
// TODO need to iron out the role of isDefaultGW and IPMasq
bridge := NewHostLocalBridge(bridgeDeviceName, isGateway, false, ipMasq, ipamConfig)
@@ -223,7 +223,7 @@ func createMacVLAN(name string, options entities.NetworkCreateOptions, runtimeCo
return "", err
}
}
- ncList := NewNcList(name, version.Current())
+ ncList := NewNcList(name, version.Current(), options.Labels)
macvlan := NewMacVLANPlugin(options.MacVLAN)
plugins = append(plugins, macvlan)
ncList["plugins"] = plugins
diff --git a/libpod/network/files.go b/libpod/network/files.go
index 7f1e3ee18..83cb1c23a 100644
--- a/libpod/network/files.go
+++ b/libpod/network/files.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v2/libpod/define"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
)
// ErrNoSuchNetworkInterface indicates that no network interface exists
@@ -89,6 +90,35 @@ func GetCNIPlugins(list *libcni.NetworkConfigList) string {
return strings.Join(plugins, ",")
}
+// GetNetworkLabels returns a list of labels as a string
+func GetNetworkLabels(list *libcni.NetworkConfigList) NcLabels {
+ cniJSON := make(map[string]interface{})
+ err := json.Unmarshal(list.Bytes, &cniJSON)
+ if err != nil {
+ logrus.Errorf("failed to unmarshal network config %v %v", cniJSON["name"], err)
+ return nil
+ }
+ if args, ok := cniJSON["args"]; ok {
+ if key, ok := args.(map[string]interface{}); ok {
+ if labels, ok := key[PodmanLabelKey]; ok {
+ if labels, ok := labels.(map[string]interface{}); ok {
+ result := make(NcLabels, len(labels))
+ for k, v := range labels {
+ if v, ok := v.(string); ok {
+ result[k] = v
+ } else {
+ logrus.Errorf("network config %v invalid label value type %T should be string", cniJSON["name"], labels)
+ }
+ }
+ return result
+ }
+ logrus.Errorf("network config %v invalid label type %T should be map[string]string", cniJSON["name"], labels)
+ }
+ }
+ }
+ return nil
+}
+
// GetNetworksFromFilesystem gets all the networks from the cni configuration
// files
func GetNetworksFromFilesystem(config *config.Config) ([]*allocator.Net, error) {
diff --git a/libpod/network/netconflist.go b/libpod/network/netconflist.go
index ee9adce14..3db38485b 100644
--- a/libpod/network/netconflist.go
+++ b/libpod/network/netconflist.go
@@ -4,6 +4,11 @@ import (
"net"
"os"
"path/filepath"
+ "strings"
+
+ "github.com/containernetworking/cni/libcni"
+ "github.com/containers/podman/v2/pkg/util"
+ "github.com/pkg/errors"
)
const (
@@ -14,12 +19,24 @@ const (
// NcList describes a generic map
type NcList map[string]interface{}
+// NcArgs describes the cni args field
+type NcArgs map[string]NcLabels
+
+// NcLabels describes the label map
+type NcLabels map[string]string
+
+// PodmanLabelKey key used to store the podman network label in a cni config
+const PodmanLabelKey = "podman_labels"
+
// NewNcList creates a generic map of values with string
// keys and adds in version and network name
-func NewNcList(name, version string) NcList {
+func NewNcList(name, version string, labels NcLabels) NcList {
n := NcList{}
n["cniVersion"] = version
n["name"] = name
+ if len(labels) > 0 {
+ n["args"] = NcArgs{PodmanLabelKey: labels}
+ }
return n
}
@@ -159,3 +176,64 @@ func NewMacVLANPlugin(device string) MacVLANConfig {
}
return m
}
+
+// IfPassesFilter filters NetworkListReport and returns true if the filter match the given config
+func IfPassesFilter(netconf *libcni.NetworkConfigList, filters map[string][]string) (bool, error) {
+ result := true
+ for key, filterValues := range filters {
+ result = false
+ switch strings.ToLower(key) {
+ case "name":
+ // matches one name, regex allowed
+ result = util.StringMatchRegexSlice(netconf.Name, filterValues)
+
+ case "plugin":
+ // match one plugin
+ plugins := GetCNIPlugins(netconf)
+ for _, val := range filterValues {
+ if strings.Contains(plugins, val) {
+ result = true
+ break
+ }
+ }
+
+ case "label":
+ // matches all labels
+ labels := GetNetworkLabels(netconf)
+ outer:
+ for _, filterValue := range filterValues {
+ filterArray := strings.SplitN(filterValue, "=", 2)
+ filterKey := filterArray[0]
+ if len(filterArray) > 1 {
+ filterValue = filterArray[1]
+ } else {
+ filterValue = ""
+ }
+ for labelKey, labelValue := range labels {
+ if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) {
+ result = true
+ continue outer
+ }
+ }
+ result = false
+ }
+
+ case "driver":
+ // matches only for the DefaultNetworkDriver
+ for _, filterValue := range filterValues {
+ plugins := GetCNIPlugins(netconf)
+ if filterValue == DefaultNetworkDriver &&
+ strings.Contains(plugins, DefaultNetworkDriver) {
+ result = true
+ }
+ }
+
+ // TODO: add dangling filter
+ // TODO TODO: add id filter if we support ids
+
+ default:
+ return false, errors.Errorf("invalid filter %q", key)
+ }
+ }
+ return result, nil
+}
diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go
index c74cdb840..762f88a68 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)
+ report, err := getNetworkResourceByName(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) (*types.NetworkResource, error) {
+func getNetworkResourceByName(name string, runtime *libpod.Runtime, filters map[string][]string) (*types.NetworkResource, error) {
var (
ipamConfigs []dockerNetwork.IPAMConfig
)
@@ -85,6 +85,16 @@ func getNetworkResourceByName(name string, runtime *libpod.Runtime) (*types.Netw
if err != nil {
return nil, err
}
+ if len(filters) > 0 {
+ ok, err := network.IfPassesFilter(conf, filters)
+ if err != nil {
+ return nil, err
+ }
+ if !ok {
+ // do not return the config if we did not match the filter
+ return nil, nil
+ }
+ }
// No Bridge plugin means we bail
bridge, err := genericPluginsToBridge(conf.Plugins, network.DefaultNetworkDriver)
@@ -129,14 +139,14 @@ func getNetworkResourceByName(name string, runtime *libpod.Runtime) (*types.Netw
Options: nil,
Config: ipamConfigs,
},
- Internal: false,
+ Internal: !bridge.IsGW,
Attachable: false,
Ingress: false,
ConfigFrom: dockerNetwork.ConfigReference{},
ConfigOnly: false,
Containers: containerEndpoints,
Options: nil,
- Labels: nil,
+ Labels: network.GetNetworkLabels(conf),
Peers: nil,
Services: nil,
}
@@ -180,41 +190,23 @@ func ListNetworks(w http.ResponseWriter, r *http.Request) {
return
}
- filterNames, nameFilterExists := query.Filters["name"]
- // TODO remove when filters are implemented
- if (!nameFilterExists && len(query.Filters) > 0) || len(query.Filters) > 1 {
- utils.InternalServerError(w, errors.New("only the name filter for listing networks is implemented"))
- return
- }
netNames, err := network.GetNetworkNamesFromFileSystem(config)
if err != nil {
utils.InternalServerError(w, err)
return
}
- // filter by name
- if nameFilterExists {
- names := []string{}
- for _, name := range netNames {
- for _, filter := range filterNames {
- if strings.Contains(name, filter) {
- names = append(names, name)
- break
- }
- }
- }
- netNames = names
- }
-
- reports := make([]*types.NetworkResource, 0, len(netNames))
+ var reports []*types.NetworkResource
logrus.Errorf("netNames: %q", strings.Join(netNames, ", "))
for _, name := range netNames {
- report, err := getNetworkResourceByName(name, runtime)
+ report, err := getNetworkResourceByName(name, runtime, query.Filters)
if err != nil {
utils.InternalServerError(w, err)
return
}
- reports = append(reports, report)
+ if report != nil {
+ reports = append(reports, report)
+ }
}
utils.WriteResponse(w, http.StatusOK, reports)
}
@@ -245,6 +237,7 @@ func CreateNetwork(w http.ResponseWriter, r *http.Request) {
ncOptions := entities.NetworkCreateOptions{
Driver: network.DefaultNetworkDriver,
Internal: networkCreate.Internal,
+ Labels: networkCreate.Labels,
}
if networkCreate.IPAM != nil && networkCreate.IPAM.Config != nil {
if len(networkCreate.IPAM.Config) > 1 {
diff --git a/pkg/api/handlers/libpod/networks.go b/pkg/api/handlers/libpod/networks.go
index f1578f829..8511e2733 100644
--- a/pkg/api/handlers/libpod/networks.go
+++ b/pkg/api/handlers/libpod/networks.go
@@ -48,7 +48,7 @@ func ListNetworks(w http.ResponseWriter, r *http.Request) {
runtime := r.Context().Value("runtime").(*libpod.Runtime)
decoder := r.Context().Value("decoder").(*schema.Decoder)
query := struct {
- Filter string `schema:"filter"`
+ Filters map[string][]string `schema:"filters"`
}{
// override any golang type defaults
}
@@ -59,7 +59,7 @@ func ListNetworks(w http.ResponseWriter, r *http.Request) {
}
options := entities.NetworkListOptions{
- Filter: query.Filter,
+ Filters: query.Filters,
}
ic := abi.ContainerEngine{Libpod: runtime}
reports, err := ic.NetworkList(r.Context(), options)
diff --git a/pkg/api/server/register_networks.go b/pkg/api/server/register_networks.go
index ea169cbdf..193b05e6d 100644
--- a/pkg/api/server/register_networks.go
+++ b/pkg/api/server/register_networks.go
@@ -65,7 +65,11 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error {
// - in: query
// name: filters
// type: string
- // description: JSON encoded value of the filters (a map[string][]string) to process on the networks list. Only the name filter is supported.
+ // 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).
+ // - 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:
// - application/json
// responses:
@@ -216,9 +220,14 @@ func (s *APIServer) registerNetworkHandlers(r *mux.Router) error {
// description: Display summary of network configurations
// parameters:
// - in: query
- // name: filter
+ // name: filters
// type: string
- // description: Provide filter values (e.g. 'name=podman')
+ // 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).
+ // - 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`)
// produces:
// - application/json
// responses:
diff --git a/pkg/bindings/network/network.go b/pkg/bindings/network/network.go
index 1d4be8a4c..347f97703 100644
--- a/pkg/bindings/network/network.go
+++ b/pkg/bindings/network/network.go
@@ -2,6 +2,7 @@ package network
import (
"context"
+ "encoding/json"
"net/http"
"net/url"
"strconv"
@@ -79,8 +80,12 @@ func List(ctx context.Context, options entities.NetworkListOptions) ([]*entities
return nil, err
}
params := url.Values{}
- if options.Filter != "" {
- params.Set("filter", options.Filter)
+ if options.Filters != nil {
+ b, err := json.Marshal(options.Filters)
+ if err != nil {
+ return nil, err
+ }
+ params.Set("filters", string(b))
}
response, err := conn.DoRequest(nil, http.MethodGet, "/networks/json", params, nil)
if err != nil {
diff --git a/pkg/domain/entities/network.go b/pkg/domain/entities/network.go
index 86c2e1bcd..f14cac7ef 100644
--- a/pkg/domain/entities/network.go
+++ b/pkg/domain/entities/network.go
@@ -8,14 +8,15 @@ import (
// NetworkListOptions describes options for listing networks in cli
type NetworkListOptions struct {
- Format string
- Quiet bool
- Filter string
+ Format string
+ Quiet bool
+ Filters map[string][]string
}
// NetworkListReport describes the results from listing networks
type NetworkListReport struct {
*libcni.NetworkConfigList
+ Labels map[string]string
}
// NetworkInspectReport describes the results from inspect networks
@@ -39,6 +40,7 @@ type NetworkCreateOptions struct {
Driver string
Gateway net.IP
Internal bool
+ Labels map[string]string
MacVLAN string
Range net.IPNet
Subnet net.IPNet
diff --git a/pkg/domain/infra/abi/network.go b/pkg/domain/infra/abi/network.go
index c52584565..6a219edd5 100644
--- a/pkg/domain/infra/abi/network.go
+++ b/pkg/domain/infra/abi/network.go
@@ -2,10 +2,7 @@ package abi
import (
"context"
- "fmt"
- "strings"
- "github.com/containernetworking/cni/libcni"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/libpod/network"
"github.com/containers/podman/v2/pkg/domain/entities"
@@ -26,18 +23,16 @@ func (ic *ContainerEngine) NetworkList(ctx context.Context, options entities.Net
return nil, err
}
- var tokens []string
- // tokenize the networkListOptions.Filter in key=value.
- if len(options.Filter) > 0 {
- tokens = strings.Split(options.Filter, "=")
- if len(tokens) != 2 {
- return nil, fmt.Errorf("invalid filter syntax : %s", options.Filter)
- }
- }
-
for _, n := range networks {
- if ifPassesFilterTest(n, tokens) {
- reports = append(reports, &entities.NetworkListReport{NetworkConfigList: n})
+ ok, err := network.IfPassesFilter(n, options.Filters)
+ if err != nil {
+ return nil, err
+ }
+ if ok {
+ reports = append(reports, &entities.NetworkListReport{
+ NetworkConfigList: n,
+ Labels: network.GetNetworkLabels(n),
+ })
}
}
return reports, nil
@@ -117,28 +112,6 @@ func (ic *ContainerEngine) NetworkCreate(ctx context.Context, name string, optio
return network.Create(name, options, runtimeConfig)
}
-func ifPassesFilterTest(netconf *libcni.NetworkConfigList, filter []string) bool {
- result := false
- if len(filter) == 0 {
- // No filter, so pass
- return true
- }
- switch strings.ToLower(filter[0]) {
- case "name":
- if filter[1] == netconf.Name {
- result = true
- }
- case "plugin":
- plugins := network.GetCNIPlugins(netconf)
- if strings.Contains(plugins, filter[1]) {
- result = true
- }
- default:
- result = false
- }
- return result
-}
-
// NetworkDisconnect removes a container from a given network
func (ic *ContainerEngine) NetworkDisconnect(ctx context.Context, networkname string, options entities.NetworkDisconnectOptions) error {
return ic.Libpod.DisconnectContainerFromNetwork(options.Container, networkname, options.Force)
diff --git a/test/apiv2/35-networks.at b/test/apiv2/35-networks.at
index ad34511c7..d9556d59f 100644
--- a/test/apiv2/35-networks.at
+++ b/test/apiv2/35-networks.at
@@ -9,8 +9,8 @@ t GET networks/non-existing-network 404 \
t POST libpod/networks/create?name=network1 '' 200 \
.Filename~.*/network1\\.conflist
-# --data '{"Subnet":{"IP":"10.10.254.0","Mask":[255,255,255,0]}}'
-t POST libpod/networks/create?name=network2 '"Subnet":{"IP":"10.10.254.0","Mask":[255,255,255,0]}' 200 \
+# --data '{"Subnet":{"IP":"10.10.254.0","Mask":[255,255,255,0]},"Labels":{"abc":"val"}}'
+t POST libpod/networks/create?name=network2 '"Subnet":{"IP":"10.10.254.0","Mask":[255,255,255,0]},"Labels":{"abc":"val"}' 200 \
.Filename~.*/network2\\.conflist
# test for empty mask
@@ -22,7 +22,8 @@ t POST libpod/networks/create '"Subnet":{"IP":"10.10.1.0","Mask":[0,255,255,0]}'
# network list
t GET libpod/networks/json 200
-t GET libpod/networks/json?filter=name=network1 200 \
+# filters={"name":["network1"]}
+t GET libpod/networks/json?filters=%7B%22name%22%3A%5B%22network1%22%5D%7D 200 \
length=1 \
.[0].Name=network1
t GET networks 200
@@ -34,12 +35,12 @@ length=2
#filters={"name":["network"]}
t GET networks?filters=%7B%22name%22%3A%5B%22network%22%5D%7D 200 \
length=2
-# invalid filter filters={"label":"abc"}
-t GET networks?filters=%7B%22label%22%3A%5B%22abc%22%5D%7D 500 \
-.cause="only the name filter for listing networks is implemented"
-# invalid filter filters={"label":"abc","name":["network"]}
-t GET networks?filters=%7B%22label%22%3A%22abc%22%2C%22name%22%3A%5B%22network%22%5D%7D 500 \
-.cause="only the name filter for listing networks is implemented"
+# 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"'
# clean the network
t DELETE libpod/networks/network1 200 \
diff --git a/test/e2e/network_test.go b/test/e2e/network_test.go
index 20e1d5b6b..ad6af61c7 100644
--- a/test/e2e/network_test.go
+++ b/test/e2e/network_test.go
@@ -66,6 +66,65 @@ var _ = Describe("Podman network", func() {
Expect(session.LineInOutputContains(name)).To(BeTrue())
})
+ It("podman network list --filter plugin and name", func() {
+ name, path := generateNetworkConfig(podmanTest)
+ defer removeConf(path)
+
+ session := podmanTest.Podman([]string{"network", "ls", "--filter", "plugin=bridge", "--filter", "name=" + name})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(ContainSubstring(name))
+ })
+
+ It("podman network list --filter two names", func() {
+ name1, path1 := generateNetworkConfig(podmanTest)
+ defer removeConf(path1)
+
+ name2, path2 := generateNetworkConfig(podmanTest)
+ defer removeConf(path2)
+
+ session := podmanTest.Podman([]string{"network", "ls", "--filter", "name=" + name1, "--filter", "name=" + name2})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(ContainSubstring(name1))
+ Expect(session.OutputToString()).To(ContainSubstring(name2))
+ })
+
+ It("podman network list --filter labels", func() {
+ net1 := "labelnet" + stringid.GenerateNonCryptoID()
+ label1 := "testlabel1=abc"
+ label2 := "abcdef"
+ session := podmanTest.Podman([]string{"network", "create", "--label", label1, net1})
+ session.WaitWithDefaultTimeout()
+ defer podmanTest.removeCNINetwork(net1)
+ Expect(session.ExitCode()).To(BeZero())
+
+ net2 := "labelnet" + stringid.GenerateNonCryptoID()
+ session = podmanTest.Podman([]string{"network", "create", "--label", label1, "--label", label2, net2})
+ session.WaitWithDefaultTimeout()
+ defer podmanTest.removeCNINetwork(net2)
+ Expect(session.ExitCode()).To(BeZero())
+
+ session = podmanTest.Podman([]string{"network", "ls", "--filter", "label=" + label1})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).To(ContainSubstring(net1))
+ Expect(session.OutputToString()).To(ContainSubstring(net2))
+
+ session = podmanTest.Podman([]string{"network", "ls", "--filter", "label=" + label1, "--filter", "label=" + label2})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.OutputToString()).ToNot(ContainSubstring(net1))
+ Expect(session.OutputToString()).To(ContainSubstring(net2))
+ })
+
+ It("podman network list --filter invalid value", func() {
+ session := podmanTest.Podman([]string{"network", "ls", "--filter", "namr=ab"})
+ session.WaitWithDefaultTimeout()
+ Expect(session).To(ExitWithError())
+ Expect(session.ErrorToString()).To(ContainSubstring(`invalid filter "namr"`))
+ })
+
It("podman network list --filter failure", func() {
name, path := generateNetworkConfig(podmanTest)
defer removeConf(path)