summaryrefslogtreecommitdiffstats
path: root/nixos/tests/rundeck.nix
blob: 8bfd209816f31ab7f2b5070a4ab654fbbd0f6125 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
{
  name = "rundeck";

  nodes = {
    rundeck =
      { pkgs, ... }:
      {
        environment.etc."rundeck-admin-password" = {
          text = "testpassword";
          mode = "0400";
          user = "rundeck";
          group = "rundeck";
        };

        services.rundeck = {
          enable = true;
          serverHostname = "rundeck";
          adminUser = "testadmin";
          adminPasswordFile = "/etc/rundeck-admin-password";
          serverPort = 4441;
          database.type = "h2";
          openFirewall = true;
        };

        environment.systemPackages = with pkgs; [
          curl
          jq
        ];
      };
  };

  testScript = ''
    start_all()

    def login_and_verify_api(machine, host, port, user, password, timeout=300):
        """Authenticate via Rundeck form login and verify API access."""
        machine.wait_until_succeeds(
            f"curl -s -c /tmp/cookies -L"
            f" -d 'j_username={user}&j_password={password}'"
            f" http://{host}:{port}/j_security_check -o /dev/null"
            f" && curl -s -b /tmp/cookies -H 'Accept: application/json'"
            f" http://{host}:{port}/api/26/system/info"
            f" | jq -e '.system.rundeck.version'",
            timeout=timeout,
        )

    def properties(machine, path):
        return machine.succeed(f"cat {path}").replace("\\", "").replace(" = ", "=")

    with subtest("Rundeck starts and serves homepage"):
        rundeck.wait_for_unit("rundeck.service")
        rundeck.wait_for_open_port(4441)
        rundeck.wait_until_succeeds(
            "curl -sL http://rundeck:4441 | grep -qi Rundeck"
        )

    with subtest("Regression - port is included in generated URLs"):
        config = properties(rundeck, "/etc/rundeck/rundeck-config.properties")
        framework = properties(rundeck, "/etc/rundeck/framework.properties")

        assert "grails.serverURL=http://rundeck:4441" in config, config
        assert "server.port=4441" in config, config
        assert "framework.server.url=http://rundeck:4441" in framework, framework

    with subtest("Structural settings end up in the generated config"):
        config = properties(rundeck, "/etc/rundeck/rundeck-config.properties")

        assert "dataSource.driverClassName=org.h2.Driver" in config, config
        assert "dataSource.dialect=org.hibernate.dialect.H2Dialect" in config, config

    with subtest("Server UUID is generated and substituted"):
        framework = properties(rundeck, "/etc/rundeck/framework.properties")

        assert "@SERVER_UUID@" not in framework, framework
        rundeck.succeed(
            "grep -qE '^rundeck\\.server\\.uuid = [0-9a-f-]{36}$'"
            " /etc/rundeck/framework.properties"
        )

    with subtest("Secrets are substituted and not world-readable"):
        rundeck.succeed(
            "grep -qxF 'testadmin:testpassword,user,admin'"
            " /etc/rundeck/realm.properties"
        )
        rundeck.fail("grep -q '@ADMIN_PASSWORD@' /etc/rundeck/realm.properties")
        rundeck.succeed(
            "[ \"$(stat -c %a /etc/rundeck/realm.properties)\" = 600 ]"
        )
        rundeck.succeed(
            "[ \"$(stat -c %U /etc/rundeck/realm.properties)\" = rundeck ]"
        )

    with subtest("API authentication via form login"):
        login_and_verify_api(rundeck, "rundeck", 4441, "testadmin", "testpassword")

        rundeck.succeed(
            "curl -s -b /tmp/cookies -X POST"
            " -H 'Accept: application/json'"
            " -H 'Content-Type: application/json'"
            " -d '{\"name\":\"test-project\",\"config\":{}}'"
            " http://rundeck:4441/api/26/projects"
            " | jq -e '.name == \"test-project\"'"
        )

        rundeck.succeed(
            "curl -s -b /tmp/cookies -H 'Accept: application/json'"
            " http://rundeck:4441/api/26/projects"
            " | jq -e 'any(.[]; .name == \"test-project\")'"
        )
  '';
}