Skip to content

Commit

Permalink
Merge pull request moby#33630 from yongtang/167-cli-network-inspect-s…
Browse files Browse the repository at this point in the history
…cope

Add `scope` filter in `GET /networks/(id or name)`
  • Loading branch information
aaronlehmann authored Jun 13, 2017
2 parents 8183b9d + 158b2a1 commit 4310f7d
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 17 deletions.
20 changes: 14 additions & 6 deletions api/server/router/network/network_routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r
return errors.NewBadRequestError(err)
}
}
scope := r.URL.Query().Get("scope")

isMatchingScope := func(scope, term string) bool {
if term != "" {
return scope == term
}
return true
}

// In case multiple networks have duplicate names, return error.
// TODO (yongtang): should we wrap with version here for backward compatibility?
Expand All @@ -112,15 +120,15 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r

nw := n.backend.GetNetworks()
for _, network := range nw {
if network.ID() == term {
if network.ID() == term && isMatchingScope(network.Info().Scope(), scope) {
return httputils.WriteJSON(w, http.StatusOK, *n.buildDetailedNetworkResources(network, verbose))
}
if network.Name() == term {
if network.Name() == term && isMatchingScope(network.Info().Scope(), scope) {
// No need to check the ID collision here as we are still in
// local scope and the network ID is unique in this scope.
listByFullName[network.ID()] = *n.buildDetailedNetworkResources(network, verbose)
}
if strings.HasPrefix(network.ID(), term) {
if strings.HasPrefix(network.ID(), term) && isMatchingScope(network.Info().Scope(), scope) {
// No need to check the ID collision here as we are still in
// local scope and the network ID is unique in this scope.
listByPartialID[network.ID()] = *n.buildDetailedNetworkResources(network, verbose)
Expand All @@ -129,18 +137,18 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r

nr, _ := n.cluster.GetNetworks()
for _, network := range nr {
if network.ID == term {
if network.ID == term && isMatchingScope(network.Scope, scope) {
return httputils.WriteJSON(w, http.StatusOK, network)
}
if network.Name == term {
if network.Name == term && isMatchingScope(network.Scope, scope) {
// Check the ID collision as we are in swarm scope here, and
// the map (of the listByFullName) may have already had a
// network with the same ID (from local scope previously)
if _, ok := listByFullName[network.ID]; !ok {
listByFullName[network.ID] = network
}
}
if strings.HasPrefix(network.ID, term) {
if strings.HasPrefix(network.ID, term) && isMatchingScope(network.Scope, scope) {
// Check the ID collision as we are in swarm scope here, and
// the map (of the listByPartialID) may have already had a
// network with the same ID (from local scope previously)
Expand Down
4 changes: 4 additions & 0 deletions api/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6437,6 +6437,10 @@ paths:
description: "Detailed inspect output for troubleshooting"
type: "boolean"
default: false
- name: "scope"
in: "query"
description: "Filter the network by scope (swarm, global, or local)"
type: "string"
tags: ["Network"]

delete:
Expand Down
6 changes: 6 additions & 0 deletions api/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,12 @@ type NetworkDisconnect struct {
Force bool
}

// NetworkInspectOptions holds parameters to inspect network
type NetworkInspectOptions struct {
Scope string
Verbose bool
}

// Checkpoint represents the details of a checkpoint
type Checkpoint struct {
Name string // Name is the name of the checkpoint
Expand Down
4 changes: 2 additions & 2 deletions client/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ type NetworkAPIClient interface {
NetworkConnect(ctx context.Context, networkID, container string, config *network.EndpointSettings) error
NetworkCreate(ctx context.Context, name string, options types.NetworkCreate) (types.NetworkCreateResponse, error)
NetworkDisconnect(ctx context.Context, networkID, container string, force bool) error
NetworkInspect(ctx context.Context, networkID string, verbose bool) (types.NetworkResource, error)
NetworkInspectWithRaw(ctx context.Context, networkID string, verbose bool) (types.NetworkResource, []byte, error)
NetworkInspect(ctx context.Context, networkID string, options types.NetworkInspectOptions) (types.NetworkResource, error)
NetworkInspectWithRaw(ctx context.Context, networkID string, options types.NetworkInspectOptions) (types.NetworkResource, []byte, error)
NetworkList(ctx context.Context, options types.NetworkListOptions) ([]types.NetworkResource, error)
NetworkRemove(ctx context.Context, networkID string) error
NetworksPrune(ctx context.Context, pruneFilter filters.Args) (types.NetworksPruneReport, error)
Expand Down
11 changes: 7 additions & 4 deletions client/network_inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,25 @@ import (
)

// NetworkInspect returns the information for a specific network configured in the docker host.
func (cli *Client) NetworkInspect(ctx context.Context, networkID string, verbose bool) (types.NetworkResource, error) {
networkResource, _, err := cli.NetworkInspectWithRaw(ctx, networkID, verbose)
func (cli *Client) NetworkInspect(ctx context.Context, networkID string, options types.NetworkInspectOptions) (types.NetworkResource, error) {
networkResource, _, err := cli.NetworkInspectWithRaw(ctx, networkID, options)
return networkResource, err
}

// NetworkInspectWithRaw returns the information for a specific network configured in the docker host and its raw representation.
func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string, verbose bool) (types.NetworkResource, []byte, error) {
func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string, options types.NetworkInspectOptions) (types.NetworkResource, []byte, error) {
var (
networkResource types.NetworkResource
resp serverResponse
err error
)
query := url.Values{}
if verbose {
if options.Verbose {
query.Set("verbose", "true")
}
if options.Scope != "" {
query.Set("scope", options.Scope)
}
resp, err = cli.get(ctx, "/networks/"+networkID, query, nil)
if err != nil {
if resp.statusCode == http.StatusNotFound {
Expand Down
21 changes: 16 additions & 5 deletions client/network_inspect_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/network"
"github.com/stretchr/testify/assert"
"golang.org/x/net/context"
)

Expand All @@ -19,7 +20,7 @@ func TestNetworkInspectError(t *testing.T) {
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
}

_, err := client.NetworkInspect(context.Background(), "nothing", false)
_, err := client.NetworkInspect(context.Background(), "nothing", types.NetworkInspectOptions{})
if err == nil || err.Error() != "Error response from daemon: Server error" {
t.Fatalf("expected a Server Error, got %v", err)
}
Expand All @@ -30,7 +31,7 @@ func TestNetworkInspectContainerNotFound(t *testing.T) {
client: newMockClient(errorMock(http.StatusNotFound, "Server error")),
}

_, err := client.NetworkInspect(context.Background(), "unknown", false)
_, err := client.NetworkInspect(context.Background(), "unknown", types.NetworkInspectOptions{})
if err == nil || !IsErrNetworkNotFound(err) {
t.Fatalf("expected a networkNotFound error, got %v", err)
}
Expand All @@ -51,7 +52,14 @@ func TestNetworkInspect(t *testing.T) {
content []byte
err error
)
if strings.HasPrefix(req.URL.RawQuery, "verbose=true") {
if strings.Contains(req.URL.RawQuery, "scope=global") {
return &http.Response{
StatusCode: http.StatusNotFound,
Body: ioutil.NopCloser(bytes.NewReader(content)),
}, nil
}

if strings.Contains(req.URL.RawQuery, "verbose=true") {
s := map[string]network.ServiceInfo{
"web": {},
}
Expand All @@ -74,15 +82,15 @@ func TestNetworkInspect(t *testing.T) {
}),
}

r, err := client.NetworkInspect(context.Background(), "network_id", false)
r, err := client.NetworkInspect(context.Background(), "network_id", types.NetworkInspectOptions{})
if err != nil {
t.Fatal(err)
}
if r.Name != "mynetwork" {
t.Fatalf("expected `mynetwork`, got %s", r.Name)
}

r, err = client.NetworkInspect(context.Background(), "network_id", true)
r, err = client.NetworkInspect(context.Background(), "network_id", types.NetworkInspectOptions{Verbose: true})
if err != nil {
t.Fatal(err)
}
Expand All @@ -93,4 +101,7 @@ func TestNetworkInspect(t *testing.T) {
if !ok {
t.Fatalf("expected service `web` missing in the verbose output")
}

_, err = client.NetworkInspect(context.Background(), "network_id", types.NetworkInspectOptions{Scope: "global"})
assert.EqualError(t, err, "Error: No such network: network_id")
}
1 change: 1 addition & 0 deletions docs/api/version-history.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ keywords: "API, Docker, rcli, REST, documentation"
* `POST /secrets/create` now returns status code 409 instead of 500 when creating an already existing secret.
* `POST /secrets/(name)/update` now returns status code 400 instead of 500 when updating a secret's content which is not the labels.
* `POST /nodes/(name)/update` now returns status code 400 instead of 500 when demoting last node fails.
* `GET /networks/(id or name)` now takes an optional query parameter `scope` that will filter the network based on the scope (`local`, `swarm`, or `global`).

## v1.30 API changes

Expand Down
34 changes: 34 additions & 0 deletions integration-cli/docker_api_swarm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"io/ioutil"
"net"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -1002,3 +1003,36 @@ func (s *DockerSwarmSuite) TestSwarmRepeatedRootRotation(c *check.C) {
currentTrustRoot = clusterTLSInfo.TrustRoot
}
}

func (s *DockerSwarmSuite) TestAPINetworkInspectWithScope(c *check.C) {
d := s.AddDaemon(c, true, true)

name := "foo"
networkCreateRequest := types.NetworkCreateRequest{
Name: name,
}

var n types.NetworkCreateResponse
networkCreateRequest.NetworkCreate.Driver = "overlay"

status, out, err := d.SockRequest("POST", "/networks/create", networkCreateRequest)
c.Assert(err, checker.IsNil, check.Commentf(string(out)))
c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf(string(out)))
c.Assert(json.Unmarshal(out, &n), checker.IsNil)

var r types.NetworkResource

status, body, err := d.SockRequest("GET", "/networks/"+name, nil)
c.Assert(err, checker.IsNil, check.Commentf(string(out)))
c.Assert(status, checker.Equals, http.StatusOK, check.Commentf(string(out)))
c.Assert(json.Unmarshal(body, &r), checker.IsNil)
c.Assert(r.Scope, checker.Equals, "swarm")
c.Assert(r.ID, checker.Equals, n.ID)

v := url.Values{}
v.Set("scope", "local")

status, body, err = d.SockRequest("GET", "/networks/"+name+"?"+v.Encode(), nil)
c.Assert(err, checker.IsNil, check.Commentf(string(out)))
c.Assert(status, checker.Equals, http.StatusNotFound, check.Commentf(string(out)))
}

0 comments on commit 4310f7d

Please sign in to comment.