network.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. package controlapi
  2. import (
  3. "net"
  4. "github.com/docker/docker/pkg/plugingetter"
  5. "github.com/docker/libnetwork/driverapi"
  6. "github.com/docker/libnetwork/ipamapi"
  7. "github.com/docker/swarmkit/api"
  8. "github.com/docker/swarmkit/identity"
  9. "github.com/docker/swarmkit/manager/allocator"
  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 spec.Ingress && spec.DriverConfig != nil && spec.DriverConfig.Name != "overlay" {
  64. return grpc.Errorf(codes.Unimplemented, "only overlay driver is currently supported for ingress network")
  65. }
  66. if spec.Attachable && spec.Ingress {
  67. return grpc.Errorf(codes.InvalidArgument, "ingress network cannot be attachable")
  68. }
  69. if err := validateAnnotations(spec.Annotations); err != nil {
  70. return err
  71. }
  72. if err := validateDriver(spec.DriverConfig, pg, driverapi.NetworkPluginEndpointType); err != nil {
  73. return err
  74. }
  75. if err := validateIPAM(spec.IPAM, pg); err != nil {
  76. return err
  77. }
  78. return nil
  79. }
  80. // CreateNetwork creates and returns a Network based on the provided NetworkSpec.
  81. // - Returns `InvalidArgument` if the NetworkSpec is malformed.
  82. // - Returns an error if the creation fails.
  83. func (s *Server) CreateNetwork(ctx context.Context, request *api.CreateNetworkRequest) (*api.CreateNetworkResponse, error) {
  84. if err := validateNetworkSpec(request.Spec, s.pg); err != nil {
  85. return nil, err
  86. }
  87. // TODO(mrjana): Consider using `Name` as a primary key to handle
  88. // duplicate creations. See #65
  89. n := &api.Network{
  90. ID: identity.NewID(),
  91. Spec: *request.Spec,
  92. }
  93. err := s.store.Update(func(tx store.Tx) error {
  94. if request.Spec.Ingress {
  95. if n, err := allocator.GetIngressNetwork(s.store); err == nil {
  96. return grpc.Errorf(codes.AlreadyExists, "ingress network (%s) is already present", n.ID)
  97. } else if err != allocator.ErrNoIngress {
  98. return grpc.Errorf(codes.Internal, "failed ingress network presence check: %v", err)
  99. }
  100. }
  101. return store.CreateNetwork(tx, n)
  102. })
  103. if err != nil {
  104. return nil, err
  105. }
  106. return &api.CreateNetworkResponse{
  107. Network: n,
  108. }, nil
  109. }
  110. // GetNetwork returns a Network given a NetworkID.
  111. // - Returns `InvalidArgument` if NetworkID is not provided.
  112. // - Returns `NotFound` if the Network is not found.
  113. func (s *Server) GetNetwork(ctx context.Context, request *api.GetNetworkRequest) (*api.GetNetworkResponse, error) {
  114. if request.NetworkID == "" {
  115. return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
  116. }
  117. var n *api.Network
  118. s.store.View(func(tx store.ReadTx) {
  119. n = store.GetNetwork(tx, request.NetworkID)
  120. })
  121. if n == nil {
  122. return nil, grpc.Errorf(codes.NotFound, "network %s not found", request.NetworkID)
  123. }
  124. return &api.GetNetworkResponse{
  125. Network: n,
  126. }, nil
  127. }
  128. // RemoveNetwork removes a Network referenced by NetworkID.
  129. // - Returns `InvalidArgument` if NetworkID is not provided.
  130. // - Returns `NotFound` if the Network is not found.
  131. // - Returns an error if the deletion fails.
  132. func (s *Server) RemoveNetwork(ctx context.Context, request *api.RemoveNetworkRequest) (*api.RemoveNetworkResponse, error) {
  133. if request.NetworkID == "" {
  134. return nil, grpc.Errorf(codes.InvalidArgument, errInvalidArgument.Error())
  135. }
  136. var (
  137. n *api.Network
  138. rm = s.removeNetwork
  139. )
  140. s.store.View(func(tx store.ReadTx) {
  141. n = store.GetNetwork(tx, request.NetworkID)
  142. })
  143. if n == nil {
  144. return nil, grpc.Errorf(codes.NotFound, "network %s not found", request.NetworkID)
  145. }
  146. if allocator.IsIngressNetwork(n) {
  147. rm = s.removeIngressNetwork
  148. }
  149. if err := rm(n.ID); err != nil {
  150. if err == store.ErrNotExist {
  151. return nil, grpc.Errorf(codes.NotFound, "network %s not found", request.NetworkID)
  152. }
  153. return nil, err
  154. }
  155. return &api.RemoveNetworkResponse{}, nil
  156. }
  157. func (s *Server) removeNetwork(id string) error {
  158. return s.store.Update(func(tx store.Tx) error {
  159. services, err := store.FindServices(tx, store.ByReferencedNetworkID(id))
  160. if err != nil {
  161. return grpc.Errorf(codes.Internal, "could not find services using network %s: %v", id, err)
  162. }
  163. if len(services) != 0 {
  164. return grpc.Errorf(codes.FailedPrecondition, "network %s is in use by service %s", id, services[0].ID)
  165. }
  166. tasks, err := store.FindTasks(tx, store.ByReferencedNetworkID(id))
  167. if err != nil {
  168. return grpc.Errorf(codes.Internal, "could not find tasks using network %s: %v", id, err)
  169. }
  170. for _, t := range tasks {
  171. if t.DesiredState <= api.TaskStateRunning && t.Status.State <= api.TaskStateRunning {
  172. return grpc.Errorf(codes.FailedPrecondition, "network %s is in use by task %s", id, t.ID)
  173. }
  174. }
  175. return store.DeleteNetwork(tx, id)
  176. })
  177. }
  178. func (s *Server) removeIngressNetwork(id string) error {
  179. return s.store.Update(func(tx store.Tx) error {
  180. services, err := store.FindServices(tx, store.All)
  181. if err != nil {
  182. return grpc.Errorf(codes.Internal, "could not find services using network %s: %v", id, err)
  183. }
  184. for _, srv := range services {
  185. if allocator.IsIngressNetworkNeeded(srv) {
  186. return grpc.Errorf(codes.FailedPrecondition, "ingress network cannot be removed because service %s depends on it", srv.ID)
  187. }
  188. }
  189. return store.DeleteNetwork(tx, id)
  190. })
  191. }
  192. func filterNetworks(candidates []*api.Network, filters ...func(*api.Network) bool) []*api.Network {
  193. result := []*api.Network{}
  194. for _, c := range candidates {
  195. match := true
  196. for _, f := range filters {
  197. if !f(c) {
  198. match = false
  199. break
  200. }
  201. }
  202. if match {
  203. result = append(result, c)
  204. }
  205. }
  206. return result
  207. }
  208. // ListNetworks returns a list of all networks.
  209. func (s *Server) ListNetworks(ctx context.Context, request *api.ListNetworksRequest) (*api.ListNetworksResponse, error) {
  210. var (
  211. networks []*api.Network
  212. err error
  213. )
  214. s.store.View(func(tx store.ReadTx) {
  215. switch {
  216. case request.Filters != nil && len(request.Filters.Names) > 0:
  217. networks, err = store.FindNetworks(tx, buildFilters(store.ByName, request.Filters.Names))
  218. case request.Filters != nil && len(request.Filters.NamePrefixes) > 0:
  219. networks, err = store.FindNetworks(tx, buildFilters(store.ByNamePrefix, request.Filters.NamePrefixes))
  220. case request.Filters != nil && len(request.Filters.IDPrefixes) > 0:
  221. networks, err = store.FindNetworks(tx, buildFilters(store.ByIDPrefix, request.Filters.IDPrefixes))
  222. default:
  223. networks, err = store.FindNetworks(tx, store.All)
  224. }
  225. })
  226. if err != nil {
  227. return nil, err
  228. }
  229. if request.Filters != nil {
  230. networks = filterNetworks(networks,
  231. func(e *api.Network) bool {
  232. return filterContains(e.Spec.Annotations.Name, request.Filters.Names)
  233. },
  234. func(e *api.Network) bool {
  235. return filterContainsPrefix(e.Spec.Annotations.Name, request.Filters.NamePrefixes)
  236. },
  237. func(e *api.Network) bool {
  238. return filterContainsPrefix(e.ID, request.Filters.IDPrefixes)
  239. },
  240. func(e *api.Network) bool {
  241. return filterMatchLabels(e.Spec.Annotations.Labels, request.Filters.Labels)
  242. },
  243. )
  244. }
  245. return &api.ListNetworksResponse{
  246. Networks: networks,
  247. }, nil
  248. }