summaryrefslogtreecommitdiffstats
path: root/ipam
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 16:15:20 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 16:15:20 +0000
commit9cce12a10d5c9a62cb86c1e2a2ce101d04d523bf (patch)
treedafe3c5d913024d6157de4a695b80fe2d6b3aec7 /ipam
parentInitial commit. (diff)
downloadgolang-github-docker-go-plugins-helpers-9cce12a10d5c9a62cb86c1e2a2ce101d04d523bf.tar.xz
golang-github-docker-go-plugins-helpers-9cce12a10d5c9a62cb86c1e2a2ce101d04d523bf.zip
Adding upstream version 0.20211224.upstream/0.20211224upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ipam')
-rw-r--r--ipam/README.md31
-rw-r--r--ipam/api.go173
2 files changed, 204 insertions, 0 deletions
diff --git a/ipam/README.md b/ipam/README.md
new file mode 100644
index 0000000..fcd0079
--- /dev/null
+++ b/ipam/README.md
@@ -0,0 +1,31 @@
+# Docker IPAM extension API
+
+Go handler to create external IPAM extensions for Docker.
+
+## Usage
+
+This library is designed to be integrated in your program.
+
+1. Implement the `ipam.Driver` interface.
+2. Initialize a `ipam.Handler` with your implementation.
+3. Call either `ServeTCP` or `ServeUnix` from the `ipam.Handler`.
+
+### Example using TCP sockets:
+
+```go
+ import "github.com/docker/go-plugins-helpers/ipam"
+
+ d := MyIPAMDriver{}
+ h := ipam.NewHandler(d)
+ h.ServeTCP("test_ipam", ":8080")
+```
+
+### Example using Unix sockets:
+
+```go
+ import "github.com/docker/go-plugins-helpers/ipam"
+
+ d := MyIPAMDriver{}
+ h := ipam.NewHandler(d)
+ h.ServeUnix("root", "test_ipam")
+```
diff --git a/ipam/api.go b/ipam/api.go
new file mode 100644
index 0000000..7ebc906
--- /dev/null
+++ b/ipam/api.go
@@ -0,0 +1,173 @@
+package ipam
+
+import (
+ "net/http"
+
+ "github.com/docker/go-plugins-helpers/sdk"
+)
+
+const (
+ manifest = `{"Implements": ["IpamDriver"]}`
+
+ capabilitiesPath = "/IpamDriver.GetCapabilities"
+ addressSpacesPath = "/IpamDriver.GetDefaultAddressSpaces"
+ requestPoolPath = "/IpamDriver.RequestPool"
+ releasePoolPath = "/IpamDriver.ReleasePool"
+ requestAddressPath = "/IpamDriver.RequestAddress"
+ releaseAddressPath = "/IpamDriver.ReleaseAddress"
+)
+
+// Ipam represent the interface a driver must fulfill.
+type Ipam interface {
+ GetCapabilities() (*CapabilitiesResponse, error)
+ GetDefaultAddressSpaces() (*AddressSpacesResponse, error)
+ RequestPool(*RequestPoolRequest) (*RequestPoolResponse, error)
+ ReleasePool(*ReleasePoolRequest) error
+ RequestAddress(*RequestAddressRequest) (*RequestAddressResponse, error)
+ ReleaseAddress(*ReleaseAddressRequest) error
+}
+
+// CapabilitiesResponse returns whether or not this IPAM required pre-made MAC
+type CapabilitiesResponse struct {
+ RequiresMACAddress bool
+}
+
+// AddressSpacesResponse returns the default local and global address space names for this IPAM
+type AddressSpacesResponse struct {
+ LocalDefaultAddressSpace string
+ GlobalDefaultAddressSpace string
+}
+
+// RequestPoolRequest is sent by the daemon when a pool needs to be created
+type RequestPoolRequest struct {
+ AddressSpace string
+ Pool string
+ SubPool string
+ Options map[string]string
+ V6 bool
+}
+
+// RequestPoolResponse returns a registered address pool with the IPAM driver
+type RequestPoolResponse struct {
+ PoolID string
+ Pool string
+ Data map[string]string
+}
+
+// ReleasePoolRequest is sent when releasing a previously registered address pool
+type ReleasePoolRequest struct {
+ PoolID string
+}
+
+// RequestAddressRequest is sent when requesting an address from IPAM
+type RequestAddressRequest struct {
+ PoolID string
+ Address string
+ Options map[string]string
+}
+
+// RequestAddressResponse is formed with allocated address by IPAM
+type RequestAddressResponse struct {
+ Address string
+ Data map[string]string
+}
+
+// ReleaseAddressRequest is sent in order to release an address from the pool
+type ReleaseAddressRequest struct {
+ PoolID string
+ Address string
+}
+
+// ErrorResponse is a formatted error message that libnetwork can understand
+type ErrorResponse struct {
+ Err string
+}
+
+// NewErrorResponse creates an ErrorResponse with the provided message
+func NewErrorResponse(msg string) *ErrorResponse {
+ return &ErrorResponse{Err: msg}
+}
+
+// Handler forwards requests and responses between the docker daemon and the plugin.
+type Handler struct {
+ ipam Ipam
+ sdk.Handler
+}
+
+// NewHandler initializes the request handler with a driver implementation.
+func NewHandler(ipam Ipam) *Handler {
+ h := &Handler{ipam, sdk.NewHandler(manifest)}
+ h.initMux()
+ return h
+}
+
+func (h *Handler) initMux() {
+ h.HandleFunc(capabilitiesPath, func(w http.ResponseWriter, r *http.Request) {
+ res, err := h.ipam.GetCapabilities()
+ if err != nil {
+ sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true)
+ return
+ }
+ sdk.EncodeResponse(w, res, false)
+ })
+ h.HandleFunc(addressSpacesPath, func(w http.ResponseWriter, r *http.Request) {
+ res, err := h.ipam.GetDefaultAddressSpaces()
+ if err != nil {
+ sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true)
+ return
+ }
+ sdk.EncodeResponse(w, res, false)
+ })
+ h.HandleFunc(requestPoolPath, func(w http.ResponseWriter, r *http.Request) {
+ req := &RequestPoolRequest{}
+ err := sdk.DecodeRequest(w, r, req)
+ if err != nil {
+ return
+ }
+ res, err := h.ipam.RequestPool(req)
+ if err != nil {
+ sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true)
+ return
+ }
+ sdk.EncodeResponse(w, res, false)
+ })
+ h.HandleFunc(releasePoolPath, func(w http.ResponseWriter, r *http.Request) {
+ req := &ReleasePoolRequest{}
+ err := sdk.DecodeRequest(w, r, req)
+ if err != nil {
+ return
+ }
+ err = h.ipam.ReleasePool(req)
+ if err != nil {
+ sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true)
+ return
+ }
+ sdk.EncodeResponse(w, struct{}{}, false)
+ })
+ h.HandleFunc(requestAddressPath, func(w http.ResponseWriter, r *http.Request) {
+ req := &RequestAddressRequest{}
+ err := sdk.DecodeRequest(w, r, req)
+ if err != nil {
+ return
+ }
+ res, err := h.ipam.RequestAddress(req)
+ if err != nil {
+ sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true)
+ return
+ }
+ sdk.EncodeResponse(w, res, false)
+ })
+ h.HandleFunc(releaseAddressPath, func(w http.ResponseWriter, r *http.Request) {
+ req := &ReleaseAddressRequest{}
+ err := sdk.DecodeRequest(w, r, req)
+ if err != nil {
+ return
+ }
+ err = h.ipam.ReleaseAddress(req)
+ if err != nil {
+ sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true)
+ return
+ }
+ sdk.EncodeResponse(w, struct{}{}, false)
+ })
+}