mirror of
				https://github.com/moby/moby.git
				synced 2022-11-09 12:21:53 -05:00 
			
		
		
		
	Enhance network inspect to show all tasks, local & non-local, in swarm mode
Signed-off-by: Santhosh Manohar <santhosh@docker.com>
This commit is contained in:
		
							parent
							
								
									6708676464
								
							
						
					
					
						commit
						14f76a21db
					
				
					 13 changed files with 320 additions and 37 deletions
				
			
		| 
						 | 
				
			
			@ -4,10 +4,12 @@ import (
 | 
			
		|||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
 | 
			
		||||
	"github.com/docker/docker/api/errors"
 | 
			
		||||
	"github.com/docker/docker/api/server/httputils"
 | 
			
		||||
	"github.com/docker/docker/api/types"
 | 
			
		||||
	"github.com/docker/docker/api/types/filters"
 | 
			
		||||
| 
						 | 
				
			
			@ -65,7 +67,7 @@ SKIP:
 | 
			
		|||
		// run across all the networks. Starting API version 1.27, this detailed
 | 
			
		||||
		// info is available for network specific GET API (equivalent to inspect)
 | 
			
		||||
		if versions.LessThan(httputils.VersionFromContext(ctx), "1.27") {
 | 
			
		||||
			nr = n.buildDetailedNetworkResources(nw)
 | 
			
		||||
			nr = n.buildDetailedNetworkResources(nw, false)
 | 
			
		||||
		} else {
 | 
			
		||||
			nr = n.buildNetworkResource(nw)
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -85,6 +87,16 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	term := vars["id"]
 | 
			
		||||
	var (
 | 
			
		||||
		verbose bool
 | 
			
		||||
		err     error
 | 
			
		||||
	)
 | 
			
		||||
	if v := r.URL.Query().Get("verbose"); v != "" {
 | 
			
		||||
		if verbose, err = strconv.ParseBool(v); err != nil {
 | 
			
		||||
			err = fmt.Errorf("invalid value for verbose: %s", v)
 | 
			
		||||
			return errors.NewBadRequestError(err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// In case multiple networks have duplicate names, return error.
 | 
			
		||||
	// TODO (yongtang): should we wrap with version here for backward compatibility?
 | 
			
		||||
| 
						 | 
				
			
			@ -100,17 +112,17 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r
 | 
			
		|||
	nw := n.backend.GetNetworks()
 | 
			
		||||
	for _, network := range nw {
 | 
			
		||||
		if network.ID() == term {
 | 
			
		||||
			return httputils.WriteJSON(w, http.StatusOK, *n.buildDetailedNetworkResources(network))
 | 
			
		||||
			return httputils.WriteJSON(w, http.StatusOK, *n.buildDetailedNetworkResources(network, verbose))
 | 
			
		||||
		}
 | 
			
		||||
		if network.Name() == term {
 | 
			
		||||
			// 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)
 | 
			
		||||
			listByFullName[network.ID()] = *n.buildDetailedNetworkResources(network, verbose)
 | 
			
		||||
		}
 | 
			
		||||
		if strings.HasPrefix(network.ID(), term) {
 | 
			
		||||
			// 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)
 | 
			
		||||
			listByPartialID[network.ID()] = *n.buildDetailedNetworkResources(network, verbose)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -294,7 +306,7 @@ func (n *networkRouter) buildNetworkResource(nw libnetwork.Network) *types.Netwo
 | 
			
		|||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (n *networkRouter) buildDetailedNetworkResources(nw libnetwork.Network) *types.NetworkResource {
 | 
			
		||||
func (n *networkRouter) buildDetailedNetworkResources(nw libnetwork.Network, verbose bool) *types.NetworkResource {
 | 
			
		||||
	if nw == nil {
 | 
			
		||||
		return &types.NetworkResource{}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -315,6 +327,28 @@ func (n *networkRouter) buildDetailedNetworkResources(nw libnetwork.Network) *ty
 | 
			
		|||
 | 
			
		||||
		r.Containers[key] = buildEndpointResource(tmpID, e.Name(), ei)
 | 
			
		||||
	}
 | 
			
		||||
	if !verbose {
 | 
			
		||||
		return r
 | 
			
		||||
	}
 | 
			
		||||
	services := nw.Info().Services()
 | 
			
		||||
	r.Services = make(map[string]network.ServiceInfo)
 | 
			
		||||
	for name, service := range services {
 | 
			
		||||
		tasks := []network.Task{}
 | 
			
		||||
		for _, t := range service.Tasks {
 | 
			
		||||
			tasks = append(tasks, network.Task{
 | 
			
		||||
				Name:       t.Name,
 | 
			
		||||
				EndpointID: t.EndpointID,
 | 
			
		||||
				EndpointIP: t.EndpointIP,
 | 
			
		||||
				Info:       t.Info,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		r.Services[name] = network.ServiceInfo{
 | 
			
		||||
			VIP:          service.VIP,
 | 
			
		||||
			Ports:        service.Ports,
 | 
			
		||||
			Tasks:        tasks,
 | 
			
		||||
			LocalLBIndex: service.LocalLBIndex,
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6265,6 +6265,11 @@ paths:
 | 
			
		|||
          description: "Network ID or name"
 | 
			
		||||
          required: true
 | 
			
		||||
          type: "string"
 | 
			
		||||
        - name: "verbose"
 | 
			
		||||
          in: "query"
 | 
			
		||||
          description: "Detailed inspect output for troubleshooting"
 | 
			
		||||
          type: "boolean"
 | 
			
		||||
          default: false
 | 
			
		||||
      tags: ["Network"]
 | 
			
		||||
 | 
			
		||||
    delete:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,6 +60,22 @@ type EndpointSettings struct {
 | 
			
		|||
	MacAddress          string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Task carries the information about one backend task
 | 
			
		||||
type Task struct {
 | 
			
		||||
	Name       string
 | 
			
		||||
	EndpointID string
 | 
			
		||||
	EndpointIP string
 | 
			
		||||
	Info       map[string]string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ServiceInfo represents service parameters with the list of service's tasks
 | 
			
		||||
type ServiceInfo struct {
 | 
			
		||||
	VIP          string
 | 
			
		||||
	Ports        []string
 | 
			
		||||
	LocalLBIndex int
 | 
			
		||||
	Tasks        []Task
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Copy makes a deep copy of `EndpointSettings`
 | 
			
		||||
func (es *EndpointSettings) Copy() *EndpointSettings {
 | 
			
		||||
	epCopy := *es
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -390,19 +390,20 @@ type MountPoint struct {
 | 
			
		|||
 | 
			
		||||
// NetworkResource is the body of the "get network" http response message
 | 
			
		||||
type NetworkResource struct {
 | 
			
		||||
	Name       string                      // Name is the requested name of the network
 | 
			
		||||
	ID         string                      `json:"Id"` // ID uniquely identifies a network on a single machine
 | 
			
		||||
	Created    time.Time                   // Created is the time the network created
 | 
			
		||||
	Scope      string                      // Scope describes the level at which the network exists (e.g. `global` for cluster-wide or `local` for machine level)
 | 
			
		||||
	Driver     string                      // Driver is the Driver name used to create the network (e.g. `bridge`, `overlay`)
 | 
			
		||||
	EnableIPv6 bool                        // EnableIPv6 represents whether to enable IPv6
 | 
			
		||||
	IPAM       network.IPAM                // IPAM is the network's IP Address Management
 | 
			
		||||
	Internal   bool                        // Internal represents if the network is used internal only
 | 
			
		||||
	Attachable bool                        // Attachable represents if the global scope is manually attachable by regular containers from workers in swarm mode.
 | 
			
		||||
	Containers map[string]EndpointResource // Containers contains endpoints belonging to the network
 | 
			
		||||
	Options    map[string]string           // Options holds the network specific options to use for when creating the network
 | 
			
		||||
	Labels     map[string]string           // Labels holds metadata specific to the network being created
 | 
			
		||||
	Peers      []network.PeerInfo          `json:",omitempty"` // List of peer nodes for an overlay network
 | 
			
		||||
	Name       string                         // Name is the requested name of the network
 | 
			
		||||
	ID         string                         `json:"Id"` // ID uniquely identifies a network on a single machine
 | 
			
		||||
	Created    time.Time                      // Created is the time the network created
 | 
			
		||||
	Scope      string                         // Scope describes the level at which the network exists (e.g. `global` for cluster-wide or `local` for machine level)
 | 
			
		||||
	Driver     string                         // Driver is the Driver name used to create the network (e.g. `bridge`, `overlay`)
 | 
			
		||||
	EnableIPv6 bool                           // EnableIPv6 represents whether to enable IPv6
 | 
			
		||||
	IPAM       network.IPAM                   // IPAM is the network's IP Address Management
 | 
			
		||||
	Internal   bool                           // Internal represents if the network is used internal only
 | 
			
		||||
	Attachable bool                           // Attachable represents if the global scope is manually attachable by regular containers from workers in swarm mode.
 | 
			
		||||
	Containers map[string]EndpointResource    // Containers contains endpoints belonging to the network
 | 
			
		||||
	Options    map[string]string              // Options holds the network specific options to use for when creating the network
 | 
			
		||||
	Labels     map[string]string              // Labels holds metadata specific to the network being created
 | 
			
		||||
	Peers      []network.PeerInfo             `json:",omitempty"` // List of peer nodes for an overlay network
 | 
			
		||||
	Services   map[string]network.ServiceInfo `json:",omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EndpointResource contains network resources allocated and used for a container in a network
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,8 +10,9 @@ import (
 | 
			
		|||
)
 | 
			
		||||
 | 
			
		||||
type inspectOptions struct {
 | 
			
		||||
	format string
 | 
			
		||||
	names  []string
 | 
			
		||||
	format  string
 | 
			
		||||
	names   []string
 | 
			
		||||
	verbose bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newInspectCommand(dockerCli *command.DockerCli) *cobra.Command {
 | 
			
		||||
| 
						 | 
				
			
			@ -28,6 +29,7 @@ func newInspectCommand(dockerCli *command.DockerCli) *cobra.Command {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	cmd.Flags().StringVarP(&opts.format, "format", "f", "", "Format the output using the given Go template")
 | 
			
		||||
	cmd.Flags().BoolVarP(&opts.verbose, "verbose", "v", false, "Verbose output for diagnostics")
 | 
			
		||||
 | 
			
		||||
	return cmd
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -38,7 +40,7 @@ func runInspect(dockerCli *command.DockerCli, opts inspectOptions) error {
 | 
			
		|||
	ctx := context.Background()
 | 
			
		||||
 | 
			
		||||
	getNetFunc := func(name string) (interface{}, []byte, error) {
 | 
			
		||||
		return client.NetworkInspectWithRaw(ctx, name)
 | 
			
		||||
		return client.NetworkInspectWithRaw(ctx, name, opts.verbose)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return inspect.Inspect(dockerCli.Out(), opts.names, opts.format, getNetFunc)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -140,7 +140,7 @@ func validateExternalNetworks(
 | 
			
		|||
	client := dockerCli.Client()
 | 
			
		||||
 | 
			
		||||
	for _, networkName := range externalNetworks {
 | 
			
		||||
		network, err := client.NetworkInspect(ctx, networkName)
 | 
			
		||||
		network, err := client.NetworkInspect(ctx, networkName, false)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if dockerclient.IsErrNetworkNotFound(err) {
 | 
			
		||||
				return fmt.Errorf("network %q is declared as external, but could not be found. You need to create the network before the stack is deployed (with overlay driver)", networkName)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -67,7 +67,7 @@ func inspectImages(ctx context.Context, dockerCli *command.DockerCli) inspect.Ge
 | 
			
		|||
 | 
			
		||||
func inspectNetwork(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc {
 | 
			
		||||
	return func(ref string) (interface{}, []byte, error) {
 | 
			
		||||
		return dockerCli.Client().NetworkInspectWithRaw(ctx, ref)
 | 
			
		||||
		return dockerCli.Client().NetworkInspectWithRaw(ctx, ref, false)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -91,8 +91,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) (types.NetworkResource, error)
 | 
			
		||||
	NetworkInspectWithRaw(ctx context.Context, networkID string) (types.NetworkResource, []byte, error)
 | 
			
		||||
	NetworkInspect(ctx context.Context, networkID string, verbose bool) (types.NetworkResource, error)
 | 
			
		||||
	NetworkInspectWithRaw(ctx context.Context, networkID string, verbose bool) (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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,21 +5,30 @@ import (
 | 
			
		|||
	"encoding/json"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
 | 
			
		||||
	"github.com/docker/docker/api/types"
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// NetworkInspect returns the information for a specific network configured in the docker host.
 | 
			
		||||
func (cli *Client) NetworkInspect(ctx context.Context, networkID string) (types.NetworkResource, error) {
 | 
			
		||||
	networkResource, _, err := cli.NetworkInspectWithRaw(ctx, networkID)
 | 
			
		||||
func (cli *Client) NetworkInspect(ctx context.Context, networkID string, verbose bool) (types.NetworkResource, error) {
 | 
			
		||||
	networkResource, _, err := cli.NetworkInspectWithRaw(ctx, networkID, verbose)
 | 
			
		||||
	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) (types.NetworkResource, []byte, error) {
 | 
			
		||||
	var networkResource types.NetworkResource
 | 
			
		||||
	resp, err := cli.get(ctx, "/networks/"+networkID, nil, nil)
 | 
			
		||||
func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string, verbose bool) (types.NetworkResource, []byte, error) {
 | 
			
		||||
	var (
 | 
			
		||||
		networkResource types.NetworkResource
 | 
			
		||||
		resp            serverResponse
 | 
			
		||||
		err             error
 | 
			
		||||
	)
 | 
			
		||||
	query := url.Values{}
 | 
			
		||||
	if verbose {
 | 
			
		||||
		query.Set("verbose", "true")
 | 
			
		||||
	}
 | 
			
		||||
	resp, err = cli.get(ctx, "/networks/"+networkID, query, nil)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if resp.statusCode == http.StatusNotFound {
 | 
			
		||||
			return networkResource, nil, networkNotFoundError{networkID}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,6 +10,7 @@ import (
 | 
			
		|||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/docker/docker/api/types"
 | 
			
		||||
	"github.com/docker/docker/api/types/network"
 | 
			
		||||
	"golang.org/x/net/context"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +19,7 @@ func TestNetworkInspectError(t *testing.T) {
 | 
			
		|||
		client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err := client.NetworkInspect(context.Background(), "nothing")
 | 
			
		||||
	_, err := client.NetworkInspect(context.Background(), "nothing", false)
 | 
			
		||||
	if err == nil || err.Error() != "Error response from daemon: Server error" {
 | 
			
		||||
		t.Fatalf("expected a Server Error, got %v", err)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -29,7 +30,7 @@ func TestNetworkInspectContainerNotFound(t *testing.T) {
 | 
			
		|||
		client: newMockClient(errorMock(http.StatusNotFound, "Server error")),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	_, err := client.NetworkInspect(context.Background(), "unknown")
 | 
			
		||||
	_, err := client.NetworkInspect(context.Background(), "unknown", false)
 | 
			
		||||
	if err == nil || !IsErrNetworkNotFound(err) {
 | 
			
		||||
		t.Fatalf("expected a networkNotFound error, got %v", err)
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -46,9 +47,23 @@ func TestNetworkInspect(t *testing.T) {
 | 
			
		|||
				return nil, fmt.Errorf("expected GET method, got %s", req.Method)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			content, err := json.Marshal(types.NetworkResource{
 | 
			
		||||
				Name: "mynetwork",
 | 
			
		||||
			})
 | 
			
		||||
			var (
 | 
			
		||||
				content []byte
 | 
			
		||||
				err     error
 | 
			
		||||
			)
 | 
			
		||||
			if strings.HasPrefix(req.URL.RawQuery, "verbose=true") {
 | 
			
		||||
				s := map[string]network.ServiceInfo{
 | 
			
		||||
					"web": {},
 | 
			
		||||
				}
 | 
			
		||||
				content, err = json.Marshal(types.NetworkResource{
 | 
			
		||||
					Name:     "mynetwork",
 | 
			
		||||
					Services: s,
 | 
			
		||||
				})
 | 
			
		||||
			} else {
 | 
			
		||||
				content, err = json.Marshal(types.NetworkResource{
 | 
			
		||||
					Name: "mynetwork",
 | 
			
		||||
				})
 | 
			
		||||
			}
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
| 
						 | 
				
			
			@ -59,11 +74,23 @@ func TestNetworkInspect(t *testing.T) {
 | 
			
		|||
		}),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	r, err := client.NetworkInspect(context.Background(), "network_id")
 | 
			
		||||
	r, err := client.NetworkInspect(context.Background(), "network_id", false)
 | 
			
		||||
	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)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	if r.Name != "mynetwork" {
 | 
			
		||||
		t.Fatalf("expected `mynetwork`, got %s", r.Name)
 | 
			
		||||
	}
 | 
			
		||||
	_, ok := r.Services["web"]
 | 
			
		||||
	if !ok {
 | 
			
		||||
		t.Fatalf("expected service `web` missing in the verbose output")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,6 +17,7 @@ keywords: "API, Docker, rcli, REST, documentation"
 | 
			
		|||
 | 
			
		||||
[Docker Engine API v1.27](https://docs.docker.com/engine/api/v1.27/) documentation
 | 
			
		||||
 | 
			
		||||
* Optional query parameter `verbose` for `GET /networks/(id or name)` will now list all services with all the tasks, including the non-local tasks on the given network.
 | 
			
		||||
* `GET /containers/(id or name)/attach/ws` now returns WebSocket in binary frame format for API version >= v1.27, and returns WebSocket in text frame format for API version< v1.27, for the purpose of backward-compatibility.
 | 
			
		||||
* `GET /networks` is optimised only to return list of all networks and network specific information. List of all containers attached to a specific network is removed from this API and is only available using the network specific `GET /networks/{network-id}.
 | 
			
		||||
* `GET /containers/json` now supports `publish` and `expose` filters to filter containers that expose or publish certain ports.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,7 +48,7 @@ The `network inspect` command shows the containers, by id, in its
 | 
			
		|||
results. For networks backed by multi-host network driver, such as Overlay,
 | 
			
		||||
this command also shows the container endpoints in other hosts in the
 | 
			
		||||
cluster. These endpoints are represented as "ep-{endpoint-id}" in the output.
 | 
			
		||||
However, for swarm-scoped networks, only the endpoints that are local to the
 | 
			
		||||
However, for swarm mode networks, only the endpoints that are local to the
 | 
			
		||||
node are shown.
 | 
			
		||||
 | 
			
		||||
You can specify an alternate format to execute a given
 | 
			
		||||
| 
						 | 
				
			
			@ -201,6 +201,101 @@ $ docker network inspect ingress
 | 
			
		|||
]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Using `verbose` option for `network inspect`
 | 
			
		||||
 | 
			
		||||
`docker network inspect --verbose` for swarm mode overlay networks shows service-specific
 | 
			
		||||
details such as the service's VIP and port mappings. It also shows IPs of service tasks,
 | 
			
		||||
and the IPs of the nodes where the tasks are running.
 | 
			
		||||
 | 
			
		||||
Following is an example output for a overlay network `ov1` that has one service `s1`
 | 
			
		||||
attached to. service `s1` in this case has three replicas.
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
$ docker network inspect --verbose ov1
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "Name": "ov1",
 | 
			
		||||
        "Id": "ybmyjvao9vtzy3oorxbssj13b",
 | 
			
		||||
        "Created": "2017-03-13T17:04:39.776106792Z",
 | 
			
		||||
        "Scope": "swarm",
 | 
			
		||||
        "Driver": "overlay",
 | 
			
		||||
        "EnableIPv6": false,
 | 
			
		||||
        "IPAM": {
 | 
			
		||||
            "Driver": "default",
 | 
			
		||||
            "Options": null,
 | 
			
		||||
            "Config": [
 | 
			
		||||
                {
 | 
			
		||||
                    "Subnet": "10.0.0.0/24",
 | 
			
		||||
                    "Gateway": "10.0.0.1"
 | 
			
		||||
                }
 | 
			
		||||
            ]
 | 
			
		||||
        },
 | 
			
		||||
        "Internal": false,
 | 
			
		||||
        "Attachable": false,
 | 
			
		||||
        "Containers": {
 | 
			
		||||
            "020403bd88a15f60747fd25d1ad5fa1272eb740e8a97fc547d8ad07b2f721c5e": {
 | 
			
		||||
                "Name": "s1.1.pjn2ik0sfgkfzed3h0s00gs9o",
 | 
			
		||||
                "EndpointID": "ad16946f416562d658f3bb30b9830d73ad91ccf6feae44411269cd0ff674714e",
 | 
			
		||||
                "MacAddress": "02:42:0a:00:00:04",
 | 
			
		||||
                "IPv4Address": "10.0.0.4/24",
 | 
			
		||||
                "IPv6Address": ""
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "Options": {
 | 
			
		||||
            "com.docker.network.driver.overlay.vxlanid_list": "4097"
 | 
			
		||||
        },
 | 
			
		||||
        "Labels": {},
 | 
			
		||||
        "Peers": [
 | 
			
		||||
            {
 | 
			
		||||
                "Name": "net-3-5d3cfd30a58c",
 | 
			
		||||
                "IP": "192.168.33.13"
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "Name": "net-1-6ecbc0040a73",
 | 
			
		||||
                "IP": "192.168.33.11"
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "Name": "net-2-fb80208efd75",
 | 
			
		||||
                "IP": "192.168.33.12"
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "Services": {
 | 
			
		||||
            "s1": {
 | 
			
		||||
                "VIP": "10.0.0.2",
 | 
			
		||||
                "Ports": [],
 | 
			
		||||
                "LocalLBIndex": 257,
 | 
			
		||||
                "Tasks": [
 | 
			
		||||
                    {
 | 
			
		||||
                        "Name": "s1.2.q4hcq2aiiml25ubtrtg4q1txt",
 | 
			
		||||
                        "EndpointID": "040879b027e55fb658e8b60ae3b87c6cdac7d291e86a190a3b5ac6567b26511a",
 | 
			
		||||
                        "EndpointIP": "10.0.0.5",
 | 
			
		||||
                        "Info": {
 | 
			
		||||
                            "Host IP": "192.168.33.11"
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        "Name": "s1.3.yawl4cgkp7imkfx469kn9j6lm",
 | 
			
		||||
                        "EndpointID": "106edff9f120efe44068b834e1cddb5b39dd4a3af70211378b2f7a9e562bbad8",
 | 
			
		||||
                        "EndpointIP": "10.0.0.3",
 | 
			
		||||
                        "Info": {
 | 
			
		||||
                            "Host IP": "192.168.33.12"
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        "Name": "s1.1.pjn2ik0sfgkfzed3h0s00gs9o",
 | 
			
		||||
                        "EndpointID": "ad16946f416562d658f3bb30b9830d73ad91ccf6feae44411269cd0ff674714e",
 | 
			
		||||
                        "EndpointIP": "10.0.0.4",
 | 
			
		||||
                        "Info": {
 | 
			
		||||
                            "Host IP": "192.168.33.13"
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                ]
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Related commands
 | 
			
		||||
 | 
			
		||||
* [network disconnect ](network_disconnect.md)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -86,3 +86,96 @@ $ docker network inspect simple-network
 | 
			
		|||
    }
 | 
			
		||||
]
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
`docker network inspect --verbose` for swarm mode overlay networks shows service-specific
 | 
			
		||||
details such as the service's VIP and port mappings. It also shows IPs of service tasks,
 | 
			
		||||
and the IPs of the nodes where the tasks are running.
 | 
			
		||||
 | 
			
		||||
Following is an example output for a overlay network `ov1` that has one service `s1`
 | 
			
		||||
attached to. service `s1` in this case has three replicas.
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
$ docker network inspect --verbose ov1
 | 
			
		||||
[
 | 
			
		||||
    {
 | 
			
		||||
        "Name": "ov1",
 | 
			
		||||
        "Id": "ybmyjvao9vtzy3oorxbssj13b",
 | 
			
		||||
        "Created": "2017-03-13T17:04:39.776106792Z",
 | 
			
		||||
        "Scope": "swarm",
 | 
			
		||||
        "Driver": "overlay",
 | 
			
		||||
        "EnableIPv6": false,
 | 
			
		||||
        "IPAM": {
 | 
			
		||||
            "Driver": "default",
 | 
			
		||||
            "Options": null,
 | 
			
		||||
            "Config": [
 | 
			
		||||
                {
 | 
			
		||||
                    "Subnet": "10.0.0.0/24",
 | 
			
		||||
                    "Gateway": "10.0.0.1"
 | 
			
		||||
                }
 | 
			
		||||
            ]
 | 
			
		||||
        },
 | 
			
		||||
        "Internal": false,
 | 
			
		||||
        "Attachable": false,
 | 
			
		||||
        "Containers": {
 | 
			
		||||
            "020403bd88a15f60747fd25d1ad5fa1272eb740e8a97fc547d8ad07b2f721c5e": {
 | 
			
		||||
                "Name": "s1.1.pjn2ik0sfgkfzed3h0s00gs9o",
 | 
			
		||||
                "EndpointID": "ad16946f416562d658f3bb30b9830d73ad91ccf6feae44411269cd0ff674714e",
 | 
			
		||||
                "MacAddress": "02:42:0a:00:00:04",
 | 
			
		||||
                "IPv4Address": "10.0.0.4/24",
 | 
			
		||||
                "IPv6Address": ""
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        "Options": {
 | 
			
		||||
            "com.docker.network.driver.overlay.vxlanid_list": "4097"
 | 
			
		||||
        },
 | 
			
		||||
        "Labels": {},
 | 
			
		||||
        "Peers": [
 | 
			
		||||
            {
 | 
			
		||||
                "Name": "net-3-5d3cfd30a58c",
 | 
			
		||||
                "IP": "192.168.33.13"
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "Name": "net-1-6ecbc0040a73",
 | 
			
		||||
                "IP": "192.168.33.11"
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
                "Name": "net-2-fb80208efd75",
 | 
			
		||||
                "IP": "192.168.33.12"
 | 
			
		||||
            }
 | 
			
		||||
        ],
 | 
			
		||||
        "Services": {
 | 
			
		||||
            "s1": {
 | 
			
		||||
                "VIP": "10.0.0.2",
 | 
			
		||||
                "Ports": [],
 | 
			
		||||
                "LocalLBIndex": 257,
 | 
			
		||||
                "Tasks": [
 | 
			
		||||
                    {
 | 
			
		||||
                        "Name": "s1.2.q4hcq2aiiml25ubtrtg4q1txt",
 | 
			
		||||
                        "EndpointID": "040879b027e55fb658e8b60ae3b87c6cdac7d291e86a190a3b5ac6567b26511a",
 | 
			
		||||
                        "EndpointIP": "10.0.0.5",
 | 
			
		||||
                        "Info": {
 | 
			
		||||
                            "Host IP": "192.168.33.11"
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        "Name": "s1.3.yawl4cgkp7imkfx469kn9j6lm",
 | 
			
		||||
                        "EndpointID": "106edff9f120efe44068b834e1cddb5b39dd4a3af70211378b2f7a9e562bbad8",
 | 
			
		||||
                        "EndpointIP": "10.0.0.3",
 | 
			
		||||
                        "Info": {
 | 
			
		||||
                            "Host IP": "192.168.33.12"
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    {
 | 
			
		||||
                        "Name": "s1.1.pjn2ik0sfgkfzed3h0s00gs9o",
 | 
			
		||||
                        "EndpointID": "ad16946f416562d658f3bb30b9830d73ad91ccf6feae44411269cd0ff674714e",
 | 
			
		||||
                        "EndpointIP": "10.0.0.4",
 | 
			
		||||
                        "Info": {
 | 
			
		||||
                            "Host IP": "192.168.33.13"
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                ]
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
]
 | 
			
		||||
```
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue