diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 16:15:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 16:15:20 +0000 |
commit | 9cce12a10d5c9a62cb86c1e2a2ce101d04d523bf (patch) | |
tree | dafe3c5d913024d6157de4a695b80fe2d6b3aec7 /ipam | |
parent | Initial commit. (diff) | |
download | golang-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.md | 31 | ||||
-rw-r--r-- | ipam/api.go | 173 |
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) + }) +} |