github.com/containers/podman/v5@v5.1.0-rc1/test/e2e/systemd_activate_test.go (about)

     1  package integration
     2  
     3  import (
     4  	"errors"
     5  	"io/fs"
     6  	"net"
     7  	"net/url"
     8  	"os"
     9  	"os/exec"
    10  	"path/filepath"
    11  	"strconv"
    12  	"syscall"
    13  	"time"
    14  
    15  	testUtils "github.com/containers/podman/v5/test/utils"
    16  	podmanUtils "github.com/containers/podman/v5/utils"
    17  	. "github.com/onsi/ginkgo/v2"
    18  	. "github.com/onsi/gomega"
    19  	. "github.com/onsi/gomega/gexec"
    20  )
    21  
    22  var _ = Describe("Systemd activate", func() {
    23  	var activate string
    24  
    25  	BeforeEach(func() {
    26  		SkipIfRemote("Testing stopped service requires both podman and podman-remote binaries")
    27  
    28  		activate, err = exec.LookPath("systemd-socket-activate")
    29  		if err != nil {
    30  			activate = "/usr/bin/systemd-socket-activate"
    31  		}
    32  		stat, err := os.Stat(activate)
    33  		switch {
    34  		case errors.Is(err, fs.ErrNotExist):
    35  			Skip(activate + " required for systemd activation tests")
    36  		case stat.Mode()&0111 == 0:
    37  			Skip("Unable to execute " + activate)
    38  		case err != nil:
    39  			Skip(err.Error())
    40  		}
    41  	})
    42  
    43  	It("stop podman.service", func() {
    44  		// systemd-socket-activate does not support DNS lookups
    45  		host := "127.0.0.1"
    46  		port, err := podmanUtils.GetRandomPort()
    47  		Expect(err).ToNot(HaveOccurred())
    48  		addr := net.JoinHostPort(host, strconv.Itoa(port))
    49  
    50  		podmanOptions := podmanTest.makeOptions(nil, false, false)
    51  
    52  		systemdArgs := []string{
    53  			"-E", "http_proxy", "-E", "https_proxy", "-E", "no_proxy",
    54  			"-E", "HTTP_PROXY", "-E", "HTTPS_PROXY", "-E", "NO_PROXY",
    55  			"-E", "XDG_RUNTIME_DIR", "-E", "CI_DESIRED_DATABASE",
    56  			"--listen", addr,
    57  			podmanTest.PodmanBinary}
    58  		systemdArgs = append(systemdArgs, podmanOptions...)
    59  		systemdArgs = append(systemdArgs, "system", "service", "--time=0")
    60  
    61  		activateSession := testUtils.StartSystemExec(activate, systemdArgs)
    62  		Expect(activateSession.Exited).ShouldNot(Receive(), "Failed to start podman service")
    63  		WaitForService(url.URL{Scheme: "tcp", Host: addr})
    64  		defer activateSession.Signal(syscall.SIGTERM)
    65  
    66  		// Create custom functions for running podman and
    67  		// podman-remote.  This test is a rare exception where both
    68  		// binaries need to be run in parallel.  Usually, the remote
    69  		// and non-remote details are hidden.  Yet we use the
    70  		// `podmanOptions` above to make sure all settings (root,
    71  		// runroot, events, tmpdir, etc.) are used as in other e2e
    72  		// tests.
    73  		podmanRemote := func(args ...string) *testUtils.PodmanSession {
    74  			args = append([]string{"--url", "tcp://" + addr}, args...)
    75  			return testUtils.SystemExec(podmanTest.RemotePodmanBinary, args)
    76  		}
    77  
    78  		podman := func(args ...string) *testUtils.PodmanSession {
    79  			args = append(podmanOptions, args...)
    80  			return testUtils.SystemExec(podmanTest.PodmanBinary, args)
    81  		}
    82  
    83  		containerName := "top_" + testUtils.RandomString(8)
    84  		apiSession := podmanRemote(
    85  			"create", "--tty", "--name", containerName, "--entrypoint", "top",
    86  			ALPINE,
    87  		)
    88  		Expect(apiSession).Should(testUtils.ExitCleanly())
    89  		defer podman("rm", "-f", containerName)
    90  
    91  		apiSession = podmanRemote("start", containerName)
    92  		Expect(apiSession).Should(testUtils.ExitCleanly())
    93  
    94  		apiSession = podmanRemote("inspect", "--format={{.State.Running}}", containerName)
    95  		Expect(apiSession).Should(testUtils.ExitCleanly())
    96  		Expect(apiSession.OutputToString()).To(Equal("true"))
    97  
    98  		// Emulate 'systemd stop podman.service'
    99  		activateSession.Signal(syscall.SIGTERM)
   100  		time.Sleep(100 * time.Millisecond)
   101  		Eventually(activateSession).Should(Exit(0))
   102  
   103  		abiSession := podman("inspect", "--format={{.State.Running}}", containerName)
   104  		Expect(abiSession).To(testUtils.ExitCleanly())
   105  		Expect(abiSession.OutputToString()).To(Equal("true"))
   106  	})
   107  
   108  	It("invalid systemd file descriptor", func() {
   109  		host := "127.0.0.1"
   110  		port, err := podmanUtils.GetRandomPort()
   111  		Expect(err).ToNot(HaveOccurred())
   112  
   113  		addr := net.JoinHostPort(host, strconv.Itoa(port))
   114  
   115  		// start systemd activation with datagram socket
   116  		activateSession := testUtils.StartSystemExec(activate, []string{
   117  			"--datagram", "--listen", addr, "-E", "CI_DESIRED_DATABASE",
   118  			podmanTest.PodmanBinary,
   119  			"--root=" + filepath.Join(tempdir, "server_root"),
   120  			"system", "service",
   121  			"--time=0",
   122  		})
   123  		Expect(activateSession.Exited).ShouldNot(Receive(), "Failed to start podman service")
   124  
   125  		// we have to wait for systemd-socket-activate to become ready
   126  		time.Sleep(1 * time.Second)
   127  
   128  		// now dial the socket to start podman
   129  		conn, err := net.Dial("udp", addr)
   130  		Expect(err).ToNot(HaveOccurred())
   131  		defer conn.Close()
   132  		_, err = conn.Write([]byte("test"))
   133  		Expect(err).ToNot(HaveOccurred())
   134  
   135  		// wait for podman to exit
   136  		activateSession.Wait(10)
   137  		Expect(activateSession).To(Exit(125))
   138  		Expect(activateSession.ErrorToString()).To(ContainSubstring("Error: unexpected fd received from systemd: cannot listen on it"))
   139  	})
   140  })