1- package volumeapi
1+ package dkv
22
33import (
44 "encoding/json"
55 "fmt"
6+ "io/ioutil"
67 "net"
78 "net/http"
9+ "os"
10+ "path/filepath"
811)
912
1013const (
11- DefaultDockerRootDirectory = "/var/lib/docker/volumes"
14+ // DefaultDockerRootDirectory is the default directory where volumes will be created.
15+ DefaultDockerRootDirectory = "/var/lib/docker/volumes"
16+
1217 defaultContentTypeV1 = "appplication/vnd.docker.plugins.v1+json"
1318 defaultImplementationManifest = `{"Implements": ["VolumeDriver"]}`
19+ pluginSpecDir = "/usr/share/docker/plugins"
1420
1521 activatePath = "/Plugin.Activate"
1622 createPath = "/VolumeDriver.Create"
@@ -20,64 +26,69 @@ const (
2026 unmountPath = "/VolumeDriver.Unmount"
2127)
2228
23- type VolumeRequest struct {
29+ // Request is the structure that docker's requests are deserialized to.
30+ type Request struct {
2431 Name string
2532}
2633
27- type VolumeResponse struct {
34+ // Response is the strucutre that the plugin's responses are serialized to.
35+ type Response struct {
2836 Mountpoint string
2937 Err string
3038}
3139
32- type VolumeDriver interface {
33- Create (VolumeRequest ) VolumeResponse
34- Remove (VolumeRequest ) VolumeResponse
35- Path (VolumeRequest ) VolumeResponse
36- Mount (VolumeRequest ) VolumeResponse
37- Unmount (VolumeRequest ) VolumeResponse
40+ // Driver represent the interface a driver must fulfill.
41+ type Driver interface {
42+ Create (Request ) Response
43+ Remove (Request ) Response
44+ Path (Request ) Response
45+ Mount (Request ) Response
46+ Unmount (Request ) Response
3847}
3948
40- type VolumeHandler struct {
41- handler VolumeDriver
42- mux * http.ServeMux
49+ // Handler forwards requests and responses between the docker daemon and the plugin.
50+ type Handler struct {
51+ driver Driver
52+ mux * http.ServeMux
4353}
4454
45- type actionHandler func (VolumeRequest ) VolumeResponse
55+ type actionHandler func (Request ) Response
4656
47- func NewVolumeHandler (handler VolumeDriver ) * VolumeHandler {
48- h := & VolumeHandler {handler , http .NewServeMux ()}
57+ // NewHandler initializes the request handler with a driver implementation.
58+ func NewHandler (driver Driver ) * Handler {
59+ h := & Handler {driver , http .NewServeMux ()}
4960 h .initMux ()
5061 return h
5162}
5263
53- func (h * VolumeHandler ) initMux () {
64+ func (h * Handler ) initMux () {
5465 h .mux .HandleFunc (activatePath , func (w http.ResponseWriter , r * http.Request ) {
5566 w .Header ().Set ("Content-Type" , defaultContentTypeV1 )
5667 fmt .Fprintln (w , defaultImplementationManifest )
5768 })
5869
59- h .handle (createPath , func (req VolumeRequest ) VolumeResponse {
60- return h .handler .Create (req )
70+ h .handle (createPath , func (req Request ) Response {
71+ return h .driver .Create (req )
6172 })
6273
63- h .handle (remotePath , func (req VolumeRequest ) VolumeResponse {
64- return h .handler .Remove (req )
74+ h .handle (remotePath , func (req Request ) Response {
75+ return h .driver .Remove (req )
6576 })
6677
67- h .handle (hostVirtualPath , func (req VolumeRequest ) VolumeResponse {
68- return h .handler .Path (req )
78+ h .handle (hostVirtualPath , func (req Request ) Response {
79+ return h .driver .Path (req )
6980 })
7081
71- h .handle (mountPath , func (req VolumeRequest ) VolumeResponse {
72- return h .handler .Mount (req )
82+ h .handle (mountPath , func (req Request ) Response {
83+ return h .driver .Mount (req )
7384 })
7485
75- h .handle (unmountPath , func (req VolumeRequest ) VolumeResponse {
76- return h .handler .Unmount (req )
86+ h .handle (unmountPath , func (req Request ) Response {
87+ return h .driver .Unmount (req )
7788 })
7889}
7990
80- func (h * VolumeHandler ) handle (name string , actionCall actionHandler ) {
91+ func (h * Handler ) handle (name string , actionCall actionHandler ) {
8192 h .mux .HandleFunc (name , func (w http.ResponseWriter , r * http.Request ) {
8293 req , err := decodeRequest (w , r )
8394 if err != nil {
@@ -90,7 +101,19 @@ func (h *VolumeHandler) handle(name string, actionCall actionHandler) {
90101 })
91102}
92103
93- func (h * VolumeHandler ) ListenAndServe (proto , addr , group string ) error {
104+ // ServeTCP makes the handler to listen for request in a given TCP address.
105+ // It also writes the spec file on the right directory for docker to read.
106+ func (h * Handler ) ServeTCP (pluginName , addr string ) error {
107+ return h .listenAndServe ("tcp" , addr , pluginName )
108+ }
109+
110+ // ServeUnix makes the handler to listen for requests in a unix socket.
111+ // It also creates the socket file on the right directory for docker to read.
112+ func (h * Handler ) ServeUnix (systemGroup , addr string ) error {
113+ return h .listenAndServe ("unix" , addr , systemGroup )
114+ }
115+
116+ func (h * Handler ) listenAndServe (proto , addr , group string ) error {
94117 server := http.Server {
95118 Addr : addr ,
96119 Handler : h .mux ,
@@ -102,7 +125,10 @@ func (h *VolumeHandler) ListenAndServe(proto, addr, group string) error {
102125 var err error
103126 switch proto {
104127 case "tcp" :
105- l , err = newTcpSocket (addr , nil , start )
128+ l , err = newTCPSocket (addr , nil , start )
129+ if err == nil {
130+ err = writeSpec (group , l .Addr ().String ())
131+ }
106132 case "unix" :
107133 l , err = newUnixSocket (addr , group , start )
108134 }
@@ -114,17 +140,27 @@ func (h *VolumeHandler) ListenAndServe(proto, addr, group string) error {
114140 return server .Serve (l )
115141}
116142
117- func decodeRequest (w http.ResponseWriter , r * http.Request ) (req VolumeRequest , err error ) {
143+ func decodeRequest (w http.ResponseWriter , r * http.Request ) (req Request , err error ) {
118144 if err = json .NewDecoder (r .Body ).Decode (& req ); err != nil {
119145 http .Error (w , err .Error (), http .StatusBadRequest )
120146 }
121147 return
122148}
123149
124- func encodeResponse (w http.ResponseWriter , res VolumeResponse ) {
150+ func encodeResponse (w http.ResponseWriter , res Response ) {
125151 w .Header ().Set ("Content-Type" , defaultContentTypeV1 )
126152 if res .Err != "" {
127153 w .WriteHeader (http .StatusInternalServerError )
128154 }
129155 json .NewEncoder (w ).Encode (res )
130156}
157+
158+ func writeSpec (name , addr string ) error {
159+ if err := os .MkdirAll (pluginSpecDir , 0755 ); err != nil {
160+ return err
161+ }
162+
163+ spec := filepath .Join (pluginSpecDir , name + ".spec" )
164+ url := "tcp://" + addr
165+ return ioutil .WriteFile (spec , []byte (url ), 0644 )
166+ }
0 commit comments