Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add filter for network ls to hide predefined network #17782

Merged
merged 1 commit into from
Dec 23, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ type apiClient interface {
NetworkCreate(options types.NetworkCreate) (types.NetworkCreateResponse, error)
NetworkDisconnect(networkID, containerID string) error
NetworkInspect(networkID string) (types.NetworkResource, error)
NetworkList() ([]types.NetworkResource, error)
NetworkList(options types.NetworkListOptions) ([]types.NetworkResource, error)
NetworkRemove(networkID string) error
RegistryLogin(auth types.AuthConfig) (types.AuthResponse, error)
ServerVersion() (types.Version, error)
Expand Down
15 changes: 13 additions & 2 deletions api/client/lib/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package lib
import (
"encoding/json"
"net/http"
"net/url"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
)

// NetworkCreate creates a new network in the docker host.
Expand Down Expand Up @@ -44,9 +46,18 @@ func (cli *Client) NetworkDisconnect(networkID, containerID string) error {
}

// NetworkList returns the list of networks configured in the docker host.
func (cli *Client) NetworkList() ([]types.NetworkResource, error) {
func (cli *Client) NetworkList(options types.NetworkListOptions) ([]types.NetworkResource, error) {
query := url.Values{}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToParam(options.Filters)
if err != nil {
return nil, err
}

query.Set("filters", filterJSON)
}
var networkResources []types.NetworkResource
resp, err := cli.get("/networks", nil, nil)
resp, err := cli.get("/networks", query, nil)
if err != nil {
return networkResources, err
}
Expand Down
22 changes: 20 additions & 2 deletions api/client/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"text/tabwriter"

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/network"
Cli "github.com/docker/docker/cli"
"github.com/docker/docker/opts"
Expand Down Expand Up @@ -138,12 +139,29 @@ func (cli *DockerCli) CmdNetworkLs(args ...string) error {
quiet := cmd.Bool([]string{"q", "-quiet"}, false, "Only display numeric IDs")
noTrunc := cmd.Bool([]string{"-no-trunc"}, false, "Do not truncate the output")

flFilter := opts.NewListOpts(nil)
cmd.Var(&flFilter, []string{"f", "-filter"}, "Filter output based on conditions provided")

cmd.Require(flag.Exact, 0)
if err := cmd.ParseFlags(args, true); err != nil {
err := cmd.ParseFlags(args, true)
if err != nil {
return err
}

networkResources, err := cli.client.NetworkList()
// Consolidate all filter flags, and sanity check them early.
// They'll get process after get response from server.
netFilterArgs := filters.NewArgs()
for _, f := range flFilter.GetAll() {
if netFilterArgs, err = filters.ParseFlag(f, netFilterArgs); err != nil {
return err
}
}

options := types.NetworkListOptions{
Filters: netFilterArgs,
}

networkResources, err := cli.client.NetworkList(options)
if err != nil {
return err
}
Expand Down
1 change: 1 addition & 0 deletions api/server/router/network/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type Backend interface {
FindNetwork(idName string) (libnetwork.Network, error)
GetNetwork(idName string, by int) (libnetwork.Network, error)
GetNetworksByID(partialID string) []libnetwork.Network
GetAllNetworks() []libnetwork.Network
CreateNetwork(name, driver string, ipam network.IPAM,
options map[string]string) (libnetwork.Network, error)
ConnectContainerToNetwork(containerName, networkName string) error
Expand Down
110 changes: 110 additions & 0 deletions api/server/router/network/filter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package network

import (
"fmt"
"regexp"
"strings"

"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/runconfig"
"github.com/docker/libnetwork"
)

type filterHandler func([]libnetwork.Network, string) ([]libnetwork.Network, error)

var (
// supportedFilters predefined some supported filter handler function
supportedFilters = map[string]filterHandler{
"type": filterNetworkByType,
"name": filterNetworkByName,
"id": filterNetworkByID,
}

// acceptFilters is an acceptable filter flag list
// generated for validation. e.g.
// acceptedFilters = map[string]bool{
// "type": true,
// "name": true,
// "id": true,
// }
acceptedFilters = func() map[string]bool {
ret := make(map[string]bool)
for k := range supportedFilters {
ret[k] = true
}
return ret
}()
)

func filterNetworkByType(nws []libnetwork.Network, netType string) (retNws []libnetwork.Network, err error) {
switch netType {
case "builtin":
for _, nw := range nws {
if runconfig.IsPreDefinedNetwork(nw.Name()) {
retNws = append(retNws, nw)
}
}
case "custom":
for _, nw := range nws {
if !runconfig.IsPreDefinedNetwork(nw.Name()) {
retNws = append(retNws, nw)
}
}
default:
return nil, fmt.Errorf("Invalid filter: 'type'='%s'", netType)
}
return retNws, nil
}

func filterNetworkByName(nws []libnetwork.Network, name string) (retNws []libnetwork.Network, err error) {
for _, nw := range nws {
// exact match (fast path)
if nw.Name() == name {
retNws = append(retNws, nw)
continue
}

// regexp match (slow path)
match, err := regexp.MatchString(name, nw.Name())
if err != nil || !match {
continue
} else {
retNws = append(retNws, nw)
}
}
return retNws, nil
}

func filterNetworkByID(nws []libnetwork.Network, id string) (retNws []libnetwork.Network, err error) {
for _, nw := range nws {
if strings.HasPrefix(nw.ID(), id) {
retNws = append(retNws, nw)
}
}
return retNws, nil
}

// filterAllNetworks filter network list according to user specified filter
// and return user chosen networks
func filterNetworks(nws []libnetwork.Network, filter filters.Args) ([]libnetwork.Network, error) {
// if filter is empty, return original network list
if filter.Len() == 0 {
return nws, nil
}

var displayNet []libnetwork.Network
for fkey, fhandler := range supportedFilters {
errFilter := filter.WalkValues(fkey, func(fval string) error {
passList, err := fhandler(nws, fval)
if err != nil {
return err
}
displayNet = append(displayNet, passList...)
return nil
})
if errFilter != nil {
return nil, errFilter
}
}
return displayNet, nil
}
34 changes: 14 additions & 20 deletions api/server/router/network/network_routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (

"golang.org/x/net/context"

"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
Expand All @@ -28,29 +27,24 @@ func (n *networkRouter) getNetworksList(ctx context.Context, w http.ResponseWrit
return err
}

list := []*types.NetworkResource{}
netFilters.WalkValues("name", func(name string) error {
if nw, err := n.backend.GetNetwork(name, daemon.NetworkByName); err == nil {
list = append(list, buildNetworkResource(nw))
} else {
logrus.Errorf("failed to get network for filter=%s : %v", name, err)
if netFilters.Len() != 0 {
if err := netFilters.Validate(acceptedFilters); err != nil {
return err
}
return nil
})
}

netFilters.WalkValues("id", func(id string) error {
for _, nw := range n.backend.GetNetworksByID(id) {
list = append(list, buildNetworkResource(nw))
}
return nil
})
list := []*types.NetworkResource{}

if !netFilters.Include("name") && !netFilters.Include("id") {
nwList := n.backend.GetNetworksByID("")
for _, nw := range nwList {
list = append(list, buildNetworkResource(nw))
}
nwList := n.backend.GetAllNetworks()
displayable, err := filterNetworks(nwList, netFilters)
if err != nil {
return err
}

for _, nw := range displayable {
list = append(list, buildNetworkResource(nw))
}

return httputils.WriteJSON(w, http.StatusOK, list)
}

Expand Down
5 changes: 5 additions & 0 deletions api/types/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ type EventsOptions struct {
Filters filters.Args
}

// NetworkListOptions holds parameters to filter the list of networks with.
type NetworkListOptions struct {
Filters filters.Args
}

// HijackedResponse holds connection information for a hijacked request.
type HijackedResponse struct {
Conn net.Conn
Expand Down
13 changes: 13 additions & 0 deletions daemon/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,19 @@ func (daemon *Daemon) GetNetworksByID(partialID string) []libnetwork.Network {
return list
}

// GetAllNetworks returns a list containing all networks
func (daemon *Daemon) GetAllNetworks() []libnetwork.Network {
c := daemon.netController
list := []libnetwork.Network{}
l := func(nw libnetwork.Network) bool {
list = append(list, nw)
return false
}
c.WalkNetworks(l)

return list
}

// CreateNetwork creates a network with the given name, driver and other optional parameters
func (daemon *Daemon) CreateNetwork(name, driver string, ipam network.IPAM, options map[string]string) (libnetwork.Network, error) {
c := daemon.netController
Expand Down
1 change: 1 addition & 0 deletions docs/reference/api/docker_remote_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ This section lists each version from latest to oldest. Each listing includes a
the push or pull completes.
* `POST /containers/create` now allows you to set a read/write rate limit for a
device (in bytes per second or IO per second).
* `GET /networks` now supports filtering by `name`, `id` and `type`.

### v1.21 API changes

Expand Down
9 changes: 5 additions & 4 deletions docs/reference/api/docker_remote_api_v1.22.md
Original file line number Diff line number Diff line change
Expand Up @@ -2728,7 +2728,7 @@ Status Codes

**Example request**:

GET /networks HTTP/1.1
GET /networks?filters={"type":{"custom":true}} HTTP/1.1

**Example response**:

Expand Down Expand Up @@ -2794,11 +2794,12 @@ Content-Type: application/json
]
```



Query Parameters:

- **filters** - JSON encoded value of the filters (a `map[string][]string`) to process on the networks list. Available filters: `name=[network-names]` , `id=[network-ids]`
- **filters** - JSON encoded network list filter. The filter value is one of:
- `name=<network-name>` Matches all or part of a network name.
- `id=<network-id>` Matches all or part of a network id.
- `type=["custom"|"builtin"]` Filters networks by type. The `custom` keyword returns all user-defined networks.

Status Codes:

Expand Down
Loading