github.com/rita33cool1/iot-system-gateway@v0.0.0-20200911033302-e65bde238cc5/docker-engine/api/server/router/network/network_routes.go (about)

     1  package network // import "github.com/docker/docker/api/server/router/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/docker/errdefs"
    17  	"github.com/docker/libnetwork"
    18  	netconst "github.com/docker/libnetwork/datastore"
    19  	"github.com/docker/libnetwork/networkdb"
    20  	"github.com/pkg/errors"
    21  )
    22  
    23  var (
    24  	// acceptedNetworkFilters is a list of acceptable filters
    25  	acceptedNetworkFilters = map[string]bool{
    26  		"driver": true,
    27  		"type":   true,
    28  		"name":   true,
    29  		"id":     true,
    30  		"label":  true,
    31  		"scope":  true,
    32  	}
    33  )
    34  
    35  func (n *networkRouter) getNetworksList(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    36  	if err := httputils.ParseForm(r); err != nil {
    37  		return err
    38  	}
    39  
    40  	filter := r.Form.Get("filters")
    41  	netFilters, err := filters.FromJSON(filter)
    42  	if err != nil {
    43  		return err
    44  	}
    45  
    46  	if err := netFilters.Validate(acceptedNetworkFilters); err != nil {
    47  		return err
    48  	}
    49  
    50  	list := []types.NetworkResource{}
    51  
    52  	if nr, err := n.cluster.GetNetworks(); err == nil {
    53  		list = append(list, nr...)
    54  	}
    55  
    56  	// Combine the network list returned by Docker daemon if it is not already
    57  	// returned by the cluster manager
    58  SKIP:
    59  	for _, nw := range n.backend.GetNetworks() {
    60  		for _, nl := range list {
    61  			if nl.ID == nw.ID() {
    62  				continue SKIP
    63  			}
    64  		}
    65  
    66  		var nr *types.NetworkResource
    67  		// Versions < 1.28 fetches all the containers attached to a network
    68  		// in a network list api call. It is a heavy weight operation when
    69  		// run across all the networks. Starting API version 1.28, this detailed
    70  		// info is available for network specific GET API (equivalent to inspect)
    71  		if versions.LessThan(httputils.VersionFromContext(ctx), "1.28") {
    72  			nr = n.buildDetailedNetworkResources(nw, false)
    73  		} else {
    74  			nr = n.buildNetworkResource(nw)
    75  		}
    76  		list = append(list, *nr)
    77  	}
    78  
    79  	list, err = filterNetworks(list, netFilters)
    80  	if err != nil {
    81  		return err
    82  	}
    83  	return httputils.WriteJSON(w, http.StatusOK, list)
    84  }
    85  
    86  type invalidRequestError struct {
    87  	cause error
    88  }
    89  
    90  func (e invalidRequestError) Error() string {
    91  	return e.cause.Error()
    92  }
    93  
    94  func (e invalidRequestError) InvalidParameter() {}
    95  
    96  type ambigousResultsError string
    97  
    98  func (e ambigousResultsError) Error() string {
    99  	return "network " + string(e) + " is ambiguous"
   100  }
   101  
   102  func (ambigousResultsError) InvalidParameter() {}
   103  
   104  func nameConflict(name string) error {
   105  	return errdefs.Conflict(libnetwork.NetworkNameError(name))
   106  }
   107  
   108  func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   109  	if err := httputils.ParseForm(r); err != nil {
   110  		return err
   111  	}
   112  
   113  	term := vars["id"]
   114  	var (
   115  		verbose bool
   116  		err     error
   117  	)
   118  	if v := r.URL.Query().Get("verbose"); v != "" {
   119  		if verbose, err = strconv.ParseBool(v); err != nil {
   120  			return errors.Wrapf(invalidRequestError{err}, "invalid value for verbose: %s", v)
   121  		}
   122  	}
   123  	scope := r.URL.Query().Get("scope")
   124  
   125  	isMatchingScope := func(scope, term string) bool {
   126  		if term != "" {
   127  			return scope == term
   128  		}
   129  		return true
   130  	}
   131  
   132  	// In case multiple networks have duplicate names, return error.
   133  	// TODO (yongtang): should we wrap with version here for backward compatibility?
   134  
   135  	// First find based on full ID, return immediately once one is found.
   136  	// If a network appears both in swarm and local, assume it is in local first
   137  
   138  	// For full name and partial ID, save the result first, and process later
   139  	// in case multiple records was found based on the same term
   140  	listByFullName := map[string]types.NetworkResource{}
   141  	listByPartialID := map[string]types.NetworkResource{}
   142  
   143  	nw := n.backend.GetNetworks()
   144  	for _, network := range nw {
   145  		if network.ID() == term && isMatchingScope(network.Info().Scope(), scope) {
   146  			return httputils.WriteJSON(w, http.StatusOK, *n.buildDetailedNetworkResources(network, verbose))
   147  		}
   148  		if network.Name() == term && isMatchingScope(network.Info().Scope(), scope) {
   149  			// No need to check the ID collision here as we are still in
   150  			// local scope and the network ID is unique in this scope.
   151  			listByFullName[network.ID()] = *n.buildDetailedNetworkResources(network, verbose)
   152  		}
   153  		if strings.HasPrefix(network.ID(), term) && isMatchingScope(network.Info().Scope(), scope) {
   154  			// No need to check the ID collision here as we are still in
   155  			// local scope and the network ID is unique in this scope.
   156  			listByPartialID[network.ID()] = *n.buildDetailedNetworkResources(network, verbose)
   157  		}
   158  	}
   159  
   160  	nwk, err := n.cluster.GetNetwork(term)
   161  	if err == nil {
   162  		// If the get network is passed with a specific network ID / partial network ID
   163  		// or if the get network was passed with a network name and scope as swarm
   164  		// return the network. Skipped using isMatchingScope because it is true if the scope
   165  		// is not set which would be case if the client API v1.30
   166  		if strings.HasPrefix(nwk.ID, term) || (netconst.SwarmScope == scope) {
   167  			// If we have a previous match "backend", return it, we need verbose when enabled
   168  			// ex: overlay/partial_ID or name/swarm_scope
   169  			if nwv, ok := listByPartialID[nwk.ID]; ok {
   170  				nwk = nwv
   171  			} else if nwv, ok := listByFullName[nwk.ID]; ok {
   172  				nwk = nwv
   173  			}
   174  			return httputils.WriteJSON(w, http.StatusOK, nwk)
   175  		}
   176  	}
   177  
   178  	nr, _ := n.cluster.GetNetworks()
   179  	for _, network := range nr {
   180  		if network.ID == term && isMatchingScope(network.Scope, scope) {
   181  			return httputils.WriteJSON(w, http.StatusOK, network)
   182  		}
   183  		if network.Name == term && isMatchingScope(network.Scope, scope) {
   184  			// Check the ID collision as we are in swarm scope here, and
   185  			// the map (of the listByFullName) may have already had a
   186  			// network with the same ID (from local scope previously)
   187  			if _, ok := listByFullName[network.ID]; !ok {
   188  				listByFullName[network.ID] = network
   189  			}
   190  		}
   191  		if strings.HasPrefix(network.ID, term) && isMatchingScope(network.Scope, scope) {
   192  			// Check the ID collision as we are in swarm scope here, and
   193  			// the map (of the listByPartialID) may have already had a
   194  			// network with the same ID (from local scope previously)
   195  			if _, ok := listByPartialID[network.ID]; !ok {
   196  				listByPartialID[network.ID] = network
   197  			}
   198  		}
   199  	}
   200  
   201  	// Find based on full name, returns true only if no duplicates
   202  	if len(listByFullName) == 1 {
   203  		for _, v := range listByFullName {
   204  			return httputils.WriteJSON(w, http.StatusOK, v)
   205  		}
   206  	}
   207  	if len(listByFullName) > 1 {
   208  		return errors.Wrapf(ambigousResultsError(term), "%d matches found based on name", len(listByFullName))
   209  	}
   210  
   211  	// Find based on partial ID, returns true only if no duplicates
   212  	if len(listByPartialID) == 1 {
   213  		for _, v := range listByPartialID {
   214  			return httputils.WriteJSON(w, http.StatusOK, v)
   215  		}
   216  	}
   217  	if len(listByPartialID) > 1 {
   218  		return errors.Wrapf(ambigousResultsError(term), "%d matches found based on ID prefix", len(listByPartialID))
   219  	}
   220  
   221  	return libnetwork.ErrNoSuchNetwork(term)
   222  }
   223  
   224  func (n *networkRouter) postNetworkCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   225  	var create types.NetworkCreateRequest
   226  
   227  	if err := httputils.ParseForm(r); err != nil {
   228  		return err
   229  	}
   230  
   231  	if err := httputils.CheckForJSON(r); err != nil {
   232  		return err
   233  	}
   234  
   235  	if err := json.NewDecoder(r.Body).Decode(&create); err != nil {
   236  		return err
   237  	}
   238  
   239  	if nws, err := n.cluster.GetNetworksByName(create.Name); err == nil && len(nws) > 0 {
   240  		return nameConflict(create.Name)
   241  	}
   242  
   243  	nw, err := n.backend.CreateNetwork(create)
   244  	if err != nil {
   245  		var warning string
   246  		if _, ok := err.(libnetwork.NetworkNameError); ok {
   247  			// check if user defined CheckDuplicate, if set true, return err
   248  			// otherwise prepare a warning message
   249  			if create.CheckDuplicate {
   250  				return nameConflict(create.Name)
   251  			}
   252  			warning = libnetwork.NetworkNameError(create.Name).Error()
   253  		}
   254  
   255  		if _, ok := err.(libnetwork.ManagerRedirectError); !ok {
   256  			return err
   257  		}
   258  		id, err := n.cluster.CreateNetwork(create)
   259  		if err != nil {
   260  			return err
   261  		}
   262  		nw = &types.NetworkCreateResponse{
   263  			ID:      id,
   264  			Warning: warning,
   265  		}
   266  	}
   267  
   268  	return httputils.WriteJSON(w, http.StatusCreated, nw)
   269  }
   270  
   271  func (n *networkRouter) postNetworkConnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   272  	var connect types.NetworkConnect
   273  	if err := httputils.ParseForm(r); err != nil {
   274  		return err
   275  	}
   276  
   277  	if err := httputils.CheckForJSON(r); err != nil {
   278  		return err
   279  	}
   280  
   281  	if err := json.NewDecoder(r.Body).Decode(&connect); err != nil {
   282  		return err
   283  	}
   284  
   285  	// Unlike other operations, we does not check ambiguity of the name/ID here.
   286  	// The reason is that, In case of attachable network in swarm scope, the actual local network
   287  	// may not be available at the time. At the same time, inside daemon `ConnectContainerToNetwork`
   288  	// does the ambiguity check anyway. Therefore, passing the name to daemon would be enough.
   289  	return n.backend.ConnectContainerToNetwork(connect.Container, vars["id"], connect.EndpointConfig)
   290  }
   291  
   292  func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   293  	var disconnect types.NetworkDisconnect
   294  	if err := httputils.ParseForm(r); err != nil {
   295  		return err
   296  	}
   297  
   298  	if err := httputils.CheckForJSON(r); err != nil {
   299  		return err
   300  	}
   301  
   302  	if err := json.NewDecoder(r.Body).Decode(&disconnect); err != nil {
   303  		return err
   304  	}
   305  
   306  	return n.backend.DisconnectContainerFromNetwork(disconnect.Container, vars["id"], disconnect.Force)
   307  }
   308  
   309  func (n *networkRouter) deleteNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   310  	if err := httputils.ParseForm(r); err != nil {
   311  		return err
   312  	}
   313  
   314  	nw, err := n.findUniqueNetwork(vars["id"])
   315  	if err != nil {
   316  		return err
   317  	}
   318  	if nw.Scope == "swarm" {
   319  		if err = n.cluster.RemoveNetwork(nw.ID); err != nil {
   320  			return err
   321  		}
   322  	} else {
   323  		if err := n.backend.DeleteNetwork(nw.ID); err != nil {
   324  			return err
   325  		}
   326  	}
   327  	w.WriteHeader(http.StatusNoContent)
   328  	return nil
   329  }
   330  
   331  func (n *networkRouter) buildNetworkResource(nw libnetwork.Network) *types.NetworkResource {
   332  	r := &types.NetworkResource{}
   333  	if nw == nil {
   334  		return r
   335  	}
   336  
   337  	info := nw.Info()
   338  	r.Name = nw.Name()
   339  	r.ID = nw.ID()
   340  	r.Created = info.Created()
   341  	r.Scope = info.Scope()
   342  	r.Driver = nw.Type()
   343  	r.EnableIPv6 = info.IPv6Enabled()
   344  	r.Internal = info.Internal()
   345  	r.Attachable = info.Attachable()
   346  	r.Ingress = info.Ingress()
   347  	r.Options = info.DriverOptions()
   348  	r.Containers = make(map[string]types.EndpointResource)
   349  	buildIpamResources(r, info)
   350  	r.Labels = info.Labels()
   351  	r.ConfigOnly = info.ConfigOnly()
   352  
   353  	if cn := info.ConfigFrom(); cn != "" {
   354  		r.ConfigFrom = network.ConfigReference{Network: cn}
   355  	}
   356  
   357  	peers := info.Peers()
   358  	if len(peers) != 0 {
   359  		r.Peers = buildPeerInfoResources(peers)
   360  	}
   361  
   362  	return r
   363  }
   364  
   365  func (n *networkRouter) buildDetailedNetworkResources(nw libnetwork.Network, verbose bool) *types.NetworkResource {
   366  	if nw == nil {
   367  		return &types.NetworkResource{}
   368  	}
   369  
   370  	r := n.buildNetworkResource(nw)
   371  	epl := nw.Endpoints()
   372  	for _, e := range epl {
   373  		ei := e.Info()
   374  		if ei == nil {
   375  			continue
   376  		}
   377  		sb := ei.Sandbox()
   378  		tmpID := e.ID()
   379  		key := "ep-" + tmpID
   380  		if sb != nil {
   381  			key = sb.ContainerID()
   382  		}
   383  
   384  		r.Containers[key] = buildEndpointResource(tmpID, e.Name(), ei)
   385  	}
   386  	if !verbose {
   387  		return r
   388  	}
   389  	services := nw.Info().Services()
   390  	r.Services = make(map[string]network.ServiceInfo)
   391  	for name, service := range services {
   392  		tasks := []network.Task{}
   393  		for _, t := range service.Tasks {
   394  			tasks = append(tasks, network.Task{
   395  				Name:       t.Name,
   396  				EndpointID: t.EndpointID,
   397  				EndpointIP: t.EndpointIP,
   398  				Info:       t.Info,
   399  			})
   400  		}
   401  		r.Services[name] = network.ServiceInfo{
   402  			VIP:          service.VIP,
   403  			Ports:        service.Ports,
   404  			Tasks:        tasks,
   405  			LocalLBIndex: service.LocalLBIndex,
   406  		}
   407  	}
   408  	return r
   409  }
   410  
   411  func buildPeerInfoResources(peers []networkdb.PeerInfo) []network.PeerInfo {
   412  	peerInfo := make([]network.PeerInfo, 0, len(peers))
   413  	for _, peer := range peers {
   414  		peerInfo = append(peerInfo, network.PeerInfo{
   415  			Name: peer.Name,
   416  			IP:   peer.IP,
   417  		})
   418  	}
   419  	return peerInfo
   420  }
   421  
   422  func buildIpamResources(r *types.NetworkResource, nwInfo libnetwork.NetworkInfo) {
   423  	id, opts, ipv4conf, ipv6conf := nwInfo.IpamConfig()
   424  
   425  	ipv4Info, ipv6Info := nwInfo.IpamInfo()
   426  
   427  	r.IPAM.Driver = id
   428  
   429  	r.IPAM.Options = opts
   430  
   431  	r.IPAM.Config = []network.IPAMConfig{}
   432  	for _, ip4 := range ipv4conf {
   433  		if ip4.PreferredPool == "" {
   434  			continue
   435  		}
   436  		iData := network.IPAMConfig{}
   437  		iData.Subnet = ip4.PreferredPool
   438  		iData.IPRange = ip4.SubPool
   439  		iData.Gateway = ip4.Gateway
   440  		iData.AuxAddress = ip4.AuxAddresses
   441  		r.IPAM.Config = append(r.IPAM.Config, iData)
   442  	}
   443  
   444  	if len(r.IPAM.Config) == 0 {
   445  		for _, ip4Info := range ipv4Info {
   446  			iData := network.IPAMConfig{}
   447  			iData.Subnet = ip4Info.IPAMData.Pool.String()
   448  			if ip4Info.IPAMData.Gateway != nil {
   449  				iData.Gateway = ip4Info.IPAMData.Gateway.IP.String()
   450  			}
   451  			r.IPAM.Config = append(r.IPAM.Config, iData)
   452  		}
   453  	}
   454  
   455  	hasIpv6Conf := false
   456  	for _, ip6 := range ipv6conf {
   457  		if ip6.PreferredPool == "" {
   458  			continue
   459  		}
   460  		hasIpv6Conf = true
   461  		iData := network.IPAMConfig{}
   462  		iData.Subnet = ip6.PreferredPool
   463  		iData.IPRange = ip6.SubPool
   464  		iData.Gateway = ip6.Gateway
   465  		iData.AuxAddress = ip6.AuxAddresses
   466  		r.IPAM.Config = append(r.IPAM.Config, iData)
   467  	}
   468  
   469  	if !hasIpv6Conf {
   470  		for _, ip6Info := range ipv6Info {
   471  			if ip6Info.IPAMData.Pool == nil {
   472  				continue
   473  			}
   474  			iData := network.IPAMConfig{}
   475  			iData.Subnet = ip6Info.IPAMData.Pool.String()
   476  			iData.Gateway = ip6Info.IPAMData.Gateway.String()
   477  			r.IPAM.Config = append(r.IPAM.Config, iData)
   478  		}
   479  	}
   480  }
   481  
   482  func buildEndpointResource(id string, name string, info libnetwork.EndpointInfo) types.EndpointResource {
   483  	er := types.EndpointResource{}
   484  
   485  	er.EndpointID = id
   486  	er.Name = name
   487  	ei := info
   488  	if ei == nil {
   489  		return er
   490  	}
   491  
   492  	if iface := ei.Iface(); iface != nil {
   493  		if mac := iface.MacAddress(); mac != nil {
   494  			er.MacAddress = mac.String()
   495  		}
   496  		if ip := iface.Address(); ip != nil && len(ip.IP) > 0 {
   497  			er.IPv4Address = ip.String()
   498  		}
   499  
   500  		if ipv6 := iface.AddressIPv6(); ipv6 != nil && len(ipv6.IP) > 0 {
   501  			er.IPv6Address = ipv6.String()
   502  		}
   503  	}
   504  	return er
   505  }
   506  
   507  func (n *networkRouter) postNetworksPrune(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   508  	if err := httputils.ParseForm(r); err != nil {
   509  		return err
   510  	}
   511  
   512  	pruneFilters, err := filters.FromJSON(r.Form.Get("filters"))
   513  	if err != nil {
   514  		return err
   515  	}
   516  
   517  	pruneReport, err := n.backend.NetworksPrune(ctx, pruneFilters)
   518  	if err != nil {
   519  		return err
   520  	}
   521  	return httputils.WriteJSON(w, http.StatusOK, pruneReport)
   522  }
   523  
   524  // findUniqueNetwork will search network across different scopes (both local and swarm).
   525  // NOTE: This findUniqueNetwork is different from FindNetwork in the daemon.
   526  // In case multiple networks have duplicate names, return error.
   527  // First find based on full ID, return immediately once one is found.
   528  // If a network appears both in swarm and local, assume it is in local first
   529  // For full name and partial ID, save the result first, and process later
   530  // in case multiple records was found based on the same term
   531  // TODO (yongtang): should we wrap with version here for backward compatibility?
   532  func (n *networkRouter) findUniqueNetwork(term string) (types.NetworkResource, error) {
   533  	listByFullName := map[string]types.NetworkResource{}
   534  	listByPartialID := map[string]types.NetworkResource{}
   535  
   536  	nw := n.backend.GetNetworks()
   537  	for _, network := range nw {
   538  		if network.ID() == term {
   539  			return *n.buildDetailedNetworkResources(network, false), nil
   540  
   541  		}
   542  		if network.Name() == term && !network.Info().Ingress() {
   543  			// No need to check the ID collision here as we are still in
   544  			// local scope and the network ID is unique in this scope.
   545  			listByFullName[network.ID()] = *n.buildDetailedNetworkResources(network, false)
   546  		}
   547  		if strings.HasPrefix(network.ID(), term) {
   548  			// No need to check the ID collision here as we are still in
   549  			// local scope and the network ID is unique in this scope.
   550  			listByPartialID[network.ID()] = *n.buildDetailedNetworkResources(network, false)
   551  		}
   552  	}
   553  
   554  	nr, _ := n.cluster.GetNetworks()
   555  	for _, network := range nr {
   556  		if network.ID == term {
   557  			return network, nil
   558  		}
   559  		if network.Name == term {
   560  			// Check the ID collision as we are in swarm scope here, and
   561  			// the map (of the listByFullName) may have already had a
   562  			// network with the same ID (from local scope previously)
   563  			if _, ok := listByFullName[network.ID]; !ok {
   564  				listByFullName[network.ID] = network
   565  			}
   566  		}
   567  		if strings.HasPrefix(network.ID, term) {
   568  			// Check the ID collision as we are in swarm scope here, and
   569  			// the map (of the listByPartialID) may have already had a
   570  			// network with the same ID (from local scope previously)
   571  			if _, ok := listByPartialID[network.ID]; !ok {
   572  				listByPartialID[network.ID] = network
   573  			}
   574  		}
   575  	}
   576  
   577  	// Find based on full name, returns true only if no duplicates
   578  	if len(listByFullName) == 1 {
   579  		for _, v := range listByFullName {
   580  			return v, nil
   581  		}
   582  	}
   583  	if len(listByFullName) > 1 {
   584  		return types.NetworkResource{}, errdefs.InvalidParameter(errors.Errorf("network %s is ambiguous (%d matches found based on name)", term, len(listByFullName)))
   585  	}
   586  
   587  	// Find based on partial ID, returns true only if no duplicates
   588  	if len(listByPartialID) == 1 {
   589  		for _, v := range listByPartialID {
   590  			return v, nil
   591  		}
   592  	}
   593  	if len(listByPartialID) > 1 {
   594  		return types.NetworkResource{}, errdefs.InvalidParameter(errors.Errorf("network %s is ambiguous (%d matches found based on ID prefix)", term, len(listByPartialID)))
   595  	}
   596  
   597  	return types.NetworkResource{}, errdefs.NotFound(libnetwork.ErrNoSuchNetwork(term))
   598  }