daemon_linux_test.go 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package main
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "os"
  7. "strconv"
  8. "testing"
  9. "github.com/docker/docker/daemon/config"
  10. "github.com/docker/docker/pkg/reexec"
  11. "golang.org/x/sys/unix"
  12. "gotest.tools/v3/assert"
  13. )
  14. const (
  15. testListenerNoAddrCmdPhase1 = "test-listener-no-addr1"
  16. testListenerNoAddrCmdPhase2 = "test-listener-no-addr2"
  17. )
  18. type listenerTestResponse struct {
  19. Err string
  20. }
  21. func initListenerTestPhase1() {
  22. os.Setenv("LISTEN_PID", strconv.Itoa(os.Getpid()))
  23. os.Setenv("LISTEN_FDS", "1")
  24. // NOTE: We cannot use O_CLOEXEC here because we need the fd to stay open for the child process.
  25. _, err := unix.Socket(unix.AF_UNIX, unix.SOCK_STREAM, 0)
  26. if err != nil {
  27. fmt.Fprintln(os.Stderr, err)
  28. os.Exit(1)
  29. }
  30. cmd := reexec.Command(testListenerNoAddrCmdPhase2)
  31. if err := unix.Exec(cmd.Path, cmd.Args, os.Environ()); err != nil {
  32. fmt.Fprintln(os.Stderr, err)
  33. os.Exit(1)
  34. }
  35. }
  36. func initListenerTestPhase2() {
  37. cfg := &config.Config{
  38. CommonConfig: config.CommonConfig{
  39. Hosts: []string{"fd://"},
  40. },
  41. }
  42. _, _, err := loadListeners(cfg, nil)
  43. var resp listenerTestResponse
  44. if err != nil {
  45. resp.Err = err.Error()
  46. }
  47. if err := json.NewEncoder(os.Stdout).Encode(resp); err != nil {
  48. fmt.Fprintln(os.Stderr, err)
  49. os.Exit(1)
  50. }
  51. }
  52. // Test to make sure that the listen specs without an address are handled
  53. // It requires a 2-phase setup due to how socket activation works (which we are using to test).
  54. // It requires LISTEN_FDS and LISTEN_PID to be set in the environment.
  55. //
  56. // LISTEN_PID is used by socket activation to determine if the process is the one that should be activated.
  57. // LISTEN_FDS is used by socket activation to determine how many file descriptors are passed to the process.
  58. //
  59. // We can sort of fake this without using extra processes, but it ends up not
  60. // being a true test because that's not how socket activation is expected to
  61. // work and we'll end up with nil listeners since the test framework has other
  62. // file descriptors open.
  63. //
  64. // This is not currently testing `tcp://` or `unix://` listen specs without an address because those can conflict with the machine running the test.
  65. // This could be worked around by using linux namespaces, however that would require root privileges which unit tests don't typically have.
  66. func TestLoadListenerNoAddr(t *testing.T) {
  67. cmd := reexec.Command(testListenerNoAddrCmdPhase1)
  68. stdout := bytes.NewBuffer(nil)
  69. cmd.Stdout = stdout
  70. stderr := bytes.NewBuffer(nil)
  71. cmd.Stderr = stderr
  72. assert.NilError(t, cmd.Run(), stderr.String())
  73. var resp listenerTestResponse
  74. assert.NilError(t, json.NewDecoder(stdout).Decode(&resp))
  75. assert.Equal(t, resp.Err, "")
  76. }