diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4319d63..a79bd46 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -16,6 +16,6 @@ jobs: runs-on: ${{ matrix.platform }} steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: test run: make test diff --git a/Makefile b/Makefile index efaab6a..623d509 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ REPO_NAME = go-plugins-helpers REPO_OWNER = docker PKG_NAME = github.com/${REPO_OWNER}/${REPO_NAME} -IMAGE = golang:1.16 +IMAGE = golang:1.21 all: test diff --git a/README.md b/README.md index 0c4fc45..37d0fe5 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,11 @@ A collection of helper packages to extend Docker Engine in Go - Plugin type | Documentation | Description - --------------|---------------|-------------------------------------------------- - Authorization | [Link](https://docs.docker.com/engine/extend/authorization/) | Extend API authorization mechanism - Network | [Link](https://docs.docker.com/engine/extend/plugins_network/) | Extend network management - Volume | [Link](https://docs.docker.com/engine/extend/plugins_volume/) | Extend persistent storage - IPAM | [Link](https://github.com/docker/libnetwork/blob/master/docs/ipam.md) | Extend IP address management - Graph (experimental) | [Link](https://github.com/docker/cli/blob/master/docs/extend/plugins_graphdriver.md)| Extend image and container fs storage +| Plugin type | Documentation | Description | +|---------------|-----------------------------------------------------------------------|------------------------------------| +| Authorization | [Link](https://docs.docker.com/engine/extend/authorization/) | Extend API authorization mechanism | +| Network | [Link](https://docs.docker.com/engine/extend/plugins_network/) | Extend network management | +| Volume | [Link](https://docs.docker.com/engine/extend/plugins_volume/) | Extend persistent storage | +| IPAM | [Link](https://github.com/docker/libnetwork/blob/master/docs/ipam.md) | Extend IP address management | -See the [understand Docker plugins documentation section](https://docs.docker.com/engine/extend/plugins/). +See the [understand Docker plugins documentation section](https://docs.docker.com/engine/extend/). diff --git a/authorization/api_test.go b/authorization/api_test.go index 407c65e..5532b2b 100644 --- a/authorization/api_test.go +++ b/authorization/api_test.go @@ -8,7 +8,7 @@ import ( "crypto/x509/pkix" "encoding/json" "fmt" - "io/ioutil" + "io" "math/big" "net/http" "os" @@ -42,15 +42,13 @@ func (p *TestPlugin) AuthZRes(r Request) Response { func TestActivate(t *testing.T) { response, err := http.Get("http://localhost:32456/Plugin.Activate") - if err != nil { t.Fatal(err) } defer response.Body.Close() - body, err := ioutil.ReadAll(response.Body) - + body, err := io.ReadAll(response.Body) if err != nil { t.Fatal(err) } @@ -68,15 +66,13 @@ func TestAuthZReq(t *testing.T) { sdk.DefaultContentTypeV1_1, strings.NewReader(request), ) - if err != nil { t.Fatal(err) } defer response.Body.Close() - body, err := ioutil.ReadAll(response.Body) - + body, err := io.ReadAll(response.Body) if err != nil { t.Fatal(err) } @@ -107,15 +103,13 @@ func TestAuthZRes(t *testing.T) { sdk.DefaultContentTypeV1_1, strings.NewReader(request), ) - if err != nil { t.Fatal(err) } defer response.Body.Close() - body, err := ioutil.ReadAll(response.Body) - + body, err := io.ReadAll(response.Body) if err != nil { t.Fatal(err) } @@ -160,14 +154,14 @@ func TestPeerCertificateMarshalJSON(t *testing.T) { publickey := &privatekey.PublicKey // create a self-signed certificate. template = parent - var parent = template + parent := template raw, err := x509.CreateCertificate(rand.Reader, template, parent, publickey, privatekey) require.NoError(t, err) cert, err := x509.ParseCertificate(raw) require.NoError(t, err) - var certs = []*x509.Certificate{cert} + certs := []*x509.Certificate{cert} addr := "www.authz.com/auth" req, err := http.NewRequest("GET", addr, nil) require.NoError(t, err) @@ -191,11 +185,9 @@ func TestPeerCertificateMarshalJSON(t *testing.T) { require.Nil(t, err) require.Equal(t, "Earth", pcObj.Subject.Country[0]) require.Equal(t, true, pcObj.IsCA) - }) } - } func callURL(url string) { diff --git a/graphdriver/README.md b/graphdriver/README.md deleted file mode 100644 index 8c55c8a..0000000 --- a/graphdriver/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# Docker volume extension api. - -Go handler to create external graphdriver extensions for Docker. - -## Usage - -This library is designed to be integrated in your program. - -1. Implement the `graphdriver.Driver` interface. -2. Initialize a `graphdriver.Handler` with your implementation. -3. Call either `ServeTCP` or `ServeUnix` from the `graphdriver.Handler`. - -### Example using TCP sockets: - -```go - d := MyGraphDriver{} - h := graphdriver.NewHandler(d) - h.ServeTCP("test_graph", ":8080") -``` - -### Example using Unix sockets: - -```go - d := MyGraphDriver{} - h := graphdriver.NewHandler(d) - h.ServeUnix("root", "test_graph") -``` diff --git a/graphdriver/api.go b/graphdriver/api.go deleted file mode 100644 index 193f77a..0000000 --- a/graphdriver/api.go +++ /dev/null @@ -1,408 +0,0 @@ -package graphdriver - -// See https://github.com/docker/cli/blob/master/docs/extend/plugins_graphdriver.md - -import ( - "io" - "net/http" - - graphDriver "github.com/docker/docker/daemon/graphdriver" - "github.com/docker/docker/pkg/containerfs" - "github.com/docker/docker/pkg/idtools" - "github.com/docker/go-plugins-helpers/sdk" -) - -const ( - // DefaultDockerRootDirectory is the default directory where graph drivers will be created. - DefaultDockerRootDirectory = "/var/lib/docker/graph" - - manifest = `{"Implements": ["GraphDriver"]}` - initPath = "/GraphDriver.Init" - createPath = "/GraphDriver.Create" - createRWPath = "/GraphDriver.CreateReadWrite" - removePath = "/GraphDriver.Remove" - getPath = "/GraphDriver.Get" - putPath = "/GraphDriver.Put" - existsPath = "/GraphDriver.Exists" - statusPath = "/GraphDriver.Status" - getMetadataPath = "/GraphDriver.GetMetadata" - cleanupPath = "/GraphDriver.Cleanup" - diffPath = "/GraphDriver.Diff" - changesPath = "/GraphDriver.Changes" - applyDiffPath = "/GraphDriver.ApplyDiff" - diffSizePath = "/GraphDriver.DiffSize" - capabilitiesPath = "/GraphDriver.Capabilities" -) - -// Init - -// InitRequest is the structure that docker's init requests are deserialized to. -type InitRequest struct { - Home string - Options []string `json:"Opts"` - UIDMaps []idtools.IDMap `json:"UIDMaps"` - GIDMaps []idtools.IDMap `json:"GIDMaps"` -} - -// Create - -// CreateRequest is the structure that docker's create requests are deserialized to. -type CreateRequest struct { - ID string - Parent string - MountLabel string - StorageOpt map[string]string -} - -// Remove - -// RemoveRequest is the structure that docker's remove requests are deserialized to. -type RemoveRequest struct { - ID string -} - -// Get - -// GetRequest is the structure that docker's get requests are deserialized to. -type GetRequest struct { - ID string - MountLabel string -} - -// GetResponse is the strucutre that docker's remove responses are serialized to. -type GetResponse struct { - Dir string -} - -// Put - -// PutRequest is the structure that docker's put requests are deserialized to. -type PutRequest struct { - ID string -} - -// Exists - -// ExistsRequest is the structure that docker's exists requests are deserialized to. -type ExistsRequest struct { - ID string -} - -// ExistsResponse is the structure that docker's exists responses are serialized to. -type ExistsResponse struct { - Exists bool -} - -// Status - -// StatusRequest is the structure that docker's status requests are deserialized to. -type StatusRequest struct{} - -// StatusResponse is the structure that docker's status responses are serialized to. -type StatusResponse struct { - Status [][2]string -} - -// GetMetadata - -// GetMetadataRequest is the structure that docker's getMetadata requests are deserialized to. -type GetMetadataRequest struct { - ID string -} - -// GetMetadataResponse is the structure that docker's getMetadata responses are serialized to. -type GetMetadataResponse struct { - Metadata map[string]string -} - -// Cleanup - -// CleanupRequest is the structure that docker's cleanup requests are deserialized to. -type CleanupRequest struct{} - -// Diff - -// DiffRequest is the structure that docker's diff requests are deserialized to. -type DiffRequest struct { - ID string - Parent string -} - -// DiffResponse is the structure that docker's diff responses are serialized to. -type DiffResponse struct { - Stream io.ReadCloser // TAR STREAM -} - -// Changes - -// ChangesRequest is the structure that docker's changes requests are deserialized to. -type ChangesRequest struct { - ID string - Parent string -} - -// ChangesResponse is the structure that docker's changes responses are serialized to. -type ChangesResponse struct { - Changes []Change -} - -// ChangeKind represents the type of change mage -type ChangeKind int - -const ( - // Modified is a ChangeKind used when an item has been modified - Modified ChangeKind = iota - // Added is a ChangeKind used when an item has been added - Added - // Deleted is a ChangeKind used when an item has been deleted - Deleted -) - -// Change is the structure that docker's individual changes are serialized to. -type Change struct { - Path string - Kind ChangeKind -} - -// ApplyDiff - -// ApplyDiffRequest is the structure that docker's applyDiff requests are deserialized to. -type ApplyDiffRequest struct { - Stream io.Reader // TAR STREAM - ID string - Parent string -} - -// ApplyDiffResponse is the structure that docker's applyDiff responses are serialized to. -type ApplyDiffResponse struct { - Size int64 -} - -// DiffSize - -// DiffSizeRequest is the structure that docker's diffSize requests are deserialized to. -type DiffSizeRequest struct { - ID string - Parent string -} - -// DiffSizeResponse is the structure that docker's diffSize responses are serialized to. -type DiffSizeResponse struct { - Size int64 -} - -// CapabilitiesRequest is the structure that docker's capabilities requests are deserialized to. -type CapabilitiesRequest struct{} - -// CapabilitiesResponse is the structure that docker's capabilities responses are serialized to. -type CapabilitiesResponse struct { - Capabilities graphDriver.Capabilities -} - -// ErrorResponse is a formatted error message that docker can understand -type ErrorResponse struct { - Err string -} - -// NewErrorResponse creates an ErrorResponse with the provided message -func NewErrorResponse(msg string) *ErrorResponse { - return &ErrorResponse{Err: msg} -} - -// Driver represent the interface a driver must fulfill. -type Driver interface { - Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) error - Create(id, parent, mountlabel string, storageOpt map[string]string) error - CreateReadWrite(id, parent, mountlabel string, storageOpt map[string]string) error - Remove(id string) error - Get(id, mountLabel string) (containerfs.ContainerFS, error) - Put(id string) error - Exists(id string) bool - Status() [][2]string - GetMetadata(id string) (map[string]string, error) - Cleanup() error - Diff(id, parent string) io.ReadCloser - Changes(id, parent string) ([]Change, error) - ApplyDiff(id, parent string, archive io.Reader) (int64, error) - DiffSize(id, parent string) (int64, error) - Capabilities() graphDriver.Capabilities -} - -// 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() - return h -} - -func (h *Handler) initMux() { - 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) - if err != nil { - sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true) - return - } - sdk.EncodeResponse(w, struct{}{}, false) - }) - h.HandleFunc(createPath, func(w http.ResponseWriter, r *http.Request) { - req := CreateRequest{} - err := sdk.DecodeRequest(w, r, &req) - if err != nil { - return - } - err = h.driver.Create(req.ID, req.Parent, req.MountLabel, req.StorageOpt) - if err != nil { - sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true) - return - } - sdk.EncodeResponse(w, struct{}{}, false) - }) - h.HandleFunc(createRWPath, func(w http.ResponseWriter, r *http.Request) { - req := CreateRequest{} - err := sdk.DecodeRequest(w, r, &req) - if err != nil { - return - } - err = h.driver.CreateReadWrite(req.ID, req.Parent, req.MountLabel, req.StorageOpt) - if err != nil { - sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true) - return - } - sdk.EncodeResponse(w, struct{}{}, false) - }) - h.HandleFunc(removePath, func(w http.ResponseWriter, r *http.Request) { - req := RemoveRequest{} - err := sdk.DecodeRequest(w, r, &req) - if err != nil { - return - } - err = h.driver.Remove(req.ID) - if err != nil { - sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true) - return - } - sdk.EncodeResponse(w, struct{}{}, false) - - }) - h.HandleFunc(getPath, func(w http.ResponseWriter, r *http.Request) { - req := GetRequest{} - err := sdk.DecodeRequest(w, r, &req) - if err != nil { - return - } - dir, err := h.driver.Get(req.ID, req.MountLabel) - if err != nil { - sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true) - return - } - sdk.EncodeResponse(w, &GetResponse{Dir: dir.Path()}, false) - }) - h.HandleFunc(putPath, func(w http.ResponseWriter, r *http.Request) { - req := PutRequest{} - err := sdk.DecodeRequest(w, r, &req) - if err != nil { - return - } - err = h.driver.Put(req.ID) - if err != nil { - sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true) - return - } - sdk.EncodeResponse(w, struct{}{}, false) - }) - h.HandleFunc(existsPath, func(w http.ResponseWriter, r *http.Request) { - req := ExistsRequest{} - err := sdk.DecodeRequest(w, r, &req) - if err != nil { - return - } - exists := h.driver.Exists(req.ID) - sdk.EncodeResponse(w, &ExistsResponse{Exists: exists}, false) - }) - h.HandleFunc(statusPath, func(w http.ResponseWriter, r *http.Request) { - status := h.driver.Status() - sdk.EncodeResponse(w, &StatusResponse{Status: status}, false) - }) - h.HandleFunc(getMetadataPath, func(w http.ResponseWriter, r *http.Request) { - req := GetMetadataRequest{} - err := sdk.DecodeRequest(w, r, &req) - if err != nil { - return - } - metadata, err := h.driver.GetMetadata(req.ID) - if err != nil { - sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true) - return - } - sdk.EncodeResponse(w, &GetMetadataResponse{Metadata: metadata}, false) - }) - h.HandleFunc(cleanupPath, func(w http.ResponseWriter, r *http.Request) { - err := h.driver.Cleanup() - if err != nil { - sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true) - return - } - sdk.EncodeResponse(w, struct{}{}, false) - }) - h.HandleFunc(diffPath, func(w http.ResponseWriter, r *http.Request) { - req := DiffRequest{} - err := sdk.DecodeRequest(w, r, &req) - if err != nil { - return - } - stream := h.driver.Diff(req.ID, req.Parent) - sdk.StreamResponse(w, stream) - }) - h.HandleFunc(changesPath, func(w http.ResponseWriter, r *http.Request) { - req := ChangesRequest{} - err := sdk.DecodeRequest(w, r, &req) - if err != nil { - return - } - changes, err := h.driver.Changes(req.ID, req.Parent) - if err != nil { - sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true) - return - } - sdk.EncodeResponse(w, &ChangesResponse{Changes: changes}, false) - }) - h.HandleFunc(applyDiffPath, func(w http.ResponseWriter, r *http.Request) { - params := r.URL.Query() - id := params.Get("id") - parent := params.Get("parent") - size, err := h.driver.ApplyDiff(id, parent, r.Body) - if err != nil { - sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true) - return - } - sdk.EncodeResponse(w, &ApplyDiffResponse{Size: size}, false) - }) - h.HandleFunc(diffSizePath, func(w http.ResponseWriter, r *http.Request) { - req := DiffRequest{} - err := sdk.DecodeRequest(w, r, &req) - if err != nil { - return - } - size, err := h.driver.DiffSize(req.ID, req.Parent) - if err != nil { - sdk.EncodeResponse(w, NewErrorResponse(err.Error()), true) - return - } - sdk.EncodeResponse(w, &DiffSizeResponse{Size: size}, false) - }) - h.HandleFunc(capabilitiesPath, func(w http.ResponseWriter, r *http.Request) { - caps := h.driver.Capabilities() - sdk.EncodeResponse(w, &CapabilitiesResponse{Capabilities: caps}, false) - }) -} diff --git a/graphdriver/api_test.go b/graphdriver/api_test.go deleted file mode 100644 index b2c97c4..0000000 --- a/graphdriver/api_test.go +++ /dev/null @@ -1,320 +0,0 @@ -package graphdriver - -import ( - "bytes" - "encoding/json" - "io" - "io/ioutil" - "net/http" - "testing" - - graphDriver "github.com/docker/docker/daemon/graphdriver" - "github.com/docker/docker/pkg/containerfs" - "github.com/docker/docker/pkg/idtools" - "github.com/docker/go-connections/sockets" -) - -const url = "http://localhost" - -func TestHandler(t *testing.T) { - p := &testPlugin{} - h := NewHandler(p) - l := sockets.NewInmemSocket("test", 0) - go h.Serve(l) - defer l.Close() - - client := &http.Client{Transport: &http.Transport{ - Dial: l.Dial, - }} - - // Init - _, err := pluginRequest(client, initPath, &InitRequest{Home: "foo"}) - if err != nil { - t.Fatal(err) - } - if p.init != 1 { - t.Fatalf("expected init 1, got %d", p.init) - } - - // Create - _, err = pluginRequest(client, createPath, &CreateRequest{ID: "foo", Parent: "bar"}) - if err != nil { - t.Fatal(err) - } - if p.create != 1 { - t.Fatalf("expected create 1, got %d", p.create) - } - - // CreateReadWrite - _, err = pluginRequest(client, createRWPath, &CreateRequest{ID: "foo", Parent: "bar", MountLabel: "toto"}) - if err != nil { - t.Fatal(err) - } - if p.createRW != 1 { - t.Fatalf("expected createReadWrite 1, got %d", p.createRW) - } - - // Remove - _, err = pluginRequest(client, removePath, RemoveRequest{ID: "foo"}) - if err != nil { - t.Fatal(err) - } - if p.remove != 1 { - t.Fatalf("expected remove 1, got %d", p.remove) - } - - // Get - resp, err := pluginRequest(client, getPath, GetRequest{ID: "foo", MountLabel: "bar"}) - if err != nil { - t.Fatal(err) - } - var gResp *GetResponse - if err := json.NewDecoder(resp).Decode(&gResp); err != nil { - t.Fatal(err) - } - if gResp.Dir != "baz" { - t.Fatalf("expected dir = 'baz', got %s", gResp.Dir) - } - if p.get != 1 { - t.Fatalf("expected get 1, got %d", p.get) - } - - // Put - _, err = pluginRequest(client, putPath, PutRequest{ID: "foo"}) - if err != nil { - t.Fatal(err) - } - if p.put != 1 { - t.Fatalf("expected put 1, got %d", p.put) - } - - // Exists - resp, err = pluginRequest(client, existsPath, ExistsRequest{ID: "foo"}) - if err != nil { - t.Fatal(err) - } - var eResp *ExistsResponse - if err := json.NewDecoder(resp).Decode(&eResp); err != nil { - t.Fatal(err) - } - if !eResp.Exists { - t.Fatalf("got error testing for existence of graph drivers: %v", eResp.Exists) - } - if p.exists != 1 { - t.Fatalf("expected exists 1, got %d", p.exists) - } - - // Status - resp, err = pluginRequest(client, statusPath, StatusRequest{}) - if err != nil { - t.Fatal(err) - } - var sResp *StatusResponse - if err := json.NewDecoder(resp).Decode(&sResp); err != nil { - t.Fatal(err) - } - if p.status != 1 { - t.Fatalf("expected get 1, got %d", p.status) - } - - // GetMetadata - resp, err = pluginRequest(client, getMetadataPath, GetMetadataRequest{ID: "foo"}) - if err != nil { - t.Fatal(err) - } - var gmResp *GetMetadataResponse - if err := json.NewDecoder(resp).Decode(&gmResp); err != nil { - t.Fatal(err) - } - if p.getMetadata != 1 { - t.Fatalf("expected getMetadata 1, got %d", p.getMetadata) - } - - // Cleanup - _, err = pluginRequest(client, cleanupPath, CleanupRequest{}) - if err != nil { - t.Fatal(err) - } - if p.cleanup != 1 { - t.Fatalf("expected cleanup 1, got %d", p.cleanup) - } - - // Diff - _, err = pluginRequest(client, diffPath, DiffRequest{ID: "foo", Parent: "bar"}) - if err != nil { - t.Fatal(err) - } - if p.diff != 1 { - t.Fatalf("expected diff 1, got %d", p.diff) - } - - // Changes - resp, err = pluginRequest(client, changesPath, ChangesRequest{ID: "foo", Parent: "bar"}) - if err != nil { - t.Fatal(err) - } - var cResp *ChangesResponse - if err := json.NewDecoder(resp).Decode(&cResp); err != nil { - t.Fatal(err) - } - if p.status != 1 { - t.Fatalf("expected get 1, got %d", p.get) - } - - // ApplyDiff - b := new(bytes.Buffer) - stream := bytes.NewReader(b.Bytes()) - resp, err = pluginRequest(client, applyDiffPath, &ApplyDiffRequest{ID: "foo", Parent: "bar", Stream: stream}) - if err != nil { - t.Fatal(err) - } - var adResp *ApplyDiffResponse - if err := json.NewDecoder(resp).Decode(&adResp); err != nil { - t.Fatal(err) - } - if p.status != 1 { - t.Fatalf("expected applyDiff 1, got %d", p.applyDiff) - } - - // DiffSize - resp, err = pluginRequest(client, diffSizePath, DiffSizeRequest{ID: "foo", Parent: "bar"}) - if err != nil { - t.Fatal(err) - } - var dsResp *DiffSizeResponse - if err := json.NewDecoder(resp).Decode(&dsResp); err != nil { - t.Fatal(err) - } - if p.diffSize != 1 { - t.Fatalf("expected diffSize 1, got %d", p.diffSize) - } - - // Capabilities - resp, err = pluginRequest(client, capabilitiesPath, CapabilitiesRequest{}) - if err != nil { - t.Fatal(err) - } - var caResp *CapabilitiesResponse - if err := json.NewDecoder(resp).Decode(&caResp); err != nil { - t.Fatal(err) - } - if caResp.Capabilities.ReproducesExactDiffs != true { - t.Fatalf("got error getting capabilities for graph drivers: %v", caResp.Capabilities) - } - if p.capabilities != 1 { - t.Fatalf("expected get 1, got %d", p.get) - } -} - -func pluginRequest(client *http.Client, method string, req interface{}) (io.Reader, error) { - b, err := json.Marshal(req) - if err != nil { - return nil, err - } - if req == nil { - b = []byte{} - } - resp, err := client.Post("http://localhost"+method, "application/json", bytes.NewReader(b)) - if err != nil { - return nil, err - } - - return resp.Body, nil -} - -type testPlugin struct { - init int - create int - createRW int - remove int - get int - put int - exists int - status int - getMetadata int - cleanup int - diff int - changes int - applyDiff int - diffSize int - capabilities int -} - -var _ Driver = &testPlugin{} - -func (p *testPlugin) Init(string, []string, []idtools.IDMap, []idtools.IDMap) error { - p.init++ - return nil -} - -func (p *testPlugin) Create(string, string, string, map[string]string) error { - p.create++ - return nil -} - -func (p *testPlugin) CreateReadWrite(string, string, string, map[string]string) error { - p.createRW++ - return nil -} - -func (p *testPlugin) Remove(string) error { - p.remove++ - return nil -} - -func (p *testPlugin) Get(string, string) (containerfs.ContainerFS, error) { - p.get++ - return containerfs.NewLocalContainerFS("baz"), nil -} - -func (p *testPlugin) Put(string) error { - p.put++ - return nil -} - -func (p *testPlugin) Exists(string) bool { - p.exists++ - return true -} - -func (p *testPlugin) Status() [][2]string { - p.status++ - return nil -} - -func (p *testPlugin) GetMetadata(string) (map[string]string, error) { - p.getMetadata++ - return nil, nil -} - -func (p *testPlugin) Cleanup() error { - p.cleanup++ - return nil -} - -func (p *testPlugin) Diff(string, string) io.ReadCloser { - p.diff++ - b := new(bytes.Buffer) - x := ioutil.NopCloser(bytes.NewReader(b.Bytes())) - return x -} - -func (p *testPlugin) Changes(string, string) ([]Change, error) { - p.changes++ - return nil, nil -} - -func (p *testPlugin) ApplyDiff(string, string, io.Reader) (int64, error) { - p.applyDiff++ - return 42, nil -} - -func (p *testPlugin) DiffSize(string, string) (int64, error) { - p.diffSize++ - return 42, nil -} - -func (p *testPlugin) Capabilities() graphDriver.Capabilities { - p.capabilities++ - return graphDriver.Capabilities{ReproducesExactDiffs: true} -} diff --git a/graphdriver/shim/shim.go b/graphdriver/shim/shim.go deleted file mode 100644 index bec1f59..0000000 --- a/graphdriver/shim/shim.go +++ /dev/null @@ -1,176 +0,0 @@ -package shim - -import ( - "errors" - "io" - "log" - - graphDriver "github.com/docker/docker/daemon/graphdriver" - "github.com/docker/docker/pkg/archive" - "github.com/docker/docker/pkg/containerfs" - "github.com/docker/docker/pkg/idtools" - graphPlugin "github.com/docker/go-plugins-helpers/graphdriver" -) - -type shimDriver struct { - driver graphDriver.Driver - init graphDriver.InitFunc -} - -// NewHandlerFromGraphDriver creates a plugin handler from an existing graph -// driver. This could be used, for instance, by the `overlayfs` graph driver -// 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 { - return graphPlugin.NewHandler(&shimDriver{driver: nil, init: init}) -} - -func (d *shimDriver) Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) error { - driver, err := d.init(home, options, uidMaps, gidMaps) - if err != nil { - return err - } - d.driver = driver - return nil -} - -var errNotInitialized = errors.New("Not initialized") - -func (d *shimDriver) Create(id, parent, mountLabel string, storageOpt map[string]string) error { - if d == nil { - return errNotInitialized - } - opts := graphDriver.CreateOpts{ - MountLabel: mountLabel, - StorageOpt: storageOpt, - } - return d.driver.Create(id, parent, &opts) -} - -func (d *shimDriver) CreateReadWrite(id, parent, mountLabel string, storageOpt map[string]string) error { - if d == nil { - return errNotInitialized - } - opts := graphDriver.CreateOpts{ - MountLabel: mountLabel, - StorageOpt: storageOpt, - } - return d.driver.CreateReadWrite(id, parent, &opts) -} - -func (d *shimDriver) Remove(id string) error { - if d == nil { - return errNotInitialized - } - return d.driver.Remove(id) -} - -func (d *shimDriver) Get(id, mountLabel string) (containerfs.ContainerFS, error) { - if d == nil { - return nil, errNotInitialized - } - return d.driver.Get(id, mountLabel) -} - -func (d *shimDriver) Put(id string) error { - if d == nil { - return errNotInitialized - } - return d.driver.Put(id) -} - -func (d *shimDriver) Exists(id string) bool { - if d == nil { - return false - } - return d.driver.Exists(id) -} - -func (d *shimDriver) Status() [][2]string { - if d == nil { - return nil - } - return d.driver.Status() -} - -func (d *shimDriver) GetMetadata(id string) (map[string]string, error) { - if d == nil { - return nil, errNotInitialized - } - return d.driver.GetMetadata(id) -} - -func (d *shimDriver) Cleanup() error { - if d == nil { - return errNotInitialized - } - return d.driver.Cleanup() -} - -func (d *shimDriver) Diff(id, parent string) io.ReadCloser { - if d == nil { - return nil - } - // FIXME(samoht): how do we pass the error to the driver? - archive, err := d.driver.Diff(id, parent) - if err != nil { - log.Fatalf("Diff: error in stream %v", err) - } - return archive -} - -func changeKind(c archive.ChangeType) graphPlugin.ChangeKind { - switch c { - case archive.ChangeModify: - return graphPlugin.Modified - case archive.ChangeAdd: - return graphPlugin.Added - case archive.ChangeDelete: - return graphPlugin.Deleted - } - return 0 -} - -func (d *shimDriver) Changes(id, parent string) ([]graphPlugin.Change, error) { - if d == nil { - return nil, errNotInitialized - } - cs, err := d.driver.Changes(id, parent) - if err != nil { - return nil, err - } - changes := make([]graphPlugin.Change, len(cs)) - for _, c := range cs { - change := graphPlugin.Change{ - Path: c.Path, - Kind: changeKind(c.Kind), - } - changes = append(changes, change) - } - return changes, nil -} - -func (d *shimDriver) ApplyDiff(id, parent string, archive io.Reader) (int64, error) { - if d == nil { - return 0, errNotInitialized - } - return d.driver.ApplyDiff(id, parent, archive) -} - -func (d *shimDriver) DiffSize(id, parent string) (int64, error) { - if d == nil { - return 0, errNotInitialized - } - return d.driver.DiffSize(id, parent) -} - -func (d *shimDriver) Capabilities() graphDriver.Capabilities { - if d == nil { - return graphDriver.Capabilities{} - } - if capDriver, ok := d.driver.(graphDriver.CapabilityDriver); ok { - return capDriver.Capabilities() - } - return graphDriver.Capabilities{} -} diff --git a/graphdriver/shim/shim_test.go b/graphdriver/shim/shim_test.go deleted file mode 100644 index 032301a..0000000 --- a/graphdriver/shim/shim_test.go +++ /dev/null @@ -1,98 +0,0 @@ -package shim - -import ( - "bytes" - "encoding/json" - "net/http" - "testing" - - "github.com/docker/docker/pkg/containerfs" - - "github.com/docker/docker/daemon/graphdriver" - "github.com/docker/docker/pkg/idtools" - "github.com/docker/go-connections/sockets" - graphPlugin "github.com/docker/go-plugins-helpers/graphdriver" -) - -type testGraphDriver struct{} - -// ProtoDriver -var _ graphdriver.ProtoDriver = &testGraphDriver{} - -func (t *testGraphDriver) String() string { - return "" -} - -// FIXME(samoht): this doesn't seem to be called by the plugins -func (t *testGraphDriver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error { - return nil -} -func (t *testGraphDriver) Create(id, parent string, opts *graphdriver.CreateOpts) error { - return nil -} -func (t *testGraphDriver) Remove(id string) error { - return nil -} -func (t *testGraphDriver) Get(id, mountLabel string) (dir containerfs.ContainerFS, err error) { - return containerfs.NewLocalContainerFS(""), nil -} -func (t *testGraphDriver) Put(id string) error { - return nil -} -func (t *testGraphDriver) Exists(id string) bool { - return false -} -func (t *testGraphDriver) Status() [][2]string { - return nil -} -func (t *testGraphDriver) GetMetadata(id string) (map[string]string, error) { - return nil, nil -} -func (t *testGraphDriver) Cleanup() error { - return nil -} -func (t *testGraphDriver) Capabilities() graphdriver.Capabilities { - return graphdriver.Capabilities{} -} - -func Init(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) { - d := graphdriver.NewNaiveDiffDriver(&testGraphDriver{}, uidMaps, gidMaps) - return d, nil -} - -func TestGraphDriver(t *testing.T) { - h := NewHandlerFromGraphDriver(Init) - l := sockets.NewInmemSocket("test", 0) - go h.Serve(l) - defer l.Close() - - client := &http.Client{Transport: &http.Transport{ - Dial: l.Dial, - }} - - resp, err := pluginRequest(client, "/GraphDriver.Init", &graphPlugin.InitRequest{Home: "foo"}) - if err != nil { - t.Fatal(err) - } - if resp.Err != "" { - t.Fatalf("error while creating GraphDriver: %v", err) - } -} - -func pluginRequest(client *http.Client, method string, req *graphPlugin.InitRequest) (*graphPlugin.ErrorResponse, error) { - b, err := json.Marshal(req) - if err != nil { - return nil, err - } - resp, err := client.Post("http://localhost"+method, "application/json", bytes.NewReader(b)) - if err != nil { - return nil, err - } - var gResp graphPlugin.ErrorResponse - err = json.NewDecoder(resp.Body).Decode(&gResp) - if err != nil { - return nil, err - } - - return &gResp, nil -} diff --git a/network/api_test.go b/network/api_test.go index 66281a9..6cfee7a 100644 --- a/network/api_test.go +++ b/network/api_test.go @@ -3,7 +3,7 @@ package network import ( "errors" "fmt" - "io/ioutil" + "io" "net/http" "os" "strings" @@ -142,7 +142,7 @@ func TestActivate(t *testing.T) { t.Fatal(err) } defer response.Body.Close() - body, err := ioutil.ReadAll(response.Body) + body, err := io.ReadAll(response.Body) if string(body) != manifest+"\n" { t.Fatalf("Expected %s, got %s\n", manifest+"\n", string(body)) @@ -155,7 +155,7 @@ func TestCapabilitiesExchange(t *testing.T) { t.Fatal(err) } defer response.Body.Close() - body, err := ioutil.ReadAll(response.Body) + body, err := io.ReadAll(response.Body) expected := `{"Scope":"local","ConnectivityScope":"global"}` if string(body) != expected+"\n" { @@ -174,7 +174,7 @@ func TestCreateNetworkSuccess(t *testing.T) { t.Fatal(err) } defer response.Body.Close() - body, err := ioutil.ReadAll(response.Body) + body, err := io.ReadAll(response.Body) if response.StatusCode != http.StatusOK { t.Fatalf("Expected 200, got %d\n", response.StatusCode) @@ -193,7 +193,7 @@ func TestCreateNetworkError(t *testing.T) { t.Fatal(err) } defer response.Body.Close() - body, err := ioutil.ReadAll(response.Body) + body, err := io.ReadAll(response.Body) if response.StatusCode != http.StatusInternalServerError { t.Fatalf("Expected 500, got %d\n", response.StatusCode) @@ -214,7 +214,7 @@ func TestProgramExternalConnectivity(t *testing.T) { defer response.Body.Close() if response.StatusCode != http.StatusOK { - body, _ := ioutil.ReadAll(response.Body) + body, _ := io.ReadAll(response.Body) t.Fatalf("Expected %d, got %d: %s\n", http.StatusOK, response.StatusCode, string(body)) } } diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go deleted file mode 100644 index b157c69..0000000 --- a/sdk/sdk_test.go +++ /dev/null @@ -1,7 +0,0 @@ -package sdk - -import "testing" - -func TestTrue(t *testing.T) { - // FIXME: Add tests -} diff --git a/sdk/spec_file_generator.go b/sdk/spec_file_generator.go index bc8cfc6..c9cdbb2 100644 --- a/sdk/spec_file_generator.go +++ b/sdk/spec_file_generator.go @@ -2,7 +2,6 @@ package sdk import ( "fmt" - "io/ioutil" "os" "path/filepath" ) @@ -50,7 +49,7 @@ func writeSpecFile(name, address, pluginSpecDir string, proto protocol) (string, specFileDir := filepath.Join(pluginSpecDir, name+".spec") url := string(proto) + "://" + address - if err := ioutil.WriteFile(specFileDir, []byte(url), 0644); err != nil { + if err := os.WriteFile(specFileDir, []byte(url), 0644); err != nil { return "", err } diff --git a/sdk/unix_listener.go b/sdk/unix_listener.go index 54b9a6d..00bc911 100644 --- a/sdk/unix_listener.go +++ b/sdk/unix_listener.go @@ -1,4 +1,4 @@ -// +build linux freebsd +//go:build linux || freebsd package sdk diff --git a/sdk/unix_listener_nosystemd.go b/sdk/unix_listener_nosystemd.go index a798b87..1a9247b 100644 --- a/sdk/unix_listener_nosystemd.go +++ b/sdk/unix_listener_nosystemd.go @@ -1,10 +1,10 @@ -// +build linux freebsd -// +build nosystemd +//go:build (linux || freebsd) && nosystemd package sdk import "net" +// FIXME(thaJeztah): this code was added in https://github.com/docker/go-plugins-helpers/commit/008703b825c10311af1840deeaf5f4769df7b59e, but is not used anywhere func setupSocketActivation() (net.Listener, error) { return nil, nil } diff --git a/sdk/unix_listener_systemd.go b/sdk/unix_listener_systemd.go index 5d5d8f4..59c53bf 100644 --- a/sdk/unix_listener_systemd.go +++ b/sdk/unix_listener_systemd.go @@ -1,5 +1,4 @@ -// +build linux freebsd -// +build !nosystemd +//go:build (linux || freebsd) && !nosystemd package sdk @@ -25,6 +24,7 @@ func isRunningSystemd() bool { return fi.IsDir() } +// FIXME(thaJeztah): this code was added in https://github.com/docker/go-plugins-helpers/commit/008703b825c10311af1840deeaf5f4769df7b59e, but is not used anywhere func setupSocketActivation() (net.Listener, error) { if !isRunningSystemd() { return nil, nil diff --git a/sdk/unix_listener_unsupported.go b/sdk/unix_listener_unsupported.go index 344cf75..a472f06 100644 --- a/sdk/unix_listener_unsupported.go +++ b/sdk/unix_listener_unsupported.go @@ -1,4 +1,4 @@ -// +build !linux,!freebsd +//go:build !linux && !freebsd package sdk @@ -7,10 +7,6 @@ import ( "net" ) -var ( - errOnlySupportedOnLinuxAndFreeBSD = errors.New("unix socket creation is only supported on Linux and FreeBSD") -) - func newUnixListener(pluginName string, gid int) (net.Listener, string, error) { - return nil, "", errOnlySupportedOnLinuxAndFreeBSD + return nil, "", errors.New("unix socket creation is only supported on Linux and FreeBSD") } diff --git a/sdk/windows_listener.go b/sdk/windows_listener.go index b5deaba..afb0f0b 100644 --- a/sdk/windows_listener.go +++ b/sdk/windows_listener.go @@ -1,4 +1,4 @@ -// +build windows +//go:build windows package sdk @@ -14,20 +14,19 @@ import ( // Named pipes use Windows Security Descriptor Definition Language to define ACL. Following are // some useful definitions. const ( - // This will set permissions for everyone to have full access + // AllowEveryone grants full access permissions for everyone. AllowEveryone = "S:(ML;;NW;;;LW)D:(A;;0x12019f;;;WD)" - // This will set permissions for Service, System, Adminstrator group and account to have full access + // AllowServiceSystemAdmin grants full access permissions for Service, System, Administrator group and account. AllowServiceSystemAdmin = "D:(A;ID;FA;;;SY)(A;ID;FA;;;BA)(A;ID;FA;;;LA)(A;ID;FA;;;LS)" ) func newWindowsListener(address, pluginName, daemonRoot string, pipeConfig *WindowsPipeConfig) (net.Listener, string, error) { - winioPipeConfig := winio.PipeConfig{ + listener, err := winio.ListenPipe(address, &winio.PipeConfig{ SecurityDescriptor: pipeConfig.SecurityDescriptor, InputBufferSize: pipeConfig.InBufferSize, OutputBufferSize: pipeConfig.OutBufferSize, - } - listener, err := winio.ListenPipe(address, &winioPipeConfig) + }) if err != nil { return nil, "", err } @@ -48,7 +47,7 @@ func newWindowsListener(address, pluginName, daemonRoot string, pipeConfig *Wind func windowsCreateDirectoryWithACL(name string) error { sa := syscall.SecurityAttributes{Length: 0} - sddl := "D:P(A;OICI;GA;;;BA)(A;OICI;GA;;;SY)" + const sddl = "D:P(A;OICI;GA;;;BA)(A;OICI;GA;;;SY)" sd, err := winio.SddlToSecurityDescriptor(sddl) if err != nil { return &os.PathError{Op: "mkdir", Path: name, Err: err} diff --git a/sdk/windows_listener_unsupported.go b/sdk/windows_listener_unsupported.go index 0f5e113..1b187d0 100644 --- a/sdk/windows_listener_unsupported.go +++ b/sdk/windows_listener_unsupported.go @@ -1,4 +1,4 @@ -// +build !windows +//go:build !windows package sdk @@ -7,12 +7,8 @@ import ( "net" ) -var ( - errOnlySupportedOnWindows = errors.New("named pipe creation is only supported on Windows") -) - func newWindowsListener(address, pluginName, daemonRoot string, pipeConfig *WindowsPipeConfig) (net.Listener, string, error) { - return nil, "", errOnlySupportedOnWindows + return nil, "", errors.New("named pipe creation is only supported on Windows") } func windowsCreateDirectoryWithACL(name string) error { diff --git a/volume/shim/shim.go b/volume/shim/shim.go index 197d9b4..0dec1a1 100644 --- a/volume/shim/shim.go +++ b/volume/shim/shim.go @@ -12,7 +12,7 @@ type shimDriver struct { // NewHandlerFromVolumeDriver creates a plugin handler from an existing volume // driver. This could be used, for instance, by the `local` volume driver 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 volume.Driver interface from +// directly to any volume driver that satisfies the volume.Driver interface from // Docker Engine. func NewHandlerFromVolumeDriver(d volume.Driver) *volumeplugin.Handler { return volumeplugin.NewHandler(&shimDriver{d}) diff --git a/volume/shim/shim_test.go b/volume/shim/shim_test.go index 7a3c3f1..bb765fb 100644 --- a/volume/shim/shim_test.go +++ b/volume/shim/shim_test.go @@ -12,13 +12,6 @@ import ( ) type testVolumeDriver struct{} -type testVolume struct{} - -func (testVolume) Name() string { return "" } -func (testVolume) Path() string { return "" } -func (testVolume) Mount() (string, error) { return "", nil } -func (testVolume) Unmount() error { return nil } -func (testVolume) DriverName() string { return "" } func (testVolumeDriver) Name() string { return "" } func (testVolumeDriver) Create(string, map[string]string) (volume.Volume, error) { return nil, nil }