From 7e14fbfa27350b217929cf34076aa323273d0bb2 Mon Sep 17 00:00:00 2001 From: Georg Seibt Date: Mon, 29 Jun 2020 23:46:49 +0200 Subject: [PATCH 1/4] Store a reference to http.Server in the Handler - Add a Shutdown method - Implement ServeXYZ methods on *Handler, adjust plugin Handlers --- authorization/api.go | 2 +- graphdriver/api.go | 2 +- ipam/api.go | 2 +- network/api.go | 2 +- sdk/handler.go | 23 ++++++++++++++++------- secrets/api.go | 2 +- volume/api.go | 2 +- 7 files changed, 22 insertions(+), 13 deletions(-) diff --git a/authorization/api.go b/authorization/api.go index 7e157f7..b10771c 100644 --- a/authorization/api.go +++ b/authorization/api.go @@ -108,7 +108,7 @@ type Handler struct { // NewHandler initializes the request handler with a plugin implementation. func NewHandler(plugin Plugin) *Handler { - h := &Handler{plugin, sdk.NewHandler(manifest)} + h := &Handler{plugin, *sdk.NewHandler(manifest)} h.initMux() return h } diff --git a/graphdriver/api.go b/graphdriver/api.go index 193f77a..c394f74 100644 --- a/graphdriver/api.go +++ b/graphdriver/api.go @@ -236,7 +236,7 @@ type Handler struct { // NewHandler initializes the request handler with a driver implementation. func NewHandler(driver Driver) *Handler { - h := &Handler{driver, sdk.NewHandler(manifest)} + h := &Handler{driver, *sdk.NewHandler(manifest)} h.initMux() return h } diff --git a/ipam/api.go b/ipam/api.go index 7ebc906..678b82a 100644 --- a/ipam/api.go +++ b/ipam/api.go @@ -96,7 +96,7 @@ type Handler struct { // NewHandler initializes the request handler with a driver implementation. func NewHandler(ipam Ipam) *Handler { - h := &Handler{ipam, sdk.NewHandler(manifest)} + h := &Handler{ipam, *sdk.NewHandler(manifest)} h.initMux() return h } diff --git a/network/api.go b/network/api.go index a3c4396..33d22df 100644 --- a/network/api.go +++ b/network/api.go @@ -214,7 +214,7 @@ type Handler struct { // NewHandler initializes the request handler with a driver implementation. func NewHandler(driver Driver) *Handler { - h := &Handler{driver, sdk.NewHandler(manifest)} + h := &Handler{driver, *sdk.NewHandler(manifest)} h.initMux() return h } diff --git a/sdk/handler.go b/sdk/handler.go index c0d042e..7baaa01 100644 --- a/sdk/handler.go +++ b/sdk/handler.go @@ -1,6 +1,7 @@ package sdk import ( + "context" "crypto/tls" "fmt" "net" @@ -14,10 +15,11 @@ const activatePath = "/Plugin.Activate" // It initializes connections and sockets to listen to. type Handler struct { mux *http.ServeMux + server *http.Server } // NewHandler creates a new Handler with an http mux. -func NewHandler(manifest string) Handler { +func NewHandler(manifest string) *Handler { mux := http.NewServeMux() mux.HandleFunc(activatePath, func(w http.ResponseWriter, r *http.Request) { @@ -25,24 +27,31 @@ func NewHandler(manifest string) Handler { fmt.Fprintln(w, manifest) }) - return Handler{mux: mux} + return &Handler{mux: mux} } // Serve sets up the handler to serve requests on the passed in listener -func (h Handler) Serve(l net.Listener) error { +func (h *Handler) Serve(l net.Listener) error { server := http.Server{ Addr: l.Addr().String(), Handler: h.mux, } + + h.server = &server return server.Serve(l) } +// Gracefully shuts down the http.Server serving requests +func (h *Handler) Shutdown(c context.Context) error { + return h.server.Shutdown(c) +} + // ServeTCP makes the handler to listen for request in a given TCP address. // It also writes the spec file in the right directory for docker to read. // Due to constrains for running Docker in Docker on Windows, data-root directory // of docker daemon must be provided. To get default directory, use // WindowsDefaultDaemonRootDir() function. On Unix, this parameter is ignored. -func (h Handler) ServeTCP(pluginName, addr, daemonDir string, tlsConfig *tls.Config) error { +func (h *Handler) ServeTCP(pluginName, addr, daemonDir string, tlsConfig *tls.Config) error { l, spec, err := newTCPListener(addr, pluginName, daemonDir, tlsConfig) if err != nil { return err @@ -55,7 +64,7 @@ func (h Handler) ServeTCP(pluginName, addr, daemonDir string, tlsConfig *tls.Con // ServeUnix makes the handler to listen for requests in a unix socket. // It also creates the socket file in the right directory for docker to read. -func (h Handler) ServeUnix(addr string, gid int) error { +func (h *Handler) ServeUnix(addr string, gid int) error { l, spec, err := newUnixListener(addr, gid) if err != nil { return err @@ -71,7 +80,7 @@ func (h Handler) ServeUnix(addr string, gid int) error { // Due to constrains for running Docker in Docker on Windows, data-root directory // of docker daemon must be provided. To get default directory, use // WindowsDefaultDaemonRootDir() function. On Unix, this parameter is ignored. -func (h Handler) ServeWindows(addr, pluginName, daemonDir string, pipeConfig *WindowsPipeConfig) error { +func (h *Handler) ServeWindows(addr, pluginName, daemonDir string, pipeConfig *WindowsPipeConfig) error { l, spec, err := newWindowsListener(addr, pluginName, daemonDir, pipeConfig) if err != nil { return err @@ -83,6 +92,6 @@ func (h Handler) ServeWindows(addr, pluginName, daemonDir string, pipeConfig *Wi } // HandleFunc registers a function to handle a request path with. -func (h Handler) HandleFunc(path string, fn func(w http.ResponseWriter, r *http.Request)) { +func (h *Handler) HandleFunc(path string, fn func(w http.ResponseWriter, r *http.Request)) { h.mux.HandleFunc(path, fn) } diff --git a/secrets/api.go b/secrets/api.go index e05fd38..2c5c797 100644 --- a/secrets/api.go +++ b/secrets/api.go @@ -68,7 +68,7 @@ type Handler struct { // NewHandler initializes the request handler with a driver implementation. func NewHandler(driver Driver) *Handler { - h := &Handler{driver, sdk.NewHandler(manifest)} + h := &Handler{driver, *sdk.NewHandler(manifest)} h.initMux() return h } diff --git a/volume/api.go b/volume/api.go index dcc2f3a..f2df941 100644 --- a/volume/api.go +++ b/volume/api.go @@ -123,7 +123,7 @@ type Handler struct { // NewHandler initializes the request handler with a driver implementation. func NewHandler(driver Driver) *Handler { - h := &Handler{driver, sdk.NewHandler(manifest)} + h := &Handler{driver, *sdk.NewHandler(manifest)} h.initMux() return h } From b0dc75eeb8e2a9bd4ff0aca712d86de8af3e65b3 Mon Sep 17 00:00:00 2001 From: Georg Seibt Date: Mon, 29 Jun 2020 23:48:03 +0200 Subject: [PATCH 2/4] Export NewXYZListener methods so Handler.Serve(Listener) can be used easily --- sdk/handler.go | 8 ++++---- sdk/tcp_listener.go | 2 +- sdk/unix_listener.go | 2 +- sdk/windows_listener_unsupported.go | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/sdk/handler.go b/sdk/handler.go index 7baaa01..7e02872 100644 --- a/sdk/handler.go +++ b/sdk/handler.go @@ -36,7 +36,7 @@ func (h *Handler) Serve(l net.Listener) error { Addr: l.Addr().String(), Handler: h.mux, } - + h.server = &server return server.Serve(l) } @@ -52,7 +52,7 @@ func (h *Handler) Shutdown(c context.Context) error { // of docker daemon must be provided. To get default directory, use // WindowsDefaultDaemonRootDir() function. On Unix, this parameter is ignored. func (h *Handler) ServeTCP(pluginName, addr, daemonDir string, tlsConfig *tls.Config) error { - l, spec, err := newTCPListener(addr, pluginName, daemonDir, tlsConfig) + l, spec, err := NewTCPListener(addr, pluginName, daemonDir, tlsConfig) if err != nil { return err } @@ -65,7 +65,7 @@ func (h *Handler) ServeTCP(pluginName, addr, daemonDir string, tlsConfig *tls.Co // ServeUnix makes the handler to listen for requests in a unix socket. // It also creates the socket file in the right directory for docker to read. func (h *Handler) ServeUnix(addr string, gid int) error { - l, spec, err := newUnixListener(addr, gid) + l, spec, err := NewUnixListener(addr, gid) if err != nil { return err } @@ -81,7 +81,7 @@ func (h *Handler) ServeUnix(addr string, gid int) error { // of docker daemon must be provided. To get default directory, use // WindowsDefaultDaemonRootDir() function. On Unix, this parameter is ignored. func (h *Handler) ServeWindows(addr, pluginName, daemonDir string, pipeConfig *WindowsPipeConfig) error { - l, spec, err := newWindowsListener(addr, pluginName, daemonDir, pipeConfig) + l, spec, err := NewWindowsListener(addr, pluginName, daemonDir, pipeConfig) if err != nil { return err } diff --git a/sdk/tcp_listener.go b/sdk/tcp_listener.go index bad85f7..3642477 100644 --- a/sdk/tcp_listener.go +++ b/sdk/tcp_listener.go @@ -8,7 +8,7 @@ import ( "github.com/docker/go-connections/sockets" ) -func newTCPListener(address, pluginName, daemonDir string, tlsConfig *tls.Config) (net.Listener, string, error) { +func NewTCPListener(address, pluginName, daemonDir string, tlsConfig *tls.Config) (net.Listener, string, error) { listener, err := sockets.NewTCPSocket(address, tlsConfig) if err != nil { return nil, "", err diff --git a/sdk/unix_listener.go b/sdk/unix_listener.go index 54b9a6d..1ece0d0 100644 --- a/sdk/unix_listener.go +++ b/sdk/unix_listener.go @@ -12,7 +12,7 @@ import ( const pluginSockDir = "/run/docker/plugins" -func newUnixListener(pluginName string, gid int) (net.Listener, string, error) { +func NewUnixListener(pluginName string, gid int) (net.Listener, string, error) { path, err := fullSocketAddress(pluginName) if err != nil { return nil, "", err diff --git a/sdk/windows_listener_unsupported.go b/sdk/windows_listener_unsupported.go index 0f5e113..a85767d 100644 --- a/sdk/windows_listener_unsupported.go +++ b/sdk/windows_listener_unsupported.go @@ -11,7 +11,7 @@ var ( errOnlySupportedOnWindows = errors.New("named pipe creation is only supported on Windows") ) -func newWindowsListener(address, pluginName, daemonRoot string, pipeConfig *WindowsPipeConfig) (net.Listener, string, error) { +func NewWindowsListener(address, pluginName, daemonRoot string, pipeConfig *WindowsPipeConfig) (net.Listener, string, error) { return nil, "", errOnlySupportedOnWindows } From f7b43520a9ec9d9701a2159287026ff6175b0e4a Mon Sep 17 00:00:00 2001 From: Georg Seibt Date: Wed, 1 Jul 2020 14:23:18 +0200 Subject: [PATCH 3/4] Formatting --- sdk/handler.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/handler.go b/sdk/handler.go index 7e02872..1865ac3 100644 --- a/sdk/handler.go +++ b/sdk/handler.go @@ -14,7 +14,7 @@ const activatePath = "/Plugin.Activate" // Handler is the base to create plugin handlers. // It initializes connections and sockets to listen to. type Handler struct { - mux *http.ServeMux + mux *http.ServeMux server *http.Server } From a0ff4b19988f52910dbad9db8615b0b3f3a6be70 Mon Sep 17 00:00:00 2001 From: Georg Seibt Date: Wed, 1 Jul 2020 15:03:07 +0200 Subject: [PATCH 4/4] Add documentation --- sdk/handler.go | 3 ++- sdk/tcp_listener.go | 6 ++++++ sdk/unix_listener.go | 2 ++ sdk/windows_listener_unsupported.go | 6 ++++++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/sdk/handler.go b/sdk/handler.go index 1865ac3..81a550f 100644 --- a/sdk/handler.go +++ b/sdk/handler.go @@ -41,7 +41,8 @@ func (h *Handler) Serve(l net.Listener) error { return server.Serve(l) } -// Gracefully shuts down the http.Server serving requests +// Shutdown gracefully shuts down the http.Server serving requests after Serve or +// Serve{TCP,Unix,Windows} was called. func (h *Handler) Shutdown(c context.Context) error { return h.server.Shutdown(c) } diff --git a/sdk/tcp_listener.go b/sdk/tcp_listener.go index 3642477..047c4b8 100644 --- a/sdk/tcp_listener.go +++ b/sdk/tcp_listener.go @@ -8,6 +8,12 @@ import ( "github.com/docker/go-connections/sockets" ) +// NewTCPListener constructs a net.Listener to use for serving requests at the given TCP address. +// It also writes the spec file in the right directory for docker to read. +// +// Due to constrains for running Docker in Docker on Windows, data-root directory +// of docker daemon must be provided. To get default directory, use +// WindowsDefaultDaemonRootDir() function. On Unix, this parameter is ignored. func NewTCPListener(address, pluginName, daemonDir string, tlsConfig *tls.Config) (net.Listener, string, error) { listener, err := sockets.NewTCPSocket(address, tlsConfig) if err != nil { diff --git a/sdk/unix_listener.go b/sdk/unix_listener.go index 1ece0d0..96457c4 100644 --- a/sdk/unix_listener.go +++ b/sdk/unix_listener.go @@ -12,6 +12,8 @@ import ( const pluginSockDir = "/run/docker/plugins" +// NewUnixListener constructs a net.Listener to use for serving requests at the given unix socket. +// It also creates the socket file in the right directory for docker to read. func NewUnixListener(pluginName string, gid int) (net.Listener, string, error) { path, err := fullSocketAddress(pluginName) if err != nil { diff --git a/sdk/windows_listener_unsupported.go b/sdk/windows_listener_unsupported.go index a85767d..b319b35 100644 --- a/sdk/windows_listener_unsupported.go +++ b/sdk/windows_listener_unsupported.go @@ -11,6 +11,12 @@ var ( errOnlySupportedOnWindows = errors.New("named pipe creation is only supported on Windows") ) +// NewWindowsListener constructs a net.Listener to use for serving requests at the given Windows named pipe. +// It also creates the spec file in the right directory for docker to read. +// +// Due to constrains for running Docker in Docker on Windows, the data-root directory +// of docker daemon must be provided. To get default directory, use +// WindowsDefaultDaemonRootDir() function. On Unix, this parameter is ignored. func NewWindowsListener(address, pluginName, daemonRoot string, pipeConfig *WindowsPipeConfig) (net.Listener, string, error) { return nil, "", errOnlySupportedOnWindows }