network.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. package controlapi
  2. import (
  3. "fmt"
  4. "net"
  5. "github.com/docker/docker/pkg/plugingetter"
  6. "github.com/docker/libnetwork/driverapi"
  7. "github.com/docker/libnetwork/ipamapi"
  8. "github.com/docker/swarmkit/api"
  9. "github.com/docker/swarmkit/identity"
  10. "github.com/docker/swarmkit/manager/state/store"
  11. "golang.org/x/net/context"
  12. "google.golang.org/grpc"
  13. "google.golang.org/grpc/codes"
  14. )
  15. func validateIPAMConfiguration(ipamConf *api.IPAMConfig) error {
  16. if ipamConf == nil {
  17. return grpc.Errorf(codes.InvalidArgument, "ipam configuration: cannot be empty")
  18. }
  19. _, subnet, err := net.ParseCIDR(ipamConf.Subnet)
  20. if err != nil {
  21. return grpc.Errorf(codes.InvalidArgument, "ipam configuration: invalid subnet %s", ipamConf.Subnet)
  22. }
  23. if ipamConf.Range != "" {
  24. ip, _, err := net.ParseCIDR(ipamConf.Range)
  25. if err != nil {
  26. return grpc.Errorf(codes.InvalidArgument, "ipam configuration: invalid range %s", ipamConf.Range)
  27. }
  28. if !subnet.Contains(ip) {
  29. return grpc.Errorf(codes.InvalidArgument, "ipam configuration: subnet %s does not contain range %s", ipamConf.Subnet, ipamConf.Range)
  30. }
  31. }
  32. if ipamConf.Gateway != "" {
  33. ip := net.ParseIP(ipamConf.Gateway)
  34. if ip == nil {
  35. return grpc.Errorf(codes.InvalidArgument, "ipam configuration: invalid gateway %s", ipamConf.Gateway)
  36. }
  37. if !subnet.Contains(ip) {
  38. return grpc.Errorf(codes.InvalidArgument, "ipam configuration: subnet %s does not contain gateway %s", ipamConf.Subnet, ipamConf.Gateway)
  39. }
  40. }
  41. return nil
  42. }
  43. func validateIPAM(ipam *api.IPAMOptions, pg plugingetter.PluginGetter) error {
  44. if ipam == nil {
  45. // It is ok to not specify any IPAM configurations. We
  46. // will choose good defaults.
  47. return nil
  48. }
  49. if err := validateDriver(ipam.Driver, pg, ipamapi.PluginEndpointType); err != nil {
  50. return err
  51. }
  52. for _, ipamConf := range ipam.Configs {
  53. if err := validateIPAMConfiguration(ipamConf); err != nil {
  54. return err
  55. }
  56. }
  57. return nil
  58. }
  59. func validateNetworkSpec(spec *api.NetworkSpec, pg plugingetter.PluginGetter) error {
  60. if spec == nil {
  61. return grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
  62. }
  63. if err := validateAnnotations(spec.Annotations); err != nil {
  64. return err
  65. }
  66. if err := validateDriver(spec.DriverConfig, pg, driverapi.NetworkPluginEndpointType); err != nil {
  67. return err
  68. }
  69. if err := validateIPAM(spec.IPAM, pg); err != nil {
  70. return err
  71. }
  72. return nil
  73. }
  74. // CreateNetwork creates and returns a Network based on the provided NetworkSpec.
  75. // - Returns `InvalidArgument` if the NetworkSpec is malformed.
  76. // - Returns an error if the creation fails.
  77. func (s *Server) CreateNetwork(ctx context.Context, request *api.CreateNetworkRequest) (*api.CreateNetworkResponse, error) {
  78. // if you change this function, you have to change createInternalNetwork in
  79. // the tests to match it (except the part where we check the label).
  80. if err := validateNetworkSpec(request.Spec, s.pg); err != nil {
  81. return nil, err
  82. }
  83. if _, ok := request.Spec.Annotations.Labels["com.docker.swarm.internal"]; ok {
  84. return nil, grpc.Errorf(codes.PermissionDenied, "label com.docker.swarm.internal is for predefined internal networks and cannot be applied by users")
  85. }
  86. // TODO(mrjana): Consider using `Name` as a primary key to handle
  87. // duplicate creations. See #65
  88. n := &api.Network{
  89. ID: identity.NewID(),
  90. Spec: *request.Spec,
  91. }
  92. err := s.store.Update(func(tx store.Tx) error {
  93. return store.CreateNetwork(tx, n)
  94. })
  95. if err != nil {
  96. return nil, err
  97. }
  98. return &api.CreateNetworkResponse{
  99. Network: n,
  100. }, nil
  101. }
  102. // GetNetwork returns a Network given a NetworkID.
  103. // - Returns `InvalidArgument` if NetworkID is not provided.
  104. // - Returns `NotFound` if the Network is not found.
  105. func (s *Server) GetNetwork(ctx context.Context, request *api.GetNetworkRequest) (*api.GetNetworkResponse, error) {
  106. if request.NetworkID == "" {
  107. return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
  108. }
  109. var n *api.Network
  110. s.store.View(func(tx store.ReadTx) {
  111. n = store.GetNetwork(tx, request.NetworkID)
  112. })
  113. if n == nil {
  114. return nil, grpc.Errorf(codes.NotFound, "network %s not found", request.NetworkID)
  115. }
  116. return &api.GetNetworkResponse{
  117. Network: n,
  118. }, nil
  119. }
  120. // RemoveNetwork removes a Network referenced by NetworkID.
  121. // - Returns `InvalidArgument` if NetworkID is not provided.
  122. // - Returns `NotFound` if the Network is not found.
  123. // - Returns an error if the deletion fails.
  124. func (s *Server) RemoveNetwork(ctx context.Context, request *api.RemoveNetworkRequest) (*api.RemoveNetworkResponse, error) {
  125. if request.NetworkID == "" {
  126. return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
  127. }
  128. err := s.store.Update(func(tx store.Tx) error {
  129. services, err := store.FindServices(tx, store.ByReferencedNetworkID(request.NetworkID))
  130. if err != nil {
  131. return grpc.Errorf(codes.Internal, "could not find services using network %s: %v", request.NetworkID, err)
  132. }
  133. if len(services) != 0 {
  134. return grpc.Errorf(codes.FailedPrecondition, "network %s is in use by service %s", request.NetworkID, services[0].ID)
  135. }
  136. tasks, err := store.FindTasks(tx, store.ByReferencedNetworkID(request.NetworkID))
  137. if err != nil {
  138. return grpc.Errorf(codes.Internal, "could not find tasks using network %s: %v", request.NetworkID, err)
  139. }
  140. if len(tasks) != 0 {
  141. return grpc.Errorf(codes.FailedPrecondition, "network %s is in use by task %s", request.NetworkID, tasks[0].ID)
  142. }
  143. nw := store.GetNetwork(tx, request.NetworkID)
  144. if _, ok := nw.Spec.Annotations.Labels["com.docker.swarm.internal"]; ok {
  145. networkDescription := nw.ID
  146. if nw.Spec.Annotations.Name != "" {
  147. networkDescription = fmt.Sprintf("%s (%s)", nw.Spec.Annotations.Name, nw.ID)
  148. }
  149. return grpc.Errorf(codes.PermissionDenied, "%s is a pre-defined network and cannot be removed", networkDescription)
  150. }
  151. return store.DeleteNetwork(tx, request.NetworkID)
  152. })
  153. if err != nil {
  154. if err == store.ErrNotExist {
  155. return nil, grpc.Errorf(codes.NotFound, "network %s not found", request.NetworkID)
  156. }
  157. return nil, err
  158. }
  159. return &api.RemoveNetworkResponse{}, nil
  160. }
  161. func filterNetworks(candidates []*api.Network, filters ...func(*api.Network) bool) []*api.Network {
  162. result := []*api.Network{}
  163. for _, c := range candidates {
  164. match := true
  165. for _, f := range filters {
  166. if !f(c) {
  167. match = false
  168. break
  169. }
  170. }
  171. if match {
  172. result = append(result, c)
  173. }
  174. }
  175. return result
  176. }
  177. // ListNetworks returns a list of all networks.
  178. func (s *Server) ListNetworks(ctx context.Context, request *api.ListNetworksRequest) (*api.ListNetworksResponse, error) {
  179. var (
  180. networks []*api.Network
  181. err error
  182. )
  183. s.store.View(func(tx store.ReadTx) {
  184. switch {
  185. case request.Filters != nil && len(request.Filters.Names) > 0:
  186. networks, err = store.FindNetworks(tx, buildFilters(store.ByName, request.Filters.Names))
  187. case request.Filters != nil && len(request.Filters.NamePrefixes) > 0:
  188. networks, err = store.FindNetworks(tx, buildFilters(store.ByNamePrefix, request.Filters.NamePrefixes))
  189. case request.Filters != nil && len(request.Filters.IDPrefixes) > 0:
  190. networks, err = store.FindNetworks(tx, buildFilters(store.ByIDPrefix, request.Filters.IDPrefixes))
  191. default:
  192. networks, err = store.FindNetworks(tx, store.All)
  193. }
  194. })
  195. if err != nil {
  196. return nil, err
  197. }
  198. if request.Filters != nil {
  199. networks = filterNetworks(networks,
  200. func(e *api.Network) bool {
  201. return filterContains(e.Spec.Annotations.Name, request.Filters.Names)
  202. },
  203. func(e *api.Network) bool {
  204. return filterContainsPrefix(e.Spec.Annotations.Name, request.Filters.NamePrefixes)
  205. },
  206. func(e *api.Network) bool {
  207. return filterContainsPrefix(e.ID, request.Filters.IDPrefixes)
  208. },
  209. func(e *api.Network) bool {
  210. return filterMatchLabels(e.Spec.Annotations.Labels, request.Filters.Labels)
  211. },
  212. )
  213. }
  214. return &api.ListNetworksResponse{
  215. Networks: networks,
  216. }, nil
  217. }