зеркало из https://github.com/microsoft/docker.git
Merge pull request #31710 from sanimej/drillerrr
Add verbose flag to network inspect to show all services & tasks in swarm mode
This commit is contained in:
Коммит
cdf66ba715
|
@ -4,10 +4,12 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/errors"
|
||||||
"github.com/docker/docker/api/server/httputils"
|
"github.com/docker/docker/api/server/httputils"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
@ -65,7 +67,7 @@ SKIP:
|
||||||
// run across all the networks. Starting API version 1.27, this detailed
|
// run across all the networks. Starting API version 1.27, this detailed
|
||||||
// info is available for network specific GET API (equivalent to inspect)
|
// info is available for network specific GET API (equivalent to inspect)
|
||||||
if versions.LessThan(httputils.VersionFromContext(ctx), "1.27") {
|
if versions.LessThan(httputils.VersionFromContext(ctx), "1.27") {
|
||||||
nr = n.buildDetailedNetworkResources(nw)
|
nr = n.buildDetailedNetworkResources(nw, false)
|
||||||
} else {
|
} else {
|
||||||
nr = n.buildNetworkResource(nw)
|
nr = n.buildNetworkResource(nw)
|
||||||
}
|
}
|
||||||
|
@ -85,6 +87,16 @@ func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r
|
||||||
}
|
}
|
||||||
|
|
||||||
term := vars["id"]
|
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.
|
// In case multiple networks have duplicate names, return error.
|
||||||
// TODO (yongtang): should we wrap with version here for backward compatibility?
|
// 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()
|
nw := n.backend.GetNetworks()
|
||||||
for _, network := range nw {
|
for _, network := range nw {
|
||||||
if network.ID() == term {
|
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 {
|
if network.Name() == term {
|
||||||
// No need to check the ID collision here as we are still in
|
// No need to check the ID collision here as we are still in
|
||||||
// local scope and the network ID is unique in this scope.
|
// 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) {
|
if strings.HasPrefix(network.ID(), term) {
|
||||||
// No need to check the ID collision here as we are still in
|
// No need to check the ID collision here as we are still in
|
||||||
// local scope and the network ID is unique in this scope.
|
// 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
|
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 {
|
if nw == nil {
|
||||||
return &types.NetworkResource{}
|
return &types.NetworkResource{}
|
||||||
}
|
}
|
||||||
|
@ -315,6 +327,28 @@ func (n *networkRouter) buildDetailedNetworkResources(nw libnetwork.Network) *ty
|
||||||
|
|
||||||
r.Containers[key] = buildEndpointResource(tmpID, e.Name(), ei)
|
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
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6271,6 +6271,11 @@ paths:
|
||||||
description: "Network ID or name"
|
description: "Network ID or name"
|
||||||
required: true
|
required: true
|
||||||
type: "string"
|
type: "string"
|
||||||
|
- name: "verbose"
|
||||||
|
in: "query"
|
||||||
|
description: "Detailed inspect output for troubleshooting"
|
||||||
|
type: "boolean"
|
||||||
|
default: false
|
||||||
tags: ["Network"]
|
tags: ["Network"]
|
||||||
|
|
||||||
delete:
|
delete:
|
||||||
|
|
|
@ -60,6 +60,22 @@ type EndpointSettings struct {
|
||||||
MacAddress string
|
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`
|
// Copy makes a deep copy of `EndpointSettings`
|
||||||
func (es *EndpointSettings) Copy() *EndpointSettings {
|
func (es *EndpointSettings) Copy() *EndpointSettings {
|
||||||
epCopy := *es
|
epCopy := *es
|
||||||
|
|
|
@ -391,19 +391,20 @@ type MountPoint struct {
|
||||||
|
|
||||||
// NetworkResource is the body of the "get network" http response message
|
// NetworkResource is the body of the "get network" http response message
|
||||||
type NetworkResource struct {
|
type NetworkResource struct {
|
||||||
Name string // Name is the requested name of the network
|
Name string // Name is the requested name of the network
|
||||||
ID string `json:"Id"` // ID uniquely identifies a network on a single machine
|
ID string `json:"Id"` // ID uniquely identifies a network on a single machine
|
||||||
Created time.Time // Created is the time the network created
|
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)
|
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`)
|
Driver string // Driver is the Driver name used to create the network (e.g. `bridge`, `overlay`)
|
||||||
EnableIPv6 bool // EnableIPv6 represents whether to enable IPv6
|
EnableIPv6 bool // EnableIPv6 represents whether to enable IPv6
|
||||||
IPAM network.IPAM // IPAM is the network's IP Address Management
|
IPAM network.IPAM // IPAM is the network's IP Address Management
|
||||||
Internal bool // Internal represents if the network is used internal only
|
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.
|
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
|
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
|
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
|
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
|
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
|
// EndpointResource contains network resources allocated and used for a container in a network
|
||||||
|
|
|
@ -10,8 +10,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type inspectOptions struct {
|
type inspectOptions struct {
|
||||||
format string
|
format string
|
||||||
names []string
|
names []string
|
||||||
|
verbose bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newInspectCommand(dockerCli *command.DockerCli) *cobra.Command {
|
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().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
|
return cmd
|
||||||
}
|
}
|
||||||
|
@ -38,7 +40,7 @@ func runInspect(dockerCli *command.DockerCli, opts inspectOptions) error {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
getNetFunc := func(name string) (interface{}, []byte, error) {
|
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)
|
return inspect.Inspect(dockerCli.Out(), opts.names, opts.format, getNetFunc)
|
||||||
|
|
|
@ -140,7 +140,7 @@ func validateExternalNetworks(
|
||||||
client := dockerCli.Client()
|
client := dockerCli.Client()
|
||||||
|
|
||||||
for _, networkName := range externalNetworks {
|
for _, networkName := range externalNetworks {
|
||||||
network, err := client.NetworkInspect(ctx, networkName)
|
network, err := client.NetworkInspect(ctx, networkName, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if dockerclient.IsErrNetworkNotFound(err) {
|
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)
|
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 {
|
func inspectNetwork(ctx context.Context, dockerCli *command.DockerCli) inspect.GetRefFunc {
|
||||||
return func(ref string) (interface{}, []byte, error) {
|
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
|
NetworkConnect(ctx context.Context, networkID, container string, config *network.EndpointSettings) error
|
||||||
NetworkCreate(ctx context.Context, name string, options types.NetworkCreate) (types.NetworkCreateResponse, error)
|
NetworkCreate(ctx context.Context, name string, options types.NetworkCreate) (types.NetworkCreateResponse, error)
|
||||||
NetworkDisconnect(ctx context.Context, networkID, container string, force bool) error
|
NetworkDisconnect(ctx context.Context, networkID, container string, force bool) error
|
||||||
NetworkInspect(ctx context.Context, networkID string) (types.NetworkResource, error)
|
NetworkInspect(ctx context.Context, networkID string, verbose bool) (types.NetworkResource, error)
|
||||||
NetworkInspectWithRaw(ctx context.Context, networkID string) (types.NetworkResource, []byte, error)
|
NetworkInspectWithRaw(ctx context.Context, networkID string, verbose bool) (types.NetworkResource, []byte, error)
|
||||||
NetworkList(ctx context.Context, options types.NetworkListOptions) ([]types.NetworkResource, error)
|
NetworkList(ctx context.Context, options types.NetworkListOptions) ([]types.NetworkResource, error)
|
||||||
NetworkRemove(ctx context.Context, networkID string) error
|
NetworkRemove(ctx context.Context, networkID string) error
|
||||||
NetworksPrune(ctx context.Context, pruneFilter filters.Args) (types.NetworksPruneReport, error)
|
NetworksPrune(ctx context.Context, pruneFilter filters.Args) (types.NetworksPruneReport, error)
|
||||||
|
|
|
@ -5,21 +5,30 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NetworkInspect returns the information for a specific network configured in the docker host.
|
// 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) {
|
func (cli *Client) NetworkInspect(ctx context.Context, networkID string, verbose bool) (types.NetworkResource, error) {
|
||||||
networkResource, _, err := cli.NetworkInspectWithRaw(ctx, networkID)
|
networkResource, _, err := cli.NetworkInspectWithRaw(ctx, networkID, verbose)
|
||||||
return networkResource, err
|
return networkResource, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetworkInspectWithRaw returns the information for a specific network configured in the docker host and its raw representation.
|
// 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) {
|
func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string, verbose bool) (types.NetworkResource, []byte, error) {
|
||||||
var networkResource types.NetworkResource
|
var (
|
||||||
resp, err := cli.get(ctx, "/networks/"+networkID, nil, nil)
|
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 err != nil {
|
||||||
if resp.statusCode == http.StatusNotFound {
|
if resp.statusCode == http.StatusNotFound {
|
||||||
return networkResource, nil, networkNotFoundError{networkID}
|
return networkResource, nil, networkNotFoundError{networkID}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/api/types/network"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -18,7 +19,7 @@ func TestNetworkInspectError(t *testing.T) {
|
||||||
client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
|
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" {
|
if err == nil || err.Error() != "Error response from daemon: Server error" {
|
||||||
t.Fatalf("expected a Server Error, got %v", err)
|
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")),
|
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) {
|
if err == nil || !IsErrNetworkNotFound(err) {
|
||||||
t.Fatalf("expected a networkNotFound error, got %v", 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)
|
return nil, fmt.Errorf("expected GET method, got %s", req.Method)
|
||||||
}
|
}
|
||||||
|
|
||||||
content, err := json.Marshal(types.NetworkResource{
|
var (
|
||||||
Name: "mynetwork",
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if r.Name != "mynetwork" {
|
if r.Name != "mynetwork" {
|
||||||
t.Fatalf("expected `mynetwork`, got %s", r.Name)
|
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
|
[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 /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 /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.
|
* `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,
|
results. For networks backed by multi-host network driver, such as Overlay,
|
||||||
this command also shows the container endpoints in other hosts in the
|
this command also shows the container endpoints in other hosts in the
|
||||||
cluster. These endpoints are represented as "ep-{endpoint-id}" in the output.
|
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.
|
node are shown.
|
||||||
|
|
||||||
You can specify an alternate format to execute a given
|
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
|
## Related commands
|
||||||
|
|
||||||
* [network disconnect ](network_disconnect.md)
|
* [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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
|
@ -23,7 +23,7 @@ github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5
|
||||||
github.com/imdario/mergo 0.2.1
|
github.com/imdario/mergo 0.2.1
|
||||||
|
|
||||||
#get libnetwork packages
|
#get libnetwork packages
|
||||||
github.com/docker/libnetwork 1a019214c9cb80bd56219e5d6994a22caf302895
|
github.com/docker/libnetwork 4610dd67c7b9828bb4719d8aa2ac53a7f1f739d2
|
||||||
github.com/docker/go-events 18b43f1bc85d9cdd42c05a6cd2d444c7a200a894
|
github.com/docker/go-events 18b43f1bc85d9cdd42c05a6cd2d444c7a200a894
|
||||||
github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
|
github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
|
||||||
github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
|
github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
|
||||||
|
|
|
@ -44,6 +44,8 @@ type agent struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const libnetworkEPTable = "endpoint_table"
|
||||||
|
|
||||||
func getBindAddr(ifaceName string) (string, error) {
|
func getBindAddr(ifaceName string) (string, error) {
|
||||||
iface, err := net.InterfaceByName(ifaceName)
|
iface, err := net.InterfaceByName(ifaceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -285,7 +287,7 @@ func (c *controller) agentInit(listenAddr, bindAddrOrInterface, advertiseAddr st
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ch, cancel := nDB.Watch("endpoint_table", "", "")
|
ch, cancel := nDB.Watch(libnetworkEPTable, "", "")
|
||||||
nodeCh, cancel := nDB.Watch(networkdb.NodeTable, "", "")
|
nodeCh, cancel := nDB.Watch(networkdb.NodeTable, "", "")
|
||||||
|
|
||||||
c.Lock()
|
c.Lock()
|
||||||
|
@ -385,6 +387,111 @@ func (c *controller) agentClose() {
|
||||||
agent.networkDB.Close()
|
agent.networkDB.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Task has the backend container details
|
||||||
|
type Task struct {
|
||||||
|
Name string
|
||||||
|
EndpointID string
|
||||||
|
EndpointIP string
|
||||||
|
Info map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceInfo has service specific details along with the list of backend tasks
|
||||||
|
type ServiceInfo struct {
|
||||||
|
VIP string
|
||||||
|
LocalLBIndex int
|
||||||
|
Tasks []Task
|
||||||
|
Ports []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type epRecord struct {
|
||||||
|
ep EndpointRecord
|
||||||
|
info map[string]string
|
||||||
|
lbIndex int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *network) Services() map[string]ServiceInfo {
|
||||||
|
eps := make(map[string]epRecord)
|
||||||
|
|
||||||
|
if !n.isClusterEligible() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
agent := n.getController().getAgent()
|
||||||
|
if agent == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk through libnetworkEPTable and fetch the driver agnostic endpoint info
|
||||||
|
entries := agent.networkDB.GetTableByNetwork(libnetworkEPTable, n.id)
|
||||||
|
for eid, value := range entries {
|
||||||
|
var epRec EndpointRecord
|
||||||
|
nid := n.ID()
|
||||||
|
if err := proto.Unmarshal(value.([]byte), &epRec); err != nil {
|
||||||
|
logrus.Errorf("Unmarshal of libnetworkEPTable failed for endpoint %s in network %s, %v", eid, nid, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
i := n.getController().getLBIndex(epRec.ServiceID, nid, epRec.IngressPorts)
|
||||||
|
eps[eid] = epRecord{
|
||||||
|
ep: epRec,
|
||||||
|
lbIndex: i,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walk through the driver's tables, have the driver decode the entries
|
||||||
|
// and return the tuple {ep ID, value}. value is a string that coveys
|
||||||
|
// relevant info about the endpoint.
|
||||||
|
d, err := n.driver(true)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("Could not resolve driver for network %s/%s while fetching services: %v", n.networkType, n.ID(), err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, table := range n.driverTables {
|
||||||
|
if table.objType != driverapi.EndpointObject {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
entries := agent.networkDB.GetTableByNetwork(table.name, n.id)
|
||||||
|
for key, value := range entries {
|
||||||
|
epID, info := d.DecodeTableEntry(table.name, key, value.([]byte))
|
||||||
|
if ep, ok := eps[epID]; !ok {
|
||||||
|
logrus.Errorf("Inconsistent driver and libnetwork state for endpoint %s", epID)
|
||||||
|
} else {
|
||||||
|
ep.info = info
|
||||||
|
eps[epID] = ep
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// group the endpoints into a map keyed by the service name
|
||||||
|
sinfo := make(map[string]ServiceInfo)
|
||||||
|
for ep, epr := range eps {
|
||||||
|
var (
|
||||||
|
s ServiceInfo
|
||||||
|
ok bool
|
||||||
|
)
|
||||||
|
if s, ok = sinfo[epr.ep.ServiceName]; !ok {
|
||||||
|
s = ServiceInfo{
|
||||||
|
VIP: epr.ep.VirtualIP,
|
||||||
|
LocalLBIndex: epr.lbIndex,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ports := []string{}
|
||||||
|
if s.Ports == nil {
|
||||||
|
for _, port := range epr.ep.IngressPorts {
|
||||||
|
p := fmt.Sprintf("Target: %d, Publish: %d", port.TargetPort, port.PublishedPort)
|
||||||
|
ports = append(ports, p)
|
||||||
|
}
|
||||||
|
s.Ports = ports
|
||||||
|
}
|
||||||
|
s.Tasks = append(s.Tasks, Task{
|
||||||
|
Name: epr.ep.Name,
|
||||||
|
EndpointID: ep,
|
||||||
|
EndpointIP: epr.ep.EndpointIP,
|
||||||
|
Info: epr.info,
|
||||||
|
})
|
||||||
|
sinfo[epr.ep.ServiceName] = s
|
||||||
|
}
|
||||||
|
return sinfo
|
||||||
|
}
|
||||||
|
|
||||||
func (n *network) isClusterEligible() bool {
|
func (n *network) isClusterEligible() bool {
|
||||||
if n.driverScope() != datastore.GlobalScope {
|
if n.driverScope() != datastore.GlobalScope {
|
||||||
return false
|
return false
|
||||||
|
@ -508,7 +615,7 @@ func (ep *endpoint) addServiceInfoToCluster() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if agent != nil {
|
if agent != nil {
|
||||||
if err := agent.networkDB.CreateEntry("endpoint_table", n.ID(), ep.ID(), buf); err != nil {
|
if err := agent.networkDB.CreateEntry(libnetworkEPTable, n.ID(), ep.ID(), buf); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -541,7 +648,7 @@ func (ep *endpoint) deleteServiceInfoFromCluster() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if agent != nil {
|
if agent != nil {
|
||||||
if err := agent.networkDB.DeleteEntry("endpoint_table", n.ID(), ep.ID()); err != nil {
|
if err := agent.networkDB.DeleteEntry(libnetworkEPTable, n.ID(), ep.ID()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -559,8 +666,8 @@ func (n *network) addDriverWatches() {
|
||||||
if agent == nil {
|
if agent == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, tableName := range n.driverTables {
|
for _, table := range n.driverTables {
|
||||||
ch, cancel := agent.networkDB.Watch(tableName, n.ID(), "")
|
ch, cancel := agent.networkDB.Watch(table.name, n.ID(), "")
|
||||||
agent.Lock()
|
agent.Lock()
|
||||||
agent.driverCancelFuncs[n.ID()] = append(agent.driverCancelFuncs[n.ID()], cancel)
|
agent.driverCancelFuncs[n.ID()] = append(agent.driverCancelFuncs[n.ID()], cancel)
|
||||||
agent.Unlock()
|
agent.Unlock()
|
||||||
|
@ -571,9 +678,9 @@ func (n *network) addDriverWatches() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
agent.networkDB.WalkTable(tableName, func(nid, key string, value []byte) bool {
|
agent.networkDB.WalkTable(table.name, func(nid, key string, value []byte) bool {
|
||||||
if nid == n.ID() {
|
if nid == n.ID() {
|
||||||
d.EventNotify(driverapi.Create, nid, tableName, key, value)
|
d.EventNotify(driverapi.Create, nid, table.name, key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -72,6 +72,16 @@ type Driver interface {
|
||||||
// only invoked for the global scope driver.
|
// only invoked for the global scope driver.
|
||||||
EventNotify(event EventType, nid string, tableName string, key string, value []byte)
|
EventNotify(event EventType, nid string, tableName string, key string, value []byte)
|
||||||
|
|
||||||
|
// DecodeTableEntry passes the driver a key, value pair from table it registered
|
||||||
|
// with libnetwork. Driver should return {object ID, map[string]string} tuple.
|
||||||
|
// If DecodeTableEntry is called for a table associated with NetworkObject or
|
||||||
|
// EndpointObject the return object ID should be the network id or endppoint id
|
||||||
|
// associated with that entry. map should have information about the object that
|
||||||
|
// can be presented to the user.
|
||||||
|
// For exampe: overlay driver returns the VTEP IP of the host that has the endpoint
|
||||||
|
// which is shown in 'network inspect --verbose'
|
||||||
|
DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string)
|
||||||
|
|
||||||
// Type returns the type of this driver, the network type this driver manages
|
// Type returns the type of this driver, the network type this driver manages
|
||||||
Type() string
|
Type() string
|
||||||
|
|
||||||
|
@ -84,7 +94,7 @@ type Driver interface {
|
||||||
type NetworkInfo interface {
|
type NetworkInfo interface {
|
||||||
// TableEventRegister registers driver interest in a given
|
// TableEventRegister registers driver interest in a given
|
||||||
// table name.
|
// table name.
|
||||||
TableEventRegister(tableName string) error
|
TableEventRegister(tableName string, objType ObjectType) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// InterfaceInfo provides a go interface for drivers to retrive
|
// InterfaceInfo provides a go interface for drivers to retrive
|
||||||
|
@ -175,3 +185,28 @@ const (
|
||||||
// Delete event is generated when a table entry is deleted.
|
// Delete event is generated when a table entry is deleted.
|
||||||
Delete
|
Delete
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ObjectType represents the type of object driver wants to store in libnetwork's networkDB
|
||||||
|
type ObjectType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// EndpointObject should be set for libnetwork endpoint object related data
|
||||||
|
EndpointObject ObjectType = 1 + iota
|
||||||
|
// NetworkObject should be set for libnetwork network object related data
|
||||||
|
NetworkObject
|
||||||
|
// OpaqueObject is for driver specific data with no corresponding libnetwork object
|
||||||
|
OpaqueObject
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsValidType validates the passed in type against the valid object types
|
||||||
|
func IsValidType(objType ObjectType) bool {
|
||||||
|
switch objType {
|
||||||
|
case EndpointObject:
|
||||||
|
fallthrough
|
||||||
|
case NetworkObject:
|
||||||
|
fallthrough
|
||||||
|
case OpaqueObject:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
@ -575,6 +575,10 @@ func (d *driver) NetworkFree(id string) error {
|
||||||
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
|
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
// Create a new network using bridge plugin
|
// Create a new network using bridge plugin
|
||||||
func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
|
func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
|
||||||
if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" {
|
if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" {
|
||||||
|
|
6
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go
сгенерированный
поставляемый
6
vendor/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go
сгенерированный
поставляемый
|
@ -140,7 +140,6 @@ func setupIPTablesInternal(bridgeIface string, addr net.Addr, icc, ipmasq, hairp
|
||||||
hpNatRule = iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: []string{"-m", "addrtype", "--src-type", "LOCAL", "-o", bridgeIface, "-j", "MASQUERADE"}}
|
hpNatRule = iptRule{table: iptables.Nat, chain: "POSTROUTING", preArgs: []string{"-t", "nat"}, args: []string{"-m", "addrtype", "--src-type", "LOCAL", "-o", bridgeIface, "-j", "MASQUERADE"}}
|
||||||
skipDNAT = iptRule{table: iptables.Nat, chain: DockerChain, preArgs: []string{"-t", "nat"}, args: []string{"-i", bridgeIface, "-j", "RETURN"}}
|
skipDNAT = iptRule{table: iptables.Nat, chain: DockerChain, preArgs: []string{"-t", "nat"}, args: []string{"-i", bridgeIface, "-j", "RETURN"}}
|
||||||
outRule = iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", bridgeIface, "!", "-o", bridgeIface, "-j", "ACCEPT"}}
|
outRule = iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-i", bridgeIface, "!", "-o", bridgeIface, "-j", "ACCEPT"}}
|
||||||
inRule = iptRule{table: iptables.Filter, chain: "FORWARD", args: []string{"-o", bridgeIface, "-m", "conntrack", "--ctstate", "RELATED,ESTABLISHED", "-j", "ACCEPT"}}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Set NAT.
|
// Set NAT.
|
||||||
|
@ -173,11 +172,6 @@ func setupIPTablesInternal(bridgeIface string, addr net.Addr, icc, ipmasq, hairp
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set Accept on incoming packets for existing connections.
|
|
||||||
if err := programChainRule(inRule, "ACCEPT INCOMING", enable); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,10 @@ func (d *driver) NetworkFree(id string) error {
|
||||||
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
|
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
|
func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
|
||||||
d.Lock()
|
d.Lock()
|
||||||
defer d.Unlock()
|
defer d.Unlock()
|
||||||
|
|
|
@ -108,3 +108,7 @@ func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{
|
||||||
|
|
||||||
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
|
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
|
@ -110,3 +110,7 @@ func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{
|
||||||
|
|
||||||
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
|
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
|
@ -35,6 +35,10 @@ func (d *driver) NetworkFree(id string) error {
|
||||||
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
|
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
|
func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
|
||||||
d.Lock()
|
d.Lock()
|
||||||
defer d.Unlock()
|
defer d.Unlock()
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
mark = uint32(0xD0C4E3)
|
r = 0xD0C4E3
|
||||||
timeout = 30
|
timeout = 30
|
||||||
pktExpansion = 26 // SPI(4) + SeqN(4) + IV(8) + PadLength(1) + NextHeader(1) + ICV(8)
|
pktExpansion = 26 // SPI(4) + SeqN(4) + IV(8) + PadLength(1) + NextHeader(1) + ICV(8)
|
||||||
)
|
)
|
||||||
|
@ -31,6 +31,8 @@ const (
|
||||||
bidir
|
bidir
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var spMark = netlink.XfrmMark{Value: uint32(r), Mask: 0xffffffff}
|
||||||
|
|
||||||
type key struct {
|
type key struct {
|
||||||
value []byte
|
value []byte
|
||||||
tag uint32
|
tag uint32
|
||||||
|
@ -201,7 +203,7 @@ func programMangle(vni uint32, add bool) (err error) {
|
||||||
var (
|
var (
|
||||||
p = strconv.FormatUint(uint64(vxlanPort), 10)
|
p = strconv.FormatUint(uint64(vxlanPort), 10)
|
||||||
c = fmt.Sprintf("0>>22&0x3C@12&0xFFFFFF00=%d", int(vni)<<8)
|
c = fmt.Sprintf("0>>22&0x3C@12&0xFFFFFF00=%d", int(vni)<<8)
|
||||||
m = strconv.FormatUint(uint64(mark), 10)
|
m = strconv.FormatUint(uint64(r), 10)
|
||||||
chain = "OUTPUT"
|
chain = "OUTPUT"
|
||||||
rule = []string{"-p", "udp", "--dport", p, "-m", "u32", "--u32", c, "-j", "MARK", "--set-mark", m}
|
rule = []string{"-p", "udp", "--dport", p, "-m", "u32", "--u32", c, "-j", "MARK", "--set-mark", m}
|
||||||
a = "-A"
|
a = "-A"
|
||||||
|
@ -271,6 +273,7 @@ func programSA(localIP, remoteIP net.IP, spi *spi, k *key, dir int, add bool) (f
|
||||||
Proto: netlink.XFRM_PROTO_ESP,
|
Proto: netlink.XFRM_PROTO_ESP,
|
||||||
Spi: spi.reverse,
|
Spi: spi.reverse,
|
||||||
Mode: netlink.XFRM_MODE_TRANSPORT,
|
Mode: netlink.XFRM_MODE_TRANSPORT,
|
||||||
|
Reqid: r,
|
||||||
}
|
}
|
||||||
if add {
|
if add {
|
||||||
rSA.Aead = buildAeadAlgo(k, spi.reverse)
|
rSA.Aead = buildAeadAlgo(k, spi.reverse)
|
||||||
|
@ -296,6 +299,7 @@ func programSA(localIP, remoteIP net.IP, spi *spi, k *key, dir int, add bool) (f
|
||||||
Proto: netlink.XFRM_PROTO_ESP,
|
Proto: netlink.XFRM_PROTO_ESP,
|
||||||
Spi: spi.forward,
|
Spi: spi.forward,
|
||||||
Mode: netlink.XFRM_MODE_TRANSPORT,
|
Mode: netlink.XFRM_MODE_TRANSPORT,
|
||||||
|
Reqid: r,
|
||||||
}
|
}
|
||||||
if add {
|
if add {
|
||||||
fSA.Aead = buildAeadAlgo(k, spi.forward)
|
fSA.Aead = buildAeadAlgo(k, spi.forward)
|
||||||
|
@ -325,17 +329,18 @@ func programSP(fSA *netlink.XfrmState, rSA *netlink.XfrmState, add bool) error {
|
||||||
xfrmProgram = ns.NlHandle().XfrmPolicyAdd
|
xfrmProgram = ns.NlHandle().XfrmPolicyAdd
|
||||||
}
|
}
|
||||||
|
|
||||||
fullMask := net.CIDRMask(8*len(fSA.Src), 8*len(fSA.Src))
|
// Create a congruent cidr
|
||||||
|
s := types.GetMinimalIP(fSA.Src)
|
||||||
|
d := types.GetMinimalIP(fSA.Dst)
|
||||||
|
fullMask := net.CIDRMask(8*len(s), 8*len(s))
|
||||||
|
|
||||||
fPol := &netlink.XfrmPolicy{
|
fPol := &netlink.XfrmPolicy{
|
||||||
Src: &net.IPNet{IP: fSA.Src, Mask: fullMask},
|
Src: &net.IPNet{IP: s, Mask: fullMask},
|
||||||
Dst: &net.IPNet{IP: fSA.Dst, Mask: fullMask},
|
Dst: &net.IPNet{IP: d, Mask: fullMask},
|
||||||
Dir: netlink.XFRM_DIR_OUT,
|
Dir: netlink.XFRM_DIR_OUT,
|
||||||
Proto: 17,
|
Proto: 17,
|
||||||
DstPort: 4789,
|
DstPort: 4789,
|
||||||
Mark: &netlink.XfrmMark{
|
Mark: &spMark,
|
||||||
Value: mark,
|
|
||||||
},
|
|
||||||
Tmpls: []netlink.XfrmPolicyTmpl{
|
Tmpls: []netlink.XfrmPolicyTmpl{
|
||||||
{
|
{
|
||||||
Src: fSA.Src,
|
Src: fSA.Src,
|
||||||
|
@ -343,6 +348,7 @@ func programSP(fSA *netlink.XfrmState, rSA *netlink.XfrmState, add bool) error {
|
||||||
Proto: netlink.XFRM_PROTO_ESP,
|
Proto: netlink.XFRM_PROTO_ESP,
|
||||||
Mode: netlink.XFRM_MODE_TRANSPORT,
|
Mode: netlink.XFRM_MODE_TRANSPORT,
|
||||||
Spi: fSA.Spi,
|
Spi: fSA.Spi,
|
||||||
|
Reqid: r,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -426,6 +432,8 @@ func (d *driver) secMapWalk(f func(string, []*spi) ([]*spi, bool)) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *driver) setKeys(keys []*key) error {
|
func (d *driver) setKeys(keys []*key) error {
|
||||||
|
// Remove any stale policy, state
|
||||||
|
clearEncryptionStates()
|
||||||
// Accept the encryption keys and clear any stale encryption map
|
// Accept the encryption keys and clear any stale encryption map
|
||||||
d.Lock()
|
d.Lock()
|
||||||
d.keys = keys
|
d.keys = keys
|
||||||
|
@ -526,7 +534,7 @@ func updateNodeKey(lIP, aIP, rIP net.IP, idxs []*spi, curKeys []*key, newIdx, pr
|
||||||
}
|
}
|
||||||
|
|
||||||
if newIdx > -1 {
|
if newIdx > -1 {
|
||||||
// +RSA2
|
// +rSA2
|
||||||
programSA(lIP, rIP, spis[newIdx], curKeys[newIdx], reverse, true)
|
programSA(lIP, rIP, spis[newIdx], curKeys[newIdx], reverse, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -535,16 +543,17 @@ func updateNodeKey(lIP, aIP, rIP net.IP, idxs []*spi, curKeys []*key, newIdx, pr
|
||||||
fSA2, _, _ := programSA(lIP, rIP, spis[priIdx], curKeys[priIdx], forward, true)
|
fSA2, _, _ := programSA(lIP, rIP, spis[priIdx], curKeys[priIdx], forward, true)
|
||||||
|
|
||||||
// +fSP2, -fSP1
|
// +fSP2, -fSP1
|
||||||
fullMask := net.CIDRMask(8*len(fSA2.Src), 8*len(fSA2.Src))
|
s := types.GetMinimalIP(fSA2.Src)
|
||||||
|
d := types.GetMinimalIP(fSA2.Dst)
|
||||||
|
fullMask := net.CIDRMask(8*len(s), 8*len(s))
|
||||||
|
|
||||||
fSP1 := &netlink.XfrmPolicy{
|
fSP1 := &netlink.XfrmPolicy{
|
||||||
Src: &net.IPNet{IP: fSA2.Src, Mask: fullMask},
|
Src: &net.IPNet{IP: s, Mask: fullMask},
|
||||||
Dst: &net.IPNet{IP: fSA2.Dst, Mask: fullMask},
|
Dst: &net.IPNet{IP: d, Mask: fullMask},
|
||||||
Dir: netlink.XFRM_DIR_OUT,
|
Dir: netlink.XFRM_DIR_OUT,
|
||||||
Proto: 17,
|
Proto: 17,
|
||||||
DstPort: 4789,
|
DstPort: 4789,
|
||||||
Mark: &netlink.XfrmMark{
|
Mark: &spMark,
|
||||||
Value: mark,
|
|
||||||
},
|
|
||||||
Tmpls: []netlink.XfrmPolicyTmpl{
|
Tmpls: []netlink.XfrmPolicyTmpl{
|
||||||
{
|
{
|
||||||
Src: fSA2.Src,
|
Src: fSA2.Src,
|
||||||
|
@ -552,6 +561,7 @@ func updateNodeKey(lIP, aIP, rIP net.IP, idxs []*spi, curKeys []*key, newIdx, pr
|
||||||
Proto: netlink.XFRM_PROTO_ESP,
|
Proto: netlink.XFRM_PROTO_ESP,
|
||||||
Mode: netlink.XFRM_MODE_TRANSPORT,
|
Mode: netlink.XFRM_MODE_TRANSPORT,
|
||||||
Spi: fSA2.Spi,
|
Spi: fSA2.Spi,
|
||||||
|
Reqid: r,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -597,3 +607,33 @@ func (n *network) maxMTU() int {
|
||||||
}
|
}
|
||||||
return mtu
|
return mtu
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func clearEncryptionStates() {
|
||||||
|
nlh := ns.NlHandle()
|
||||||
|
spList, err := nlh.XfrmPolicyList(netlink.FAMILY_ALL)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnf("Failed to retrieve SP list for cleanup: %v", err)
|
||||||
|
}
|
||||||
|
saList, err := nlh.XfrmStateList(netlink.FAMILY_ALL)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnf("Failed to retrieve SA list for cleanup: %v", err)
|
||||||
|
}
|
||||||
|
for _, sp := range spList {
|
||||||
|
if sp.Mark != nil && sp.Mark.Value == spMark.Value {
|
||||||
|
if err := nlh.XfrmPolicyDel(&sp); err != nil {
|
||||||
|
logrus.Warnf("Failed to delete stale SP %s: %v", sp, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
logrus.Debugf("Removed stale SP: %s", sp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, sa := range saList {
|
||||||
|
if sa.Reqid == r {
|
||||||
|
if err := nlh.XfrmStateDel(&sa); err != nil {
|
||||||
|
logrus.Warnf("Failed to delete stale SA %s: %v", sa, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
logrus.Debugf("Removed stale SA: %s", sa)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -145,6 +145,23 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
|
||||||
|
if tablename != ovPeerTable {
|
||||||
|
logrus.Errorf("DecodeTableEntry: unexpected table name %s", tablename)
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var peer PeerRecord
|
||||||
|
if err := proto.Unmarshal(value, &peer); err != nil {
|
||||||
|
logrus.Errorf("DecodeTableEntry: failed to unmarshal peer record for key %s: %v", key, err)
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return key, map[string]string{
|
||||||
|
"Host IP": peer.TunnelEndpointIP,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
|
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
|
||||||
if tableName != ovPeerTable {
|
if tableName != ovPeerTable {
|
||||||
logrus.Errorf("Unexpected table notification for table %s received", tableName)
|
logrus.Errorf("Unexpected table notification for table %s received", tableName)
|
||||||
|
|
|
@ -159,7 +159,7 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d
|
||||||
}
|
}
|
||||||
|
|
||||||
if nInfo != nil {
|
if nInfo != nil {
|
||||||
if err := nInfo.TableEventRegister(ovPeerTable); err != nil {
|
if err := nInfo.TableEventRegister(ovPeerTable, driverapi.EndpointObject); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
4
vendor/github.com/docker/libnetwork/drivers/overlay/ovmanager/ovmanager.go
сгенерированный
поставляемый
4
vendor/github.com/docker/libnetwork/drivers/overlay/ovmanager/ovmanager.go
сгенерированный
поставляемый
|
@ -199,6 +199,10 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d
|
||||||
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
|
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *driver) DeleteNetwork(nid string) error {
|
func (d *driver) DeleteNetwork(nid string) error {
|
||||||
return types.NotImplementedErrorf("not implemented")
|
return types.NotImplementedErrorf("not implemented")
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,6 +116,10 @@ func (d *driver) NetworkFree(id string) error {
|
||||||
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
|
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *driver) CreateNetwork(id string, options map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
|
func (d *driver) CreateNetwork(id string, options map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
|
||||||
create := &api.CreateNetworkRequest{
|
create := &api.CreateNetworkRequest{
|
||||||
NetworkID: id,
|
NetworkID: id,
|
||||||
|
|
|
@ -175,6 +175,10 @@ func (d *driver) NetworkFree(id string) error {
|
||||||
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
|
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
|
func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
|
||||||
if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" {
|
if len(ipV4Data) == 0 || ipV4Data[0].Pool.String() == "0.0.0.0/0" {
|
||||||
return types.BadRequestErrorf("ipv4 pool is empty")
|
return types.BadRequestErrorf("ipv4 pool is empty")
|
||||||
|
|
4
vendor/github.com/docker/libnetwork/drivers/solaris/overlay/joinleave.go
сгенерированный
поставляемый
4
vendor/github.com/docker/libnetwork/drivers/solaris/overlay/joinleave.go
сгенерированный
поставляемый
|
@ -149,6 +149,10 @@ func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key stri
|
||||||
d.peerAdd(nid, eid, addr.IP, addr.Mask, mac, vtep, true)
|
d.peerAdd(nid, eid, addr.IP, addr.Mask, mac, vtep, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||||
func (d *driver) Leave(nid, eid string) error {
|
func (d *driver) Leave(nid, eid string) error {
|
||||||
if err := validateID(nid, eid); err != nil {
|
if err := validateID(nid, eid); err != nil {
|
||||||
|
|
2
vendor/github.com/docker/libnetwork/drivers/solaris/overlay/ov_network.go
сгенерированный
поставляемый
2
vendor/github.com/docker/libnetwork/drivers/solaris/overlay/ov_network.go
сгенерированный
поставляемый
|
@ -153,7 +153,7 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d
|
||||||
}
|
}
|
||||||
|
|
||||||
if nInfo != nil {
|
if nInfo != nil {
|
||||||
if err := nInfo.TableEventRegister(ovPeerTable); err != nil {
|
if err := nInfo.TableEventRegister(ovPeerTable, driverapi.EndpointObject); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
4
vendor/github.com/docker/libnetwork/drivers/windows/overlay/joinleave_windows.go
сгенерированный
поставляемый
4
vendor/github.com/docker/libnetwork/drivers/windows/overlay/joinleave_windows.go
сгенерированный
поставляемый
|
@ -93,6 +93,10 @@ func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key stri
|
||||||
d.peerAdd(nid, eid, addr.IP, addr.Mask, mac, vtep, true)
|
d.peerAdd(nid, eid, addr.IP, addr.Mask, mac, vtep, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||||
func (d *driver) Leave(nid, eid string) error {
|
func (d *driver) Leave(nid, eid string) error {
|
||||||
if err := validateID(nid, eid); err != nil {
|
if err := validateID(nid, eid); err != nil {
|
||||||
|
|
2
vendor/github.com/docker/libnetwork/drivers/windows/overlay/ov_network_windows.go
сгенерированный
поставляемый
2
vendor/github.com/docker/libnetwork/drivers/windows/overlay/ov_network_windows.go
сгенерированный
поставляемый
|
@ -169,7 +169,7 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo d
|
||||||
n.interfaceName = interfaceName
|
n.interfaceName = interfaceName
|
||||||
|
|
||||||
if nInfo != nil {
|
if nInfo != nil {
|
||||||
if err := nInfo.TableEventRegister(ovPeerTable); err != nil {
|
if err := nInfo.TableEventRegister(ovPeerTable, driverapi.EndpointObject); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,6 +183,10 @@ func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []d
|
||||||
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
|
func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
// Create a new network
|
// Create a new network
|
||||||
func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
|
func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
|
||||||
if _, err := d.getNetwork(id); err == nil {
|
if _, err := d.getNetwork(id); err == nil {
|
||||||
|
|
|
@ -50,8 +50,7 @@ var (
|
||||||
bestEffortLock sync.Mutex
|
bestEffortLock sync.Mutex
|
||||||
// ErrIptablesNotFound is returned when the rule is not found.
|
// ErrIptablesNotFound is returned when the rule is not found.
|
||||||
ErrIptablesNotFound = errors.New("Iptables not found")
|
ErrIptablesNotFound = errors.New("Iptables not found")
|
||||||
probeOnce sync.Once
|
initOnce sync.Once
|
||||||
firewalldOnce sync.Once
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ChainInfo defines the iptables chain.
|
// ChainInfo defines the iptables chain.
|
||||||
|
@ -86,22 +85,32 @@ func initFirewalld() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func detectIptables() {
|
||||||
|
path, err := exec.LookPath("iptables")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
iptablesPath = path
|
||||||
|
supportsXlock = exec.Command(iptablesPath, "--wait", "-L", "-n").Run() == nil
|
||||||
|
mj, mn, mc, err := GetVersion()
|
||||||
|
if err != nil {
|
||||||
|
logrus.Warnf("Failed to read iptables version: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
supportsCOpt = supportsCOption(mj, mn, mc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func initIptables() {
|
||||||
|
probe()
|
||||||
|
initFirewalld()
|
||||||
|
detectIptables()
|
||||||
|
}
|
||||||
|
|
||||||
func initCheck() error {
|
func initCheck() error {
|
||||||
|
initOnce.Do(initIptables)
|
||||||
|
|
||||||
if iptablesPath == "" {
|
if iptablesPath == "" {
|
||||||
probeOnce.Do(probe)
|
return ErrIptablesNotFound
|
||||||
firewalldOnce.Do(initFirewalld)
|
|
||||||
path, err := exec.LookPath("iptables")
|
|
||||||
if err != nil {
|
|
||||||
return ErrIptablesNotFound
|
|
||||||
}
|
|
||||||
iptablesPath = path
|
|
||||||
supportsXlock = exec.Command(iptablesPath, "--wait", "-L", "-n").Run() == nil
|
|
||||||
mj, mn, mc, err := GetVersion()
|
|
||||||
if err != nil {
|
|
||||||
logrus.Warnf("Failed to read iptables version: %v", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
supportsCOpt = supportsCOption(mj, mn, mc)
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -189,6 +198,26 @@ func ProgramChain(c *ChainInfo, bridgeName string, hairpinMode, enable bool) err
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
establish := []string{
|
||||||
|
"-o", bridgeName,
|
||||||
|
"-m", "conntrack",
|
||||||
|
"--ctstate", "RELATED,ESTABLISHED",
|
||||||
|
"-j", "ACCEPT"}
|
||||||
|
if !Exists(Filter, "FORWARD", establish...) && enable {
|
||||||
|
insert := append([]string{string(Insert), "FORWARD"}, establish...)
|
||||||
|
if output, err := Raw(insert...); err != nil {
|
||||||
|
return err
|
||||||
|
} else if len(output) != 0 {
|
||||||
|
return fmt.Errorf("Could not create establish rule to %s: %s", c.Table, output)
|
||||||
|
}
|
||||||
|
} else if Exists(Filter, "FORWARD", establish...) && !enable {
|
||||||
|
del := append([]string{string(Delete), "FORWARD"}, establish...)
|
||||||
|
if output, err := Raw(del...); err != nil {
|
||||||
|
return err
|
||||||
|
} else if len(output) != 0 {
|
||||||
|
return fmt.Errorf("Could not delete establish rule from %s: %s", c.Table, output)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -353,7 +382,11 @@ func exists(native bool, table Table, chain string, rule ...string) bool {
|
||||||
table = Filter
|
table = Filter
|
||||||
}
|
}
|
||||||
|
|
||||||
initCheck()
|
if err := initCheck(); err != nil {
|
||||||
|
// The exists() signature does not allow us to return an error, but at least
|
||||||
|
// we can skip the (likely invalid) exec invocation.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
if supportsCOpt {
|
if supportsCOpt {
|
||||||
// if exit status is 0 then return true, the rule exists
|
// if exit status is 0 then return true, the rule exists
|
||||||
|
@ -436,9 +469,9 @@ func ExistChain(chain string, table Table) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetVersion reads the iptables version numbers
|
// GetVersion reads the iptables version numbers during initialization
|
||||||
func GetVersion() (major, minor, micro int, err error) {
|
func GetVersion() (major, minor, micro int, err error) {
|
||||||
out, err := Raw("--version")
|
out, err := exec.Command(iptablesPath, "--version").CombinedOutput()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
major, minor, micro = parseVersionNumbers(string(out))
|
major, minor, micro = parseVersionNumbers(string(out))
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,9 @@ type NetworkInfo interface {
|
||||||
// gossip cluster. For non-dynamic overlay networks and bridge networks it returns an
|
// gossip cluster. For non-dynamic overlay networks and bridge networks it returns an
|
||||||
// empty slice
|
// empty slice
|
||||||
Peers() []networkdb.PeerInfo
|
Peers() []networkdb.PeerInfo
|
||||||
|
//Services returns a map of services keyed by the service name with the details
|
||||||
|
//of all the tasks that belong to the service. Applicable only in swarm mode.
|
||||||
|
Services() map[string]ServiceInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// EndpointWalker is a client provided function which will be used to walk the Endpoints.
|
// EndpointWalker is a client provided function which will be used to walk the Endpoints.
|
||||||
|
@ -108,6 +111,11 @@ type servicePorts struct {
|
||||||
target []serviceTarget
|
target []serviceTarget
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type networkDBTable struct {
|
||||||
|
name string
|
||||||
|
objType driverapi.ObjectType
|
||||||
|
}
|
||||||
|
|
||||||
// IpamConf contains all the ipam related configurations for a network
|
// IpamConf contains all the ipam related configurations for a network
|
||||||
type IpamConf struct {
|
type IpamConf struct {
|
||||||
// The master address pool for containers and network interfaces
|
// The master address pool for containers and network interfaces
|
||||||
|
@ -208,7 +216,7 @@ type network struct {
|
||||||
attachable bool
|
attachable bool
|
||||||
inDelete bool
|
inDelete bool
|
||||||
ingress bool
|
ingress bool
|
||||||
driverTables []string
|
driverTables []networkDBTable
|
||||||
dynamic bool
|
dynamic bool
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
@ -1607,11 +1615,18 @@ func (n *network) Labels() map[string]string {
|
||||||
return lbls
|
return lbls
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *network) TableEventRegister(tableName string) error {
|
func (n *network) TableEventRegister(tableName string, objType driverapi.ObjectType) error {
|
||||||
|
if !driverapi.IsValidType(objType) {
|
||||||
|
return fmt.Errorf("invalid object type %v in registering table, %s", objType, tableName)
|
||||||
|
}
|
||||||
|
|
||||||
|
t := networkDBTable{
|
||||||
|
name: tableName,
|
||||||
|
objType: objType,
|
||||||
|
}
|
||||||
n.Lock()
|
n.Lock()
|
||||||
defer n.Unlock()
|
defer n.Unlock()
|
||||||
|
n.driverTables = append(n.driverTables, t)
|
||||||
n.driverTables = append(n.driverTables, tableName)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -307,6 +307,22 @@ func (nDB *NetworkDB) UpdateEntry(tname, nid, key string, value []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTableByNetwork walks the networkdb by the give table and network id and
|
||||||
|
// returns a map of keys and values
|
||||||
|
func (nDB *NetworkDB) GetTableByNetwork(tname, nid string) map[string]interface{} {
|
||||||
|
entries := make(map[string]interface{})
|
||||||
|
nDB.indexes[byTable].WalkPrefix(fmt.Sprintf("/%s/%s", tname, nid), func(k string, v interface{}) bool {
|
||||||
|
entry := v.(*entry)
|
||||||
|
if entry.deleting {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
key := k[strings.LastIndex(k, "/")+1:]
|
||||||
|
entries[key] = entry.value
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
return entries
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteEntry deletes a table entry in NetworkDB for given (network,
|
// DeleteEntry deletes a table entry in NetworkDB for given (network,
|
||||||
// table, key) tuple and if the NetworkDB is part of the cluster
|
// table, key) tuple and if the NetworkDB is part of the cluster
|
||||||
// propagates this event to the cluster.
|
// propagates this event to the cluster.
|
||||||
|
|
|
@ -18,6 +18,26 @@ func newService(name string, id string, ingressPorts []*PortConfig, aliases []st
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *controller) getLBIndex(sid, nid string, ingressPorts []*PortConfig) int {
|
||||||
|
skey := serviceKey{
|
||||||
|
id: sid,
|
||||||
|
ports: portConfigs(ingressPorts).String(),
|
||||||
|
}
|
||||||
|
c.Lock()
|
||||||
|
s, ok := c.serviceBindings[skey]
|
||||||
|
c.Unlock()
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Lock()
|
||||||
|
lb := s.loadBalancers[nid]
|
||||||
|
s.Unlock()
|
||||||
|
|
||||||
|
return int(lb.fwMark)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *controller) cleanupServiceBindings(cleanupNID string) {
|
func (c *controller) cleanupServiceBindings(cleanupNID string) {
|
||||||
var cleanupFuncs []func()
|
var cleanupFuncs []func()
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче