github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/swarmkit/manager/controlapi/network.go (about)

     1  package controlapi
     2  
     3  import (
     4  	"context"
     5  	"net"
     6  
     7  	"github.com/docker/docker/pkg/plugingetter"
     8  	"github.com/docker/libnetwork/driverapi"
     9  	"github.com/docker/libnetwork/ipamapi"
    10  	"github.com/docker/swarmkit/api"
    11  	"github.com/docker/swarmkit/identity"
    12  	"github.com/docker/swarmkit/manager/allocator"
    13  	"github.com/docker/swarmkit/manager/allocator/networkallocator"
    14  	"github.com/docker/swarmkit/manager/state/store"
    15  	"google.golang.org/grpc/codes"
    16  	"google.golang.org/grpc/status"
    17  )
    18  
    19  func validateIPAMConfiguration(ipamConf *api.IPAMConfig) error {
    20  	if ipamConf == nil {
    21  		return status.Errorf(codes.InvalidArgument, "ipam configuration: cannot be empty")
    22  	}
    23  
    24  	_, subnet, err := net.ParseCIDR(ipamConf.Subnet)
    25  	if err != nil {
    26  		return status.Errorf(codes.InvalidArgument, "ipam configuration: invalid subnet %s", ipamConf.Subnet)
    27  	}
    28  
    29  	if ipamConf.Range != "" {
    30  		ip, _, err := net.ParseCIDR(ipamConf.Range)
    31  		if err != nil {
    32  			return status.Errorf(codes.InvalidArgument, "ipam configuration: invalid range %s", ipamConf.Range)
    33  		}
    34  
    35  		if !subnet.Contains(ip) {
    36  			return status.Errorf(codes.InvalidArgument, "ipam configuration: subnet %s does not contain range %s", ipamConf.Subnet, ipamConf.Range)
    37  		}
    38  	}
    39  
    40  	if ipamConf.Gateway != "" {
    41  		ip := net.ParseIP(ipamConf.Gateway)
    42  		if ip == nil {
    43  			return status.Errorf(codes.InvalidArgument, "ipam configuration: invalid gateway %s", ipamConf.Gateway)
    44  		}
    45  
    46  		if !subnet.Contains(ip) {
    47  			return status.Errorf(codes.InvalidArgument, "ipam configuration: subnet %s does not contain gateway %s", ipamConf.Subnet, ipamConf.Gateway)
    48  		}
    49  	}
    50  
    51  	return nil
    52  }
    53  
    54  func validateIPAM(ipam *api.IPAMOptions, pg plugingetter.PluginGetter) error {
    55  	if ipam == nil {
    56  		// It is ok to not specify any IPAM configurations. We
    57  		// will choose good defaults.
    58  		return nil
    59  	}
    60  
    61  	if err := validateDriver(ipam.Driver, pg, ipamapi.PluginEndpointType); err != nil {
    62  		return err
    63  	}
    64  
    65  	for _, ipamConf := range ipam.Configs {
    66  		if err := validateIPAMConfiguration(ipamConf); err != nil {
    67  			return err
    68  		}
    69  	}
    70  
    71  	return nil
    72  }
    73  
    74  func validateNetworkSpec(spec *api.NetworkSpec, pg plugingetter.PluginGetter) error {
    75  	if spec == nil {
    76  		return status.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
    77  	}
    78  
    79  	if spec.Ingress && spec.DriverConfig != nil && spec.DriverConfig.Name != "overlay" {
    80  		return status.Errorf(codes.Unimplemented, "only overlay driver is currently supported for ingress network")
    81  	}
    82  
    83  	if spec.Attachable && spec.Ingress {
    84  		return status.Errorf(codes.InvalidArgument, "ingress network cannot be attachable")
    85  	}
    86  
    87  	if err := validateAnnotations(spec.Annotations); err != nil {
    88  		return err
    89  	}
    90  
    91  	if _, ok := spec.Annotations.Labels[networkallocator.PredefinedLabel]; ok {
    92  		return status.Errorf(codes.PermissionDenied, "label %s is for internally created predefined networks and cannot be applied by users",
    93  			networkallocator.PredefinedLabel)
    94  	}
    95  	if err := validateDriver(spec.DriverConfig, pg, driverapi.NetworkPluginEndpointType); err != nil {
    96  		return err
    97  	}
    98  
    99  	return validateIPAM(spec.IPAM, pg)
   100  }
   101  
   102  // CreateNetwork creates and returns a Network based on the provided NetworkSpec.
   103  // - Returns `InvalidArgument` if the NetworkSpec is malformed.
   104  // - Returns an error if the creation fails.
   105  func (s *Server) CreateNetwork(ctx context.Context, request *api.CreateNetworkRequest) (*api.CreateNetworkResponse, error) {
   106  	if err := validateNetworkSpec(request.Spec, s.pg); err != nil {
   107  		return nil, err
   108  	}
   109  
   110  	// TODO(mrjana): Consider using `Name` as a primary key to handle
   111  	// duplicate creations. See #65
   112  	n := &api.Network{
   113  		ID:   identity.NewID(),
   114  		Spec: *request.Spec,
   115  	}
   116  
   117  	err := s.store.Update(func(tx store.Tx) error {
   118  		if request.Spec.Ingress {
   119  			if n, err := allocator.GetIngressNetwork(s.store); err == nil {
   120  				return status.Errorf(codes.AlreadyExists, "ingress network (%s) is already present", n.ID)
   121  			} else if err != allocator.ErrNoIngress {
   122  				return status.Errorf(codes.Internal, "failed ingress network presence check: %v", err)
   123  			}
   124  		}
   125  		return store.CreateNetwork(tx, n)
   126  	})
   127  	if err != nil {
   128  		return nil, err
   129  	}
   130  
   131  	return &api.CreateNetworkResponse{
   132  		Network: n,
   133  	}, nil
   134  }
   135  
   136  // GetNetwork returns a Network given a NetworkID.
   137  // - Returns `InvalidArgument` if NetworkID is not provided.
   138  // - Returns `NotFound` if the Network is not found.
   139  func (s *Server) GetNetwork(ctx context.Context, request *api.GetNetworkRequest) (*api.GetNetworkResponse, error) {
   140  	if request.NetworkID == "" {
   141  		return nil, status.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
   142  	}
   143  
   144  	var n *api.Network
   145  	s.store.View(func(tx store.ReadTx) {
   146  		n = store.GetNetwork(tx, request.NetworkID)
   147  	})
   148  	if n == nil {
   149  		return nil, status.Errorf(codes.NotFound, "network %s not found", request.NetworkID)
   150  	}
   151  	return &api.GetNetworkResponse{
   152  		Network: n,
   153  	}, nil
   154  }
   155  
   156  // RemoveNetwork removes a Network referenced by NetworkID.
   157  // - Returns `InvalidArgument` if NetworkID is not provided.
   158  // - Returns `NotFound` if the Network is not found.
   159  // - Returns an error if the deletion fails.
   160  func (s *Server) RemoveNetwork(ctx context.Context, request *api.RemoveNetworkRequest) (*api.RemoveNetworkResponse, error) {
   161  	if request.NetworkID == "" {
   162  		return nil, status.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
   163  	}
   164  
   165  	var (
   166  		n  *api.Network
   167  		rm = s.removeNetwork
   168  	)
   169  
   170  	s.store.View(func(tx store.ReadTx) {
   171  		n = store.GetNetwork(tx, request.NetworkID)
   172  	})
   173  	if n == nil {
   174  		return nil, status.Errorf(codes.NotFound, "network %s not found", request.NetworkID)
   175  	}
   176  
   177  	if allocator.IsIngressNetwork(n) {
   178  		rm = s.removeIngressNetwork
   179  	}
   180  
   181  	if v, ok := n.Spec.Annotations.Labels[networkallocator.PredefinedLabel]; ok && v == "true" {
   182  		return nil, status.Errorf(codes.FailedPrecondition, "network %s (%s) is a swarm predefined network and cannot be removed",
   183  			request.NetworkID, n.Spec.Annotations.Name)
   184  	}
   185  
   186  	if err := rm(n.ID); err != nil {
   187  		if err == store.ErrNotExist {
   188  			return nil, status.Errorf(codes.NotFound, "network %s not found", request.NetworkID)
   189  		}
   190  		return nil, err
   191  	}
   192  	return &api.RemoveNetworkResponse{}, nil
   193  }
   194  
   195  func (s *Server) removeNetwork(id string) error {
   196  	return s.store.Update(func(tx store.Tx) error {
   197  		services, err := store.FindServices(tx, store.ByReferencedNetworkID(id))
   198  		if err != nil {
   199  			return status.Errorf(codes.Internal, "could not find services using network %s: %v", id, err)
   200  		}
   201  
   202  		if len(services) != 0 {
   203  			return status.Errorf(codes.FailedPrecondition, "network %s is in use by service %s", id, services[0].ID)
   204  		}
   205  
   206  		tasks, err := store.FindTasks(tx, store.ByReferencedNetworkID(id))
   207  		if err != nil {
   208  			return status.Errorf(codes.Internal, "could not find tasks using network %s: %v", id, err)
   209  		}
   210  
   211  		for _, t := range tasks {
   212  			if t.DesiredState <= api.TaskStateRunning && t.Status.State <= api.TaskStateRunning {
   213  				return status.Errorf(codes.FailedPrecondition, "network %s is in use by task %s", id, t.ID)
   214  			}
   215  		}
   216  
   217  		return store.DeleteNetwork(tx, id)
   218  	})
   219  }
   220  
   221  func (s *Server) removeIngressNetwork(id string) error {
   222  	return s.store.Update(func(tx store.Tx) error {
   223  		services, err := store.FindServices(tx, store.All)
   224  		if err != nil {
   225  			return status.Errorf(codes.Internal, "could not find services using network %s: %v", id, err)
   226  		}
   227  		for _, srv := range services {
   228  			if allocator.IsIngressNetworkNeeded(srv) {
   229  				return status.Errorf(codes.FailedPrecondition, "ingress network cannot be removed because service %s depends on it", srv.ID)
   230  			}
   231  		}
   232  		return store.DeleteNetwork(tx, id)
   233  	})
   234  }
   235  
   236  func filterNetworks(candidates []*api.Network, filters ...func(*api.Network) bool) []*api.Network {
   237  	result := []*api.Network{}
   238  
   239  	for _, c := range candidates {
   240  		match := true
   241  		for _, f := range filters {
   242  			if !f(c) {
   243  				match = false
   244  				break
   245  			}
   246  		}
   247  		if match {
   248  			result = append(result, c)
   249  		}
   250  	}
   251  
   252  	return result
   253  }
   254  
   255  // ListNetworks returns a list of all networks.
   256  func (s *Server) ListNetworks(ctx context.Context, request *api.ListNetworksRequest) (*api.ListNetworksResponse, error) {
   257  	var (
   258  		networks []*api.Network
   259  		err      error
   260  	)
   261  
   262  	s.store.View(func(tx store.ReadTx) {
   263  		switch {
   264  		case request.Filters != nil && len(request.Filters.Names) > 0:
   265  			networks, err = store.FindNetworks(tx, buildFilters(store.ByName, request.Filters.Names))
   266  		case request.Filters != nil && len(request.Filters.NamePrefixes) > 0:
   267  			networks, err = store.FindNetworks(tx, buildFilters(store.ByNamePrefix, request.Filters.NamePrefixes))
   268  		case request.Filters != nil && len(request.Filters.IDPrefixes) > 0:
   269  			networks, err = store.FindNetworks(tx, buildFilters(store.ByIDPrefix, request.Filters.IDPrefixes))
   270  		default:
   271  			networks, err = store.FindNetworks(tx, store.All)
   272  		}
   273  	})
   274  	if err != nil {
   275  		return nil, err
   276  	}
   277  
   278  	if request.Filters != nil {
   279  		networks = filterNetworks(networks,
   280  			func(e *api.Network) bool {
   281  				return filterContains(e.Spec.Annotations.Name, request.Filters.Names)
   282  			},
   283  			func(e *api.Network) bool {
   284  				return filterContainsPrefix(e.Spec.Annotations.Name, request.Filters.NamePrefixes)
   285  			},
   286  			func(e *api.Network) bool {
   287  				return filterContainsPrefix(e.ID, request.Filters.IDPrefixes)
   288  			},
   289  			func(e *api.Network) bool {
   290  				return filterMatchLabels(e.Spec.Annotations.Labels, request.Filters.Labels)
   291  			},
   292  		)
   293  	}
   294  
   295  	return &api.ListNetworksResponse{
   296  		Networks: networks,
   297  	}, nil
   298  }