daemon_linux_test.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  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. cli := &DaemonCli{
  38. Config: &config.Config{
  39. CommonConfig: config.CommonConfig{
  40. Hosts: []string{"fd://"},
  41. },
  42. },
  43. }
  44. _, err := loadListeners(cli, nil)
  45. var resp listenerTestResponse
  46. if err != nil {
  47. resp.Err = err.Error()
  48. }
  49. if err := json.NewEncoder(os.Stdout).Encode(resp); err != nil {
  50. fmt.Fprintln(os.Stderr, err)
  51. os.Exit(1)
  52. }
  53. }
  54. // Test to make sure that the listen specs without an address are handled
  55. // It requires a 2-phase setup due to how socket activation works (which we are using to test).
  56. // It requires LISTEN_FDS and LISTEN_PID to be set in the environment.
  57. //
  58. // LISTEN_PID is used by socket activation to determine if the process is the one that should be activated.
  59. // LISTEN_FDS is used by socket activation to determine how many file descriptors are passed to the process.
  60. //
  61. // We can sort of fake this without using extra processes, but it ends up not
  62. // being a true test because that's not how socket activation is expected to
  63. // work and we'll end up with nil listeners since the test framework has other
  64. // file descriptors open.
  65. //
  66. // This is not currently testing `tcp://` or `unix://` listen specs without an address because those can conflict with the machine running the test.
  67. // This could be worked around by using linux namespaces, however that would require root privileges which unit tests don't typically have.
  68. func TestLoadListenerNoAddr(t *testing.T) {
  69. cmd := reexec.Command(testListenerNoAddrCmdPhase1)
  70. stdout := bytes.NewBuffer(nil)
  71. cmd.Stdout = stdout
  72. stderr := bytes.NewBuffer(nil)
  73. cmd.Stderr = stderr
  74. assert.NilError(t, cmd.Run(), stderr.String())
  75. var resp listenerTestResponse
  76. assert.NilError(t, json.NewDecoder(stdout).Decode(&resp))
  77. assert.Equal(t, resp.Err, "")
  78. }