github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/api/server/router/network/network_routes.go (about)

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