github.com/fabiokung/docker@v0.11.2-0.20170222101415-4534dcd49497/api/server/router/network/network_routes.go (about)

     1  package network
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  	"strings"
     8  
     9  	"golang.org/x/net/context"
    10  
    11  	"github.com/docker/docker/api/server/httputils"
    12  	"github.com/docker/docker/api/types"
    13  	"github.com/docker/docker/api/types/filters"
    14  	"github.com/docker/docker/api/types/network"
    15  	"github.com/docker/docker/api/types/versions"
    16  	"github.com/docker/libnetwork"
    17  	"github.com/docker/libnetwork/networkdb"
    18  )
    19  
    20  var (
    21  	// acceptedNetworkFilters is a list of acceptable filters
    22  	acceptedNetworkFilters = map[string]bool{
    23  		"driver": true,
    24  		"type":   true,
    25  		"name":   true,
    26  		"id":     true,
    27  		"label":  true,
    28  	}
    29  )
    30  
    31  func (n *networkRouter) getNetworksList(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    32  	if err := httputils.ParseForm(r); err != nil {
    33  		return err
    34  	}
    35  
    36  	filter := r.Form.Get("filters")
    37  	netFilters, err := filters.FromParam(filter)
    38  	if err != nil {
    39  		return err
    40  	}
    41  
    42  	if err := netFilters.Validate(acceptedNetworkFilters); err != nil {
    43  		return err
    44  	}
    45  
    46  	list := []types.NetworkResource{}
    47  
    48  	if nr, err := n.cluster.GetNetworks(); err == nil {
    49  		list = append(list, nr...)
    50  	}
    51  
    52  	// Combine the network list returned by Docker daemon if it is not already
    53  	// returned by the cluster manager
    54  SKIP:
    55  	for _, nw := range n.backend.GetNetworks() {
    56  		for _, nl := range list {
    57  			if nl.ID == nw.ID() {
    58  				continue SKIP
    59  			}
    60  		}
    61  
    62  		var nr *types.NetworkResource
    63  		// Versions < 1.27 fetches all the containers attached to a network
    64  		// in a network list api call. It is a heavy weight operation when
    65  		// run across all the networks. Starting API version 1.27, this detailed
    66  		// info is available for network specific GET API (equivalent to inspect)
    67  		if versions.LessThan(httputils.VersionFromContext(ctx), "1.27") {
    68  			nr = n.buildDetailedNetworkResources(nw)
    69  		} else {
    70  			nr = n.buildNetworkResource(nw)
    71  		}
    72  		list = append(list, *nr)
    73  	}
    74  
    75  	list, err = filterNetworks(list, netFilters)
    76  	if err != nil {
    77  		return err
    78  	}
    79  	return httputils.WriteJSON(w, http.StatusOK, list)
    80  }
    81  
    82  func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    83  	if err := httputils.ParseForm(r); err != nil {
    84  		return err
    85  	}
    86  
    87  	term := vars["id"]
    88  
    89  	// In case multiple networks have duplicate names, return error.
    90  	// TODO (yongtang): should we wrap with version here for backward compatibility?
    91  
    92  	// First find based on full ID, return immediately once one is found.
    93  	// If a network appears both in swarm and local, assume it is in local first
    94  
    95  	// For full name and partial ID, save the result first, and process later
    96  	// in case multiple records was found based on the same term
    97  	listByFullName := map[string]types.NetworkResource{}
    98  	listByPartialID := map[string]types.NetworkResource{}
    99  
   100  	nw := n.backend.GetNetworks()
   101  	for _, network := range nw {
   102  		if network.ID() == term {
   103  			return httputils.WriteJSON(w, http.StatusOK, *n.buildDetailedNetworkResources(network))
   104  		}
   105  		if network.Name() == term {
   106  			// No need to check the ID collision here as we are still in
   107  			// local scope and the network ID is unique in this scope.
   108  			listByFullName[network.ID()] = *n.buildDetailedNetworkResources(network)
   109  		}
   110  		if strings.HasPrefix(network.ID(), term) {
   111  			// No need to check the ID collision here as we are still in
   112  			// local scope and the network ID is unique in this scope.
   113  			listByPartialID[network.ID()] = *n.buildDetailedNetworkResources(network)
   114  		}
   115  	}
   116  
   117  	nr, _ := n.cluster.GetNetworks()
   118  	for _, network := range nr {
   119  		if network.ID == term {
   120  			return httputils.WriteJSON(w, http.StatusOK, network)
   121  		}
   122  		if network.Name == term {
   123  			// Check the ID collision as we are in swarm scope here, and
   124  			// the map (of the listByFullName) may have already had a
   125  			// network with the same ID (from local scope previously)
   126  			if _, ok := listByFullName[network.ID]; !ok {
   127  				listByFullName[network.ID] = network
   128  			}
   129  		}
   130  		if strings.HasPrefix(network.ID, term) {
   131  			// Check the ID collision as we are in swarm scope here, and
   132  			// the map (of the listByPartialID) may have already had a
   133  			// network with the same ID (from local scope previously)
   134  			if _, ok := listByPartialID[network.ID]; !ok {
   135  				listByPartialID[network.ID] = network
   136  			}
   137  		}
   138  	}
   139  
   140  	// Find based on full name, returns true only if no duplicates
   141  	if len(listByFullName) == 1 {
   142  		for _, v := range listByFullName {
   143  			return httputils.WriteJSON(w, http.StatusOK, v)
   144  		}
   145  	}
   146  	if len(listByFullName) > 1 {
   147  		return fmt.Errorf("network %s is ambiguous (%d matches found based on name)", term, len(listByFullName))
   148  	}
   149  
   150  	// Find based on partial ID, returns true only if no duplicates
   151  	if len(listByPartialID) == 1 {
   152  		for _, v := range listByPartialID {
   153  			return httputils.WriteJSON(w, http.StatusOK, v)
   154  		}
   155  	}
   156  	if len(listByPartialID) > 1 {
   157  		return fmt.Errorf("network %s is ambiguous (%d matches found based on ID prefix)", term, len(listByPartialID))
   158  	}
   159  
   160  	return libnetwork.ErrNoSuchNetwork(term)
   161  }
   162  
   163  func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   164  	var create types.NetworkCreateRequest
   165  
   166  	if err := httputils.ParseForm(r); err != nil {
   167  		return err
   168  	}
   169  
   170  	if err := httputils.CheckForJSON(r); err != nil {
   171  		return err
   172  	}
   173  
   174  	if err := json.NewDecoder(r.Body).Decode(&create); err != nil {
   175  		return err
   176  	}
   177  
   178  	if nws, err := n.cluster.GetNetworksByName(create.Name); err == nil && len(nws) > 0 {
   179  		return libnetwork.NetworkNameError(create.Name)
   180  	}
   181  
   182  	nw, err := n.backend.CreateNetwork(create)
   183  	if err != nil {
   184  		if _, ok := err.(libnetwork.ManagerRedirectError); !ok {
   185  			return err
   186  		}
   187  		id, err := n.cluster.CreateNetwork(create)
   188  		if err != nil {
   189  			return err
   190  		}
   191  		nw = &types.NetworkCreateResponse{ID: id}
   192  	}
   193  
   194  	return httputils.WriteJSON(w, http.StatusCreated, nw)
   195  }
   196  
   197  func (n *networkRouter) postNetworkConnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   198  	var connect types.NetworkConnect
   199  	if err := httputils.ParseForm(r); err != nil {
   200  		return err
   201  	}
   202  
   203  	if err := httputils.CheckForJSON(r); err != nil {
   204  		return err
   205  	}
   206  
   207  	if err := json.NewDecoder(r.Body).Decode(&connect); err != nil {
   208  		return err
   209  	}
   210  
   211  	return n.backend.ConnectContainerToNetwork(connect.Container, vars["id"], connect.EndpointConfig)
   212  }
   213  
   214  func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   215  	var disconnect types.NetworkDisconnect
   216  	if err := httputils.ParseForm(r); err != nil {
   217  		return err
   218  	}
   219  
   220  	if err := httputils.CheckForJSON(r); err != nil {
   221  		return err
   222  	}
   223  
   224  	if err := json.NewDecoder(r.Body).Decode(&disconnect); err != nil {
   225  		return err
   226  	}
   227  
   228  	return n.backend.DisconnectContainerFromNetwork(disconnect.Container, vars["id"], disconnect.Force)
   229  }
   230  
   231  func (n *networkRouter) deleteNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   232  	if err := httputils.ParseForm(r); err != nil {
   233  		return err
   234  	}
   235  	if _, err := n.cluster.GetNetwork(vars["id"]); err == nil {
   236  		if err = n.cluster.RemoveNetwork(vars["id"]); err != nil {
   237  			return err
   238  		}
   239  		w.WriteHeader(http.StatusNoContent)
   240  		return nil
   241  	}
   242  	if err := n.backend.DeleteNetwork(vars["id"]); err != nil {
   243  		return err
   244  	}
   245  	w.WriteHeader(http.StatusNoContent)
   246  	return nil
   247  }
   248  
   249  func (n *networkRouter) buildNetworkResource(nw libnetwork.Network) *types.NetworkResource {
   250  	r := &types.NetworkResource{}
   251  	if nw == nil {
   252  		return r
   253  	}
   254  
   255  	info := nw.Info()
   256  	r.Name = nw.Name()
   257  	r.ID = nw.ID()
   258  	r.Created = info.Created()
   259  	r.Scope = info.Scope()
   260  	if n.cluster.IsManager() {
   261  		if _, err := n.cluster.GetNetwork(nw.ID()); err == nil {
   262  			r.Scope = "swarm"
   263  		}
   264  	} else if info.Dynamic() {
   265  		r.Scope = "swarm"
   266  	}
   267  	r.Driver = nw.Type()
   268  	r.EnableIPv6 = info.IPv6Enabled()
   269  	r.Internal = info.Internal()
   270  	r.Attachable = info.Attachable()
   271  	r.Options = info.DriverOptions()
   272  	r.Containers = make(map[string]types.EndpointResource)
   273  	buildIpamResources(r, info)
   274  	r.Labels = info.Labels()
   275  
   276  	peers := info.Peers()
   277  	if len(peers) != 0 {
   278  		r.Peers = buildPeerInfoResources(peers)
   279  	}
   280  
   281  	return r
   282  }
   283  
   284  func (n *networkRouter) buildDetailedNetworkResources(nw libnetwork.Network) *types.NetworkResource {
   285  	if nw == nil {
   286  		return &types.NetworkResource{}
   287  	}
   288  
   289  	r := n.buildNetworkResource(nw)
   290  	epl := nw.Endpoints()
   291  	for _, e := range epl {
   292  		ei := e.Info()
   293  		if ei == nil {
   294  			continue
   295  		}
   296  		sb := ei.Sandbox()
   297  		tmpID := e.ID()
   298  		key := "ep-" + tmpID
   299  		if sb != nil {
   300  			key = sb.ContainerID()
   301  		}
   302  
   303  		r.Containers[key] = buildEndpointResource(tmpID, e.Name(), ei)
   304  	}
   305  	return r
   306  }
   307  
   308  func buildPeerInfoResources(peers []networkdb.PeerInfo) []network.PeerInfo {
   309  	peerInfo := make([]network.PeerInfo, 0, len(peers))
   310  	for _, peer := range peers {
   311  		peerInfo = append(peerInfo, network.PeerInfo{
   312  			Name: peer.Name,
   313  			IP:   peer.IP,
   314  		})
   315  	}
   316  	return peerInfo
   317  }
   318  
   319  func buildIpamResources(r *types.NetworkResource, nwInfo libnetwork.NetworkInfo) {
   320  	id, opts, ipv4conf, ipv6conf := nwInfo.IpamConfig()
   321  
   322  	ipv4Info, ipv6Info := nwInfo.IpamInfo()
   323  
   324  	r.IPAM.Driver = id
   325  
   326  	r.IPAM.Options = opts
   327  
   328  	r.IPAM.Config = []network.IPAMConfig{}
   329  	for _, ip4 := range ipv4conf {
   330  		if ip4.PreferredPool == "" {
   331  			continue
   332  		}
   333  		iData := network.IPAMConfig{}
   334  		iData.Subnet = ip4.PreferredPool
   335  		iData.IPRange = ip4.SubPool
   336  		iData.Gateway = ip4.Gateway
   337  		iData.AuxAddress = ip4.AuxAddresses
   338  		r.IPAM.Config = append(r.IPAM.Config, iData)
   339  	}
   340  
   341  	if len(r.IPAM.Config) == 0 {
   342  		for _, ip4Info := range ipv4Info {
   343  			iData := network.IPAMConfig{}
   344  			iData.Subnet = ip4Info.IPAMData.Pool.String()
   345  			iData.Gateway = ip4Info.IPAMData.Gateway.IP.String()
   346  			r.IPAM.Config = append(r.IPAM.Config, iData)
   347  		}
   348  	}
   349  
   350  	hasIpv6Conf := false
   351  	for _, ip6 := range ipv6conf {
   352  		if ip6.PreferredPool == "" {
   353  			continue
   354  		}
   355  		hasIpv6Conf = true
   356  		iData := network.IPAMConfig{}
   357  		iData.Subnet = ip6.PreferredPool
   358  		iData.IPRange = ip6.SubPool
   359  		iData.Gateway = ip6.Gateway
   360  		iData.AuxAddress = ip6.AuxAddresses
   361  		r.IPAM.Config = append(r.IPAM.Config, iData)
   362  	}
   363  
   364  	if !hasIpv6Conf {
   365  		for _, ip6Info := range ipv6Info {
   366  			iData := network.IPAMConfig{}
   367  			iData.Subnet = ip6Info.IPAMData.Pool.String()
   368  			iData.Gateway = ip6Info.IPAMData.Gateway.String()
   369  			r.IPAM.Config = append(r.IPAM.Config, iData)
   370  		}
   371  	}
   372  }
   373  
   374  func buildEndpointResource(id string, name string, info libnetwork.EndpointInfo) types.EndpointResource {
   375  	er := types.EndpointResource{}
   376  
   377  	er.EndpointID = id
   378  	er.Name = name
   379  	ei := info
   380  	if ei == nil {
   381  		return er
   382  	}
   383  
   384  	if iface := ei.Iface(); iface != nil {
   385  		if mac := iface.MacAddress(); mac != nil {
   386  			er.MacAddress = mac.String()
   387  		}
   388  		if ip := iface.Address(); ip != nil && len(ip.IP) > 0 {
   389  			er.IPv4Address = ip.String()
   390  		}
   391  
   392  		if ipv6 := iface.AddressIPv6(); ipv6 != nil && len(ipv6.IP) > 0 {
   393  			er.IPv6Address = ipv6.String()
   394  		}
   395  	}
   396  	return er
   397  }
   398  
   399  func (n *networkRouter) postNetworksPrune(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   400  	if err := httputils.ParseForm(r); err != nil {
   401  		return err
   402  	}
   403  
   404  	pruneFilters, err := filters.FromParam(r.Form.Get("filters"))
   405  	if err != nil {
   406  		return err
   407  	}
   408  
   409  	pruneReport, err := n.backend.NetworksPrune(pruneFilters)
   410  	if err != nil {
   411  		return err
   412  	}
   413  	return httputils.WriteJSON(w, http.StatusOK, pruneReport)
   414  }