remote.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package remote
  2. import (
  3. "fmt"
  4. "net"
  5. "github.com/Sirupsen/logrus"
  6. "github.com/docker/docker/pkg/plugins"
  7. "github.com/docker/libnetwork/discoverapi"
  8. "github.com/docker/libnetwork/ipamapi"
  9. "github.com/docker/libnetwork/ipams/remote/api"
  10. "github.com/docker/libnetwork/types"
  11. )
  12. type allocator struct {
  13. endpoint *plugins.Client
  14. name string
  15. }
  16. // PluginResponse is the interface for the plugin request responses
  17. type PluginResponse interface {
  18. IsSuccess() bool
  19. GetError() string
  20. }
  21. func newAllocator(name string, client *plugins.Client) ipamapi.Ipam {
  22. a := &allocator{name: name, endpoint: client}
  23. return a
  24. }
  25. // Init registers a remote ipam when its plugin is activated
  26. func Init(cb ipamapi.Callback, l, g interface{}) error {
  27. newPluginHandler := func(name string, client *plugins.Client) {
  28. a := newAllocator(name, client)
  29. if cps, err := a.(*allocator).getCapabilities(); err == nil {
  30. if err := cb.RegisterIpamDriverWithCapabilities(name, a, cps); err != nil {
  31. logrus.Errorf("error registering remote ipam driver %s due to %v", name, err)
  32. }
  33. } else {
  34. logrus.Infof("remote ipam driver %s does not support capabilities", name)
  35. logrus.Debug(err)
  36. if err := cb.RegisterIpamDriver(name, a); err != nil {
  37. logrus.Errorf("error registering remote ipam driver %s due to %v", name, err)
  38. }
  39. }
  40. }
  41. // Unit test code is unaware of a true PluginStore. So we fall back to v1 plugins.
  42. handleFunc := plugins.Handle
  43. if pg := cb.GetPluginGetter(); pg != nil {
  44. handleFunc = pg.Handle
  45. activePlugins := pg.GetAllManagedPluginsByCap(ipamapi.PluginEndpointType)
  46. for _, ap := range activePlugins {
  47. newPluginHandler(ap.Name(), ap.Client())
  48. }
  49. }
  50. handleFunc(ipamapi.PluginEndpointType, newPluginHandler)
  51. return nil
  52. }
  53. func (a *allocator) call(methodName string, arg interface{}, retVal PluginResponse) error {
  54. method := ipamapi.PluginEndpointType + "." + methodName
  55. err := a.endpoint.Call(method, arg, retVal)
  56. if err != nil {
  57. return err
  58. }
  59. if !retVal.IsSuccess() {
  60. return fmt.Errorf("remote: %s", retVal.GetError())
  61. }
  62. return nil
  63. }
  64. func (a *allocator) getCapabilities() (*ipamapi.Capability, error) {
  65. var res api.GetCapabilityResponse
  66. if err := a.call("GetCapabilities", nil, &res); err != nil {
  67. return nil, err
  68. }
  69. return res.ToCapability(), nil
  70. }
  71. // GetDefaultAddressSpaces returns the local and global default address spaces
  72. func (a *allocator) GetDefaultAddressSpaces() (string, string, error) {
  73. res := &api.GetAddressSpacesResponse{}
  74. if err := a.call("GetDefaultAddressSpaces", nil, res); err != nil {
  75. return "", "", err
  76. }
  77. return res.LocalDefaultAddressSpace, res.GlobalDefaultAddressSpace, nil
  78. }
  79. // RequestPool requests an address pool in the specified address space
  80. func (a *allocator) RequestPool(addressSpace, pool, subPool string, options map[string]string, v6 bool) (string, *net.IPNet, map[string]string, error) {
  81. req := &api.RequestPoolRequest{AddressSpace: addressSpace, Pool: pool, SubPool: subPool, Options: options, V6: v6}
  82. res := &api.RequestPoolResponse{}
  83. if err := a.call("RequestPool", req, res); err != nil {
  84. return "", nil, nil, err
  85. }
  86. retPool, err := types.ParseCIDR(res.Pool)
  87. return res.PoolID, retPool, res.Data, err
  88. }
  89. // ReleasePool removes an address pool from the specified address space
  90. func (a *allocator) ReleasePool(poolID string) error {
  91. req := &api.ReleasePoolRequest{PoolID: poolID}
  92. res := &api.ReleasePoolResponse{}
  93. return a.call("ReleasePool", req, res)
  94. }
  95. // RequestAddress requests an address from the address pool
  96. func (a *allocator) RequestAddress(poolID string, address net.IP, options map[string]string) (*net.IPNet, map[string]string, error) {
  97. var (
  98. prefAddress string
  99. retAddress *net.IPNet
  100. err error
  101. )
  102. if address != nil {
  103. prefAddress = address.String()
  104. }
  105. req := &api.RequestAddressRequest{PoolID: poolID, Address: prefAddress, Options: options}
  106. res := &api.RequestAddressResponse{}
  107. if err := a.call("RequestAddress", req, res); err != nil {
  108. return nil, nil, err
  109. }
  110. if res.Address != "" {
  111. retAddress, err = types.ParseCIDR(res.Address)
  112. } else {
  113. return nil, nil, ipamapi.ErrNoIPReturned
  114. }
  115. return retAddress, res.Data, err
  116. }
  117. // ReleaseAddress releases the address from the specified address pool
  118. func (a *allocator) ReleaseAddress(poolID string, address net.IP) error {
  119. var relAddress string
  120. if address != nil {
  121. relAddress = address.String()
  122. }
  123. req := &api.ReleaseAddressRequest{PoolID: poolID, Address: relAddress}
  124. res := &api.ReleaseAddressResponse{}
  125. return a.call("ReleaseAddress", req, res)
  126. }
  127. // DiscoverNew is a notification for a new discovery event, such as a new global datastore
  128. func (a *allocator) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
  129. return nil
  130. }
  131. // DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
  132. func (a *allocator) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
  133. return nil
  134. }
  135. func (a *allocator) IsBuiltIn() bool {
  136. return false
  137. }