serve.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. package docker
  2. import (
  3. "context"
  4. "crypto/tls"
  5. "fmt"
  6. "net"
  7. "net/http"
  8. "os"
  9. "path/filepath"
  10. "runtime"
  11. "github.com/rclone/rclone/fs"
  12. "github.com/rclone/rclone/lib/atexit"
  13. "github.com/rclone/rclone/lib/file"
  14. )
  15. // Server connects plugin with docker daemon by protocol
  16. type Server http.Server
  17. // NewServer creates new docker plugin server
  18. func NewServer(drv *Driver) *Server {
  19. return &Server{Handler: newRouter(drv)}
  20. }
  21. // Shutdown the server
  22. func (s *Server) Shutdown(ctx context.Context) error {
  23. hs := (*http.Server)(s)
  24. return hs.Shutdown(ctx)
  25. }
  26. func (s *Server) serve(listener net.Listener, addr, tempFile string) error {
  27. if tempFile != "" {
  28. atexit.Register(func() {
  29. // remove spec file or self-created unix socket
  30. fs.Debugf(nil, "Removing stale file %s", tempFile)
  31. _ = os.Remove(tempFile)
  32. })
  33. }
  34. hs := (*http.Server)(s)
  35. return hs.Serve(listener)
  36. }
  37. // ServeUnix makes the handler to listen for requests in a unix socket.
  38. // It also creates the socket file in the right directory for docker to read.
  39. func (s *Server) ServeUnix(path string, gid int) error {
  40. listener, socketPath, err := newUnixListener(path, gid)
  41. if err != nil {
  42. return err
  43. }
  44. if socketPath != "" {
  45. path = socketPath
  46. fs.Infof(nil, "Serving unix socket: %s", path)
  47. } else {
  48. fs.Infof(nil, "Serving systemd socket")
  49. }
  50. return s.serve(listener, path, socketPath)
  51. }
  52. // ServeTCP makes the handler listen for request on a given TCP address.
  53. // It also writes the spec file in the right directory for docker to read.
  54. func (s *Server) ServeTCP(addr, specDir string, tlsConfig *tls.Config, noSpec bool) error {
  55. listener, err := net.Listen("tcp", addr)
  56. if err != nil {
  57. return err
  58. }
  59. if tlsConfig != nil {
  60. tlsConfig.NextProtos = []string{"http/1.1"}
  61. listener = tls.NewListener(listener, tlsConfig)
  62. }
  63. addr = listener.Addr().String()
  64. specFile := ""
  65. if !noSpec {
  66. specFile, err = writeSpecFile(addr, "tcp", specDir)
  67. if err != nil {
  68. return err
  69. }
  70. }
  71. fs.Infof(nil, "Serving TCP socket: %s", addr)
  72. return s.serve(listener, addr, specFile)
  73. }
  74. func writeSpecFile(addr, proto, specDir string) (string, error) {
  75. if specDir == "" && runtime.GOOS == "windows" {
  76. specDir = os.TempDir()
  77. }
  78. if specDir == "" {
  79. specDir = defSpecDir
  80. }
  81. if err := file.MkdirAll(specDir, 0755); err != nil {
  82. return "", err
  83. }
  84. specFile := filepath.Join(specDir, "rclone.spec")
  85. url := fmt.Sprintf("%s://%s", proto, addr)
  86. if err := os.WriteFile(specFile, []byte(url), 0644); err != nil {
  87. return "", err
  88. }
  89. fs.Debugf(nil, "Plugin spec has been written to %s", specFile)
  90. return specFile, nil
  91. }