summaryrefslogtreecommitdiff
path: root/evergreen/selinux_test_executor.sh
blob: 481cc2c5199319cd85e259215a2a40019f49c834 (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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#!/bin/bash
set +o errexit

readonly k_log_path="/var/log/mongodb/mongod.log"
readonly k_mongo="$(pwd)/dist-test/bin/mongo"
readonly k_test_path="$1"
return_code=1

export PATH="$(dirname "$k_mongo"):$PATH"

function print_err() {
  echo "$@" >&2
}

function monitor_log() {
  sed "s!^!mongod| $(date '+%F %H-%M-%S') !" <(sudo --non-interactive tail -f $k_log_path)
}

function output_ausearch() {
  local cmd_parameters="AVC,USER_AVC,SELINUX_ERR,USER_SELINUX_ERR"

  echo ""
  echo "====== SELinux errors (ausearch -m $cmd_parameters): ======"
  sudo --non-interactive ausearch -m $cmd_parameters -ts $1
}

function output_journalctl() {
  echo ""
  echo "============================== journalctl ========================================="
  sudo --non-interactive journalctl --no-pager --catalog --since="$1" | grep -i mongo
}

function fail_and_exit_err() {

  echo ""
  echo "==================================================================================="
  echo "++++++++ Test failed, outputting last 5 seconds of additional log info ++++++++++++"
  echo "==================================================================================="
  output_ausearch "$(date --utc --date='5 seconds ago' '+%x %H:%M:%S')"
  output_journalctl "$(date --utc --date='5 seconds ago' +'%Y-%m-%d %H:%M:%S')"

  echo ""
  echo "==== FAIL: $1 ===="
  exit 1
}

function create_mongo_config() {
  echo "Writing /etc/mongod.conf for $k_test_path:"
  "$k_mongo" --nodb --norc --quiet --eval='
        assert(load("'"$k_test_path"'"));
        const test = new TestDefinition();
        print(JSON.stringify(test.config, null, 2));

    ' | sudo --non-interactive tee /etc/mongod.conf
}

function start_mongod() {
  # Start mongod and if it won't come up, fail and exit

  sudo --non-interactive systemctl start mongod \
    && sudo --non-interactive systemctl status mongod || (
    fail_and_exit_err "systemd failed to start mongod server!"
  )
}

function wait_for_mongod_to_accept_connections() {
  # Once the mongod process starts via systemd, it can still take a couple of seconds
  # to set up and accept connections... we will wait for log id 23016 to show up
  # indicating that the server is ready to accept incoming connections before starting the tests

  local server_ready=0
  local wait_seconds=2
  local wait_retries_max=30
  local wait_retries=0

  while [[ $wait_retries -le $wait_retries_max ]]; do
    local server_status="$(grep 23016 $k_log_path || echo "")"

    if [ "$server_status" != "" ]; then
      server_ready=1
      break
    fi

    sleep $wait_seconds
    ((wait_retries++))
  done

  if [ ! $server_ready ]; then
    fail_and_exit_err "failed to connect to mongod server after waiting for $(($wait_seconds * $wait_retries)) seconds!"
  fi
}

function clear_mongo_config() {
  # stop mongod, zero mongo log, clean up database, set all booleans to off
  sudo --non-interactive bash -c '
        systemctl stop mongod

        rm -f '"$k_log_path"'
        touch '"$k_log_path"'
        chown mongod '"$k_log_path"'

        rm -rf /var/lib/mongo/*

        rm -rf /etc/sysconfig/mongod /etc/mongod

        setsebool mongod_can_connect_ldap off
        setsebool mongod_can_use_kerberos off
    '
}

function exit_with_code() {
  exit $return_code
}

function setup_test_definition() {
  "$k_mongo" --nodb --norc --quiet --eval='
        assert(load("'"$k_test_path"'"));
        (() => {
            const test = new TestDefinition();
            print("Running setup() for '"$k_test_path"'");
            test.setup();
        })();
    '
}

function run_test() {
  "$k_mongo" --norc --gssapiServiceName=mockservice --eval='
        assert(load("'"$k_test_path"'"));
        print("Running test '"$k_test_path"'");

        const test = new TestDefinition();

        try {
            await test.run();
        } finally {
            test.teardown();
        }
    ' || fail_and_exit_err "Test failed"

  echo "SUCCESS: $k_test_path"
}

if [ ! -f "$k_mongo" ]; then
  print_err "Mongo shell at $k_mongo is missing"
  exit 1
fi

if [ ! -f "$k_test_path" ]; then
  print_err "No test supplied or test file not found. Run:"
  print_err "$(basename "${BASH_SOURCE[0]}") <path>"
  exit 1
fi

# Ensure file containing tests is valid before executing
if ! "$k_mongo" --nodb --norc --quiet "$k_test_path"; then
  print_err "File $k_test_path has syntax errors"
  exit 1
fi

echo "STARTING TEST: $k_test_path"

clear_mongo_config
create_mongo_config
setup_test_definition

# start log monitor, also kill it on exit
monitor_log &
monitor_pid="$!"
trap "sudo --non-interactive pkill -P $monitor_pid; exit_with_code" SIGINT SIGTERM ERR EXIT

start_mongod
wait_for_mongod_to_accept_connections
run_test

return_code=0