github.com/shishir-a412ed/docker@v1.3.2-0.20180103180333-fda904911d87/api/server/router/network/network_routes.go (about)

     1  package network
     2  
     3  import (
     4  	"encoding/json"
     5  	"net/http"
     6  	"strconv"
     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  	netconst "github.com/docker/libnetwork/datastore"
    18  	"github.com/docker/libnetwork/networkdb"
    19  	"github.com/pkg/errors"
    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.FromJSON(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  type invalidRequestError struct {
    86  	cause error
    87  }
    88  
    89  func (e invalidRequestError) Error() string {
    90  	return e.cause.Error()
    91  }
    92  
    93  func (e invalidRequestError) InvalidParameter() {}
    94  
    95  type ambigousResultsError string
    96  
    97  func (e ambigousResultsError) Error() string {
    98  	return "network " + string(e) + " is ambiguous"
    99  }
   100  
   101  func (ambigousResultsError) InvalidParameter() {}
   102  
   103  type conflictError struct {
   104  	cause error
   105  }
   106  
   107  func (e conflictError) Error() string {
   108  	return e.cause.Error()
   109  }
   110  
   111  func (e conflictError) Cause() error {
   112  	return e.cause
   113  }
   114  
   115  func (e conflictError) Conflict() {}
   116  
   117  func nameConflict(name string) error {
   118  	return conflictError{libnetwork.NetworkNameError(name)}
   119  }
   120  
   121  func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   122  	if err := httputils.ParseForm(r); err != nil {
   123  		return err
   124  	}
   125  
   126  	term := vars["id"]
   127  	var (
   128  		verbose bool
   129  		err     error
   130  	)
   131  	if v := r.URL.Query().Get("verbose"); v != "" {
   132  		if verbose, err = strconv.ParseBool(v); err != nil {
   133  			return errors.Wrapf(invalidRequestError{err}, "invalid value for verbose: %s", v)
   134  		}
   135  	}
   136  	scope := r.URL.Query().Get("scope")
   137  
   138  	isMatchingScope := func(scope, term string) bool {
   139  		if term != "" {
   140  			return scope == term
   141  		}
   142  		return true
   143  	}
   144  
   145  	// In case multiple networks have duplicate names, return error.
   146  	// TODO (yongtang): should we wrap with version here for backward compatibility?
   147  
   148  	// First find based on full ID, return immediately once one is found.
   149  	// If a network appears both in swarm and local, assume it is in local first
   150  
   151  	// For full name and partial ID, save the result first, and process later
   152  	// in case multiple records was found based on the same term
   153  	listByFullName := map[string]types.NetworkResource{}
   154  	listByPartialID := map[string]types.NetworkResource{}
   155  
   156  	nw := n.backend.GetNetworks()
   157  	for _, network := range nw {
   158  		if network.ID() == term && isMatchingScope(network.Info().Scope(), scope) {
   159  			return httputils.WriteJSON(w, http.StatusOK, *n.buildDetailedNetworkResources(network, verbose))
   160  		}
   161  		if network.Name() == term && isMatchingScope(network.Info().Scope(), scope) {
   162  			// No need to check the ID collision here as we are still in
   163  			// local scope and the network ID is unique in this scope.
   164  			listByFullName[network.ID()] = *n.buildDetailedNetworkResources(network, verbose)
   165  		}
   166  		if strings.HasPrefix(network.ID(), term) && isMatchingScope(network.Info().Scope(), scope) {
   167  			// No need to check the ID collision here as we are still in
   168  			// local scope and the network ID is unique in this scope.
   169  			listByPartialID[network.ID()] = *n.buildDetailedNetworkResources(network, verbose)
   170  		}
   171  	}
   172  
   173  	nwk, err := n.cluster.GetNetwork(term)
   174  	if err == nil {
   175  		// If the get network is passed with a specific network ID / partial network ID
   176  		// or if the get network was passed with a network name and scope as swarm
   177  		// return the network. Skipped using isMatchingScope because it is true if the scope
   178  		// is not set which would be case if the client API v1.30
   179  		if strings.HasPrefix(nwk.ID, term) || (netconst.SwarmScope == scope) {
   180  			return httputils.WriteJSON(w, http.StatusOK, nwk)
   181  		}
   182  	}
   183  
   184  	nr, _ := n.cluster.GetNetworks()
   185  	for _, network := range nr {
   186  		if network.ID == term && isMatchingScope(network.Scope, scope) {
   187  			return httputils.WriteJSON(w, http.StatusOK, network)
   188  		}
   189  		if network.Name == term && isMatchingScope(network.Scope, scope) {
   190  			// Check the ID collision as we are in swarm scope here, and
   191  			// the map (of the listByFullName) may have already had a
   192  			// network with the same ID (from local scope previously)
   193  			if _, ok := listByFullName[network.ID]; !ok {
   194  				listByFullName[network.ID] = network
   195  			}
   196  		}
   197  		if strings.HasPrefix(network.ID, term) && isMatchingScope(network.Scope, scope) {
   198  			// Check the ID collision as we are in swarm scope here, and
   199  			// the map (of the listByPartialID) may have already had a
   200  			// network with the same ID (from local scope previously)
   201  			if _, ok := listByPartialID[network.ID]; !ok {
   202  				listByPartialID[network.ID] = network
   203  			}
   204  		}
   205  	}
   206  
   207  	// Find based on full name, returns true only if no duplicates
   208  	if len(listByFullName) == 1 {
   209  		for _, v := range listByFullName {
   210  			return httputils.WriteJSON(w, http.StatusOK, v)
   211  		}
   212  	}
   213  	if len(listByFullName) > 1 {
   214  		return errors.Wrapf(ambigousResultsError(term), "%d matches found based on name", len(listByFullName))
   215  	}
   216  
   217  	// Find based on partial ID, returns true only if no duplicates
   218  	if len(listByPartialID) == 1 {
   219  		for _, v := range listByPartialID {
   220  			return httputils.WriteJSON(w, http.StatusOK, v)
   221  		}
   222  	}
   223  	if len(listByPartialID) > 1 {
   224  		return errors.Wrapf(ambigousResultsError(term), "%d matches found based on ID prefix", len(listByPartialID))
   225  	}
   226  
   227  	return libnetwork.ErrNoSuchNetwork(term)
   228  }
   229  
   230  func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   231  	var create types.NetworkCreateRequest
   232  
   233  	if err := httputils.ParseForm(r); err != nil {
   234  		return err
   235  	}
   236  
   237  	if err := httputils.CheckForJSON(r); err != nil {
   238  		return err
   239  	}
   240  
   241  	if err := json.NewDecoder(r.Body).Decode(&create); err != nil {
   242  		return err
   243  	}
   244  
   245  	if nws, err := n.cluster.GetNetworksByName(create.Name); err == nil && len(nws) > 0 {
   246  		return nameConflict(create.Name)
   247  	}
   248  
   249  	nw, err := n.backend.CreateNetwork(create)
   250  	if err != nil {
   251  		var warning string
   252  		if _, ok := err.(libnetwork.NetworkNameError); ok {
   253  			// check if user defined CheckDuplicate, if set true, return err
   254  			// otherwise prepare a warning message
   255  			if create.CheckDuplicate {
   256  				return nameConflict(create.Name)
   257  			}
   258  			warning = libnetwork.NetworkNameError(create.Name).Error()
   259  		}
   260  
   261  		if _, ok := err.(libnetwork.ManagerRedirectError); !ok {
   262  			return err
   263  		}
   264  		id, err := n.cluster.CreateNetwork(create)
   265  		if err != nil {
   266  			return err
   267  		}
   268  		nw = &types.NetworkCreateResponse{
   269  			ID:      id,
   270  			Warning: warning,
   271  		}
   272  	}
   273  
   274  	return httputils.WriteJSON(w, http.StatusCreated, nw)
   275  }
   276  
   277  func (n *networkRouter) postNetworkConnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   278  	var connect types.NetworkConnect
   279  	if err := httputils.ParseForm(r); err != nil {
   280  		return err
   281  	}
   282  
   283  	if err := httputils.CheckForJSON(r); err != nil {
   284  		return err
   285  	}
   286  
   287  	if err := json.NewDecoder(r.Body).Decode(&connect); err != nil {
   288  		return err
   289  	}
   290  
   291  	return n.backend.ConnectContainerToNetwork(connect.Container, vars["id"], connect.EndpointConfig)
   292  }
   293  
   294  func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   295  	var disconnect types.NetworkDisconnect
   296  	if err := httputils.ParseForm(r); err != nil {
   297  		return err
   298  	}
   299  
   300  	if err := httputils.CheckForJSON(r); err != nil {
   301  		return err
   302  	}
   303  
   304  	if err := json.NewDecoder(r.Body).Decode(&disconnect); err != nil {
   305  		return err
   306  	}
   307  
   308  	return n.backend.DisconnectContainerFromNetwork(disconnect.Container, vars["id"], disconnect.Force)
   309  }
   310  
   311  func (n *networkRouter) deleteNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   312  	if err := httputils.ParseForm(r); err != nil {
   313  		return err
   314  	}
   315  	if _, err := n.cluster.GetNetwork(vars["id"]); err == nil {
   316  		if err = n.cluster.RemoveNetwork(vars["id"]); err != nil {
   317  			return err
   318  		}
   319  		w.WriteHeader(http.StatusNoContent)
   320  		return nil
   321  	}
   322  	if err := n.backend.DeleteNetwork(vars["id"]); err != nil {
   323  		return err
   324  	}
   325  	w.WriteHeader(http.StatusNoContent)
   326  	return nil
   327  }
   328  
   329  func (n *networkRouter) buildNetworkResource(nw libnetwork.Network) *types.NetworkResource {
   330  	r := &types.NetworkResource{}
   331  	if nw == nil {
   332  		return r
   333  	}
   334  
   335  	info := nw.Info()
   336  	r.Name = nw.Name()
   337  	r.ID = nw.ID()
   338  	r.Created = info.Created()
   339  	r.Scope = info.Scope()
   340  	r.Driver = nw.Type()
   341  	r.EnableIPv6 = info.IPv6Enabled()
   342  	r.Internal = info.Internal()
   343  	r.Attachable = info.Attachable()
   344  	r.Ingress = info.Ingress()
   345  	r.Options = info.DriverOptions()
   346  	r.Containers = make(map[string]types.EndpointResource)
   347  	buildIpamResources(r, info)
   348  	r.Labels = info.Labels()
   349  	r.ConfigOnly = info.ConfigOnly()
   350  
   351  	if cn := info.ConfigFrom(); cn != "" {
   352  		r.ConfigFrom = network.ConfigReference{Network: cn}
   353  	}
   354  
   355  	peers := info.Peers()
   356  	if len(peers) != 0 {
   357  		r.Peers = buildPeerInfoResources(peers)
   358  	}
   359  
   360  	return r
   361  }
   362  
   363  func (n *networkRouter) buildDetailedNetworkResources(nw libnetwork.Network, verbose bool) *types.NetworkResource {
   364  	if nw == nil {
   365  		return &types.NetworkResource{}
   366  	}
   367  
   368  	r := n.buildNetworkResource(nw)
   369  	epl := nw.Endpoints()
   370  	for _, e := range epl {
   371  		ei := e.Info()
   372  		if ei == nil {
   373  			continue
   374  		}
   375  		sb := ei.Sandbox()
   376  		tmpID := e.ID()
   377  		key := "ep-" + tmpID
   378  		if sb != nil {
   379  			key = sb.ContainerID()
   380  		}
   381  
   382  		r.Containers[key] = buildEndpointResource(tmpID, e.Name(), ei)
   383  	}
   384  	if !verbose {
   385  		return r
   386  	}
   387  	services := nw.Info().Services()
   388  	r.Services = make(map[string]network.ServiceInfo)
   389  	for name, service := range services {
   390  		tasks := []network.Task{}
   391  		for _, t := range service.Tasks {
   392  			tasks = append(tasks, network.Task{
   393  				Name:       t.Name,
   394  				EndpointID: t.EndpointID,
   395  				EndpointIP: t.EndpointIP,
   396  				Info:       t.Info,
   397  			})
   398  		}
   399  		r.Services[name] = network.ServiceInfo{
   400  			VIP:          service.VIP,
   401  			Ports:        service.Ports,
   402  			Tasks:        tasks,
   403  			LocalLBIndex: service.LocalLBIndex,
   404  		}
   405  	}
   406  	return r
   407  }
   408  
   409  func buildPeerInfoResources(peers []networkdb.PeerInfo) []network.PeerInfo {
   410  	peerInfo := make([]network.PeerInfo, 0, len(peers))
   411  	for _, peer := range peers {
   412  		peerInfo = append(peerInfo, network.PeerInfo{
   413  			Name: peer.Name,
   414  			IP:   peer.IP,
   415  		})
   416  	}
   417  	return peerInfo
   418  }
   419  
   420  func buildIpamResources(r *types.NetworkResource, nwInfo libnetwork.NetworkInfo) {
   421  	id, opts, ipv4conf, ipv6conf := nwInfo.IpamConfig()
   422  
   423  	ipv4Info, ipv6Info := nwInfo.IpamInfo()
   424  
   425  	r.IPAM.Driver = id
   426  
   427  	r.IPAM.Options = opts
   428  
   429  	r.IPAM.Config = []network.IPAMConfig{}
   430  	for _, ip4 := range ipv4conf {
   431  		if ip4.PreferredPool == "" {
   432  			continue
   433  		}
   434  		iData := network.IPAMConfig{}
   435  		iData.Subnet = ip4.PreferredPool
   436  		iData.IPRange = ip4.SubPool
   437  		iData.Gateway = ip4.Gateway
   438  		iData.AuxAddress = ip4.AuxAddresses
   439  		r.IPAM.Config = append(r.IPAM.Config, iData)
   440  	}
   441  
   442  	if len(r.IPAM.Config) == 0 {
   443  		for _, ip4Info := range ipv4Info {
   444  			iData := network.IPAMConfig{}
   445  			iData.Subnet = ip4Info.IPAMData.Pool.String()
   446  			if ip4Info.IPAMData.Gateway != nil {
   447  				iData.Gateway = ip4Info.IPAMData.Gateway.IP.String()
   448  			}
   449  			r.IPAM.Config = append(r.IPAM.Config, iData)
   450  		}
   451  	}
   452  
   453  	hasIpv6Conf := false
   454  	for _, ip6 := range ipv6conf {
   455  		if ip6.PreferredPool == "" {
   456  			continue
   457  		}
   458  		hasIpv6Conf = true
   459  		iData := network.IPAMConfig{}
   460  		iData.Subnet = ip6.PreferredPool
   461  		iData.IPRange = ip6.SubPool
   462  		iData.Gateway = ip6.Gateway
   463  		iData.AuxAddress = ip6.AuxAddresses
   464  		r.IPAM.Config = append(r.IPAM.Config, iData)
   465  	}
   466  
   467  	if !hasIpv6Conf {
   468  		for _, ip6Info := range ipv6Info {
   469  			if ip6Info.IPAMData.Pool == nil {
   470  				continue
   471  			}
   472  			iData := network.IPAMConfig{}
   473  			iData.Subnet = ip6Info.IPAMData.Pool.String()
   474  			iData.Gateway = ip6Info.IPAMData.Gateway.String()
   475  			r.IPAM.Config = append(r.IPAM.Config, iData)
   476  		}
   477  	}
   478  }
   479  
   480  func buildEndpointResource(id string, name string, info libnetwork.EndpointInfo) types.EndpointResource {
   481  	er := types.EndpointResource{}
   482  
   483  	er.EndpointID = id
   484  	er.Name = name
   485  	ei := info
   486  	if ei == nil {
   487  		return er
   488  	}
   489  
   490  	if iface := ei.Iface(); iface != nil {
   491  		if mac := iface.MacAddress(); mac != nil {
   492  			er.MacAddress = mac.String()
   493  		}
   494  		if ip := iface.Address(); ip != nil && len(ip.IP) > 0 {
   495  			er.IPv4Address = ip.String()
   496  		}
   497  
   498  		if ipv6 := iface.AddressIPv6(); ipv6 != nil && len(ipv6.IP) > 0 {
   499  			er.IPv6Address = ipv6.String()
   500  		}
   501  	}
   502  	return er
   503  }
   504  
   505  func (n *networkRouter) postNetworksPrune(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   506  	if err := httputils.ParseForm(r); err != nil {
   507  		return err
   508  	}
   509  
   510  	pruneFilters, err := filters.FromJSON(r.Form.Get("filters"))
   511  	if err != nil {
   512  		return err
   513  	}
   514  
   515  	pruneReport, err := n.backend.NetworksPrune(ctx, pruneFilters)
   516  	if err != nil {
   517  		return err
   518  	}
   519  	return httputils.WriteJSON(w, http.StatusOK, pruneReport)
   520  }