Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support multiple drivers on single socket #68

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,18 @@ A collection of helper packages to extend Docker Engine in Go
Graph (experimental) | [Link](https://github.com/docker/docker/blob/master/experimental/plugins_graphdriver.md) | Extend image and container fs storage

See the [understand Docker plugins documentation section](https://docs.docker.com/engine/extend/plugins/).

# Serving multiple drivers on a single socket
```go
import (
"github.com/docker/go-plugins-helpers/sdk"
"github.com/docker/go-plugins-helpers/ipam"
"github.com/docker/go-plugins-helpers/network"
)
dIPAM := MyIPAMDriver{}
dNetwork := MyNetworkDriver{}
h := sdk.NewHandler()
ipam.RegisterDriver(dIPAM, h)
network.RegisterDriver(dNetwork,h)
h.ServeUnix("/var/run/docker/plugins/myplugin.sock", 1001)
```
36 changes: 18 additions & 18 deletions authorization/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ import (
)

const (
manifest = `{"Implements": ["` + authorization.AuthZApiImplements + `"]}`
reqPath = "/" + authorization.AuthZApiRequest
resPath = "/" + authorization.AuthZApiResponse
reqPath = "/" + authorization.AuthZApiRequest
resPath = "/" + authorization.AuthZApiResponse
)

// Request is the structure that docker's requests are deserialized to.
Expand All @@ -26,32 +25,33 @@ type Plugin interface {
AuthZRes(Request) Response
}

// Handler forwards requests and responses between the docker daemon and the plugin.
type Handler struct {
plugin Plugin
sdk.Handler
}

// NewHandler initializes the request handler with a plugin implementation.
func NewHandler(plugin Plugin) *Handler {
h := &Handler{plugin, sdk.NewHandler(manifest)}
h.initMux()
func NewHandler(plugin Plugin) *sdk.Handler {
h := sdk.NewHandler()
RegisterDriver(plugin, h)
return h
}

func (h *Handler) initMux() {
h.handle(reqPath, func(req Request) Response {
return h.plugin.AuthZReq(req)
// RegisterDriver registers the plugin to the SDK handler.
func RegisterDriver(plugin Plugin, h *sdk.Handler) {
h.RegisterDriver(authorization.AuthZApiImplements, func(h *sdk.Handler) {
initMux(plugin, h)
})
}

func initMux(plugin Plugin, h *sdk.Handler) {
handle(h, reqPath, func(req Request) Response {
return plugin.AuthZReq(req)
})

h.handle(resPath, func(req Request) Response {
return h.plugin.AuthZRes(req)
handle(h, resPath, func(req Request) Response {
return plugin.AuthZRes(req)
})
}

type actionHandler func(Request) Response

func (h *Handler) handle(name string, actionCall actionHandler) {
func handle(h *sdk.Handler, name string, actionCall actionHandler) {
h.HandleFunc(name, func(w http.ResponseWriter, r *http.Request) {
var (
req Request
Expand Down
5 changes: 3 additions & 2 deletions authorization/api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strings"
"testing"

"github.com/docker/docker/pkg/authorization"
"github.com/docker/go-plugins-helpers/sdk"
)

Expand Down Expand Up @@ -46,8 +47,8 @@ func TestActivate(t *testing.T) {
t.Fatal(err)
}

if string(body) != manifest+"\n" {
t.Fatalf("Expected %s, got %s\n", manifest+"\n", string(body))
if !strings.Contains(string(body), authorization.AuthZApiImplements) {
t.Fatalf("Expected driver to implement %s, got %s\n", authorization.AuthZApiImplements, string(body))
}
}

Expand Down
51 changes: 26 additions & 25 deletions graphdriver/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const (
// DefaultDockerRootDirectory is the default directory where graph drivers will be created.
DefaultDockerRootDirectory = "/var/lib/docker/graph"

manifest = `{"Implements": ["GraphDriver"]}`
driverName = "GraphDriver"
initPath = "/GraphDriver.Init"
createPath = "/GraphDriver.Create"
createRWPath = "/GraphDriver.CreateReadWrite"
Expand Down Expand Up @@ -238,27 +238,28 @@ type Driver interface {
DiffSize(id, parent string) (int64, error)
}

// Handler forwards requests and responses between the docker daemon and the plugin.
type Handler struct {
driver Driver
sdk.Handler
}

// NewHandler initializes the request handler with a driver implementation.
func NewHandler(driver Driver) *Handler {
h := &Handler{driver, sdk.NewHandler(manifest)}
h.initMux()
func NewHandler(driver Driver) *sdk.Handler {
h := sdk.NewHandler()
RegisterDriver(driver, h)
return h
}

func (h *Handler) initMux() {
// RegisterDriver registers the plugin to the SDK handler.
func RegisterDriver(driver Driver, h *sdk.Handler) {
h.RegisterDriver(driverName, func(h *sdk.Handler) {
initMux(driver, h)
})
}

func initMux(driver Driver, h *sdk.Handler) {
h.HandleFunc(initPath, func(w http.ResponseWriter, r *http.Request) {
req := InitRequest{}
err := sdk.DecodeRequest(w, r, &req)
if err != nil {
return
}
err = h.driver.Init(req.Home, req.Options, req.UIDMaps, req.GIDMaps)
err = driver.Init(req.Home, req.Options, req.UIDMaps, req.GIDMaps)
msg := ""
if err != nil {
msg = err.Error()
Expand All @@ -271,7 +272,7 @@ func (h *Handler) initMux() {
if err != nil {
return
}
err = h.driver.Create(req.ID, req.Parent, req.MountLabel, req.StorageOpt)
err = driver.Create(req.ID, req.Parent, req.MountLabel, req.StorageOpt)
msg := ""
if err != nil {
msg = err.Error()
Expand All @@ -284,7 +285,7 @@ func (h *Handler) initMux() {
if err != nil {
return
}
err = h.driver.CreateReadWrite(req.ID, req.Parent, req.MountLabel, req.StorageOpt)
err = driver.CreateReadWrite(req.ID, req.Parent, req.MountLabel, req.StorageOpt)
msg := ""
if err != nil {
msg = err.Error()
Expand All @@ -297,7 +298,7 @@ func (h *Handler) initMux() {
if err != nil {
return
}
err = h.driver.Remove(req.ID)
err = driver.Remove(req.ID)
msg := ""
if err != nil {
msg = err.Error()
Expand All @@ -311,7 +312,7 @@ func (h *Handler) initMux() {
if err != nil {
return
}
dir, err := h.driver.Get(req.ID, req.MountLabel)
dir, err := driver.Get(req.ID, req.MountLabel)
msg := ""
if err != nil {
msg = err.Error()
Expand All @@ -324,7 +325,7 @@ func (h *Handler) initMux() {
if err != nil {
return
}
err = h.driver.Put(req.ID)
err = driver.Put(req.ID)
msg := ""
if err != nil {
msg = err.Error()
Expand All @@ -337,11 +338,11 @@ func (h *Handler) initMux() {
if err != nil {
return
}
exists := h.driver.Exists(req.ID)
exists := driver.Exists(req.ID)
sdk.EncodeResponse(w, &ExistsResponse{Exists: exists}, "")
})
h.HandleFunc(statusPath, func(w http.ResponseWriter, r *http.Request) {
status := h.driver.Status()
status := driver.Status()
sdk.EncodeResponse(w, &StatusResponse{Status: status}, "")
})
h.HandleFunc(getMetadataPath, func(w http.ResponseWriter, r *http.Request) {
Expand All @@ -350,15 +351,15 @@ func (h *Handler) initMux() {
if err != nil {
return
}
metadata, err := h.driver.GetMetadata(req.ID)
metadata, err := driver.GetMetadata(req.ID)
msg := ""
if err != nil {
msg = err.Error()
}
sdk.EncodeResponse(w, &GetMetadataResponse{Err: msg, Metadata: metadata}, msg)
})
h.HandleFunc(cleanupPath, func(w http.ResponseWriter, r *http.Request) {
err := h.driver.Cleanup()
err := driver.Cleanup()
msg := ""
if err != nil {
msg = err.Error()
Expand All @@ -371,7 +372,7 @@ func (h *Handler) initMux() {
if err != nil {
return
}
stream := h.driver.Diff(req.ID, req.Parent)
stream := driver.Diff(req.ID, req.Parent)
sdk.StreamResponse(w, stream)
})
h.HandleFunc(changesPath, func(w http.ResponseWriter, r *http.Request) {
Expand All @@ -380,7 +381,7 @@ func (h *Handler) initMux() {
if err != nil {
return
}
changes, err := h.driver.Changes(req.ID, req.Parent)
changes, err := driver.Changes(req.ID, req.Parent)
msg := ""
if err != nil {
msg = err.Error()
Expand All @@ -391,7 +392,7 @@ func (h *Handler) initMux() {
params := r.URL.Query()
id := params.Get("id")
parent := params.Get("parent")
size, err := h.driver.ApplyDiff(id, parent, r.Body)
size, err := driver.ApplyDiff(id, parent, r.Body)
msg := ""
if err != nil {
msg = err.Error()
Expand All @@ -404,7 +405,7 @@ func (h *Handler) initMux() {
if err != nil {
return
}
size, err := h.driver.DiffSize(req.ID, req.Parent)
size, err := driver.DiffSize(req.ID, req.Parent)
msg := ""
if err != nil {
msg = err.Error()
Expand Down
3 changes: 2 additions & 1 deletion graphdriver/shim/shim.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/idtools"
graphPlugin "github.com/docker/go-plugins-helpers/graphdriver"
"github.com/docker/go-plugins-helpers/sdk"
)

type shimDriver struct {
Expand All @@ -21,7 +22,7 @@ type shimDriver struct {
// built-in to Docker Engine and it would create a plugin from it that maps
// plugin API calls directly to any volume driver that satifies the
// graphdriver.Driver interface from Docker Engine.
func NewHandlerFromGraphDriver(init graphDriver.InitFunc) *graphPlugin.Handler {
func NewHandlerFromGraphDriver(init graphDriver.InitFunc) *sdk.Handler {
return graphPlugin.NewHandler(&shimDriver{driver: nil, init: init})
}

Expand Down
35 changes: 18 additions & 17 deletions ipam/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

const (
manifest = `{"Implements": ["IpamDriver"]}`
driverName = "IpamDriver"

capabilitiesPath = "/IpamDriver.GetCapabilities"
addressSpacesPath = "/IpamDriver.GetDefaultAddressSpaces"
Expand Down Expand Up @@ -88,22 +88,23 @@ 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()
func NewHandler(ipam Ipam) *sdk.Handler {
h := sdk.NewHandler()
RegisterDriver(ipam, h)
return h
}

func (h *Handler) initMux() {
// RegisterDriver registers the plugin to the SDK handler.
func RegisterDriver(ipam Ipam, h *sdk.Handler) {
h.RegisterDriver(driverName, func(h *sdk.Handler) {
initMux(ipam, h)
})
}

func initMux(ipam Ipam, h *sdk.Handler) {
h.HandleFunc(capabilitiesPath, func(w http.ResponseWriter, r *http.Request) {
res, err := h.ipam.GetCapabilities()
res, err := ipam.GetCapabilities()
if err != nil {
msg := err.Error()
sdk.EncodeResponse(w, NewErrorResponse(msg), msg)
Expand All @@ -112,7 +113,7 @@ func (h *Handler) initMux() {
sdk.EncodeResponse(w, res, "")
})
h.HandleFunc(addressSpacesPath, func(w http.ResponseWriter, r *http.Request) {
res, err := h.ipam.GetDefaultAddressSpaces()
res, err := ipam.GetDefaultAddressSpaces()
if err != nil {
msg := err.Error()
sdk.EncodeResponse(w, NewErrorResponse(msg), msg)
Expand All @@ -126,7 +127,7 @@ func (h *Handler) initMux() {
if err != nil {
return
}
res, err := h.ipam.RequestPool(req)
res, err := ipam.RequestPool(req)
if err != nil {
msg := err.Error()
sdk.EncodeResponse(w, NewErrorResponse(msg), msg)
Expand All @@ -140,7 +141,7 @@ func (h *Handler) initMux() {
if err != nil {
return
}
err = h.ipam.ReleasePool(req)
err = ipam.ReleasePool(req)
if err != nil {
msg := err.Error()
sdk.EncodeResponse(w, NewErrorResponse(msg), msg)
Expand All @@ -154,7 +155,7 @@ func (h *Handler) initMux() {
if err != nil {
return
}
res, err := h.ipam.RequestAddress(req)
res, err := ipam.RequestAddress(req)
if err != nil {
msg := err.Error()
sdk.EncodeResponse(w, NewErrorResponse(msg), msg)
Expand All @@ -168,7 +169,7 @@ func (h *Handler) initMux() {
if err != nil {
return
}
err = h.ipam.ReleaseAddress(req)
err = ipam.ReleaseAddress(req)
if err != nil {
msg := err.Error()
sdk.EncodeResponse(w, NewErrorResponse(msg), msg)
Expand Down
Loading