#!/bin/bash # TODO: Convert to use new/common gate scripts when available set -e NAME=divingbell : ${LOGS_DIR:=/var/log} : ${LOGS_SUBDIR:=${LOGS_DIR}/${NAME}/$(date +"%m-%d-%y_%H:%M:%S")} mkdir -p "${LOGS_SUBDIR}" LOG_NAME="${LOGS_SUBDIR}/test.log" TEST_RESULTS="${LOGS_SUBDIR}/results.log" BASE_VALS="--values=divingbell/values.yaml" SYSCTL_KEY1=net.ipv4.conf.all.log_martians SYSCTL_VAL1_DEFAULT=1 SYSCTL_KEY2=net.ipv4.conf.all.secure_redirects SYSCTL_VAL2_DEFAULT=1 SYSCTL_KEY3=net.ipv4.conf.all.accept_redirects SYSCTL_VAL3_DEFAULT=0 SYSCTL_KEY4=net/ipv6/conf/all/accept_redirects SYSCTL_VAL4_DEFAULT=0 MOUNTS_SYSTEMD=/${NAME} MOUNTS_PATH1=${MOUNTS_SYSTEMD}1 MOUNTS_PATH2=${MOUNTS_SYSTEMD}2 MOUNTS_PATH3=${MOUNTS_SYSTEMD}3 ETHTOOL_KEY2=tx-tcp-segmentation ETHTOOL_VAL2_DEFAULT=on ETHTOOL_KEY3=tx-tcp6-segmentation # Not all NIC hardware has enough ethtool tunables available ETHTOOL_KEY3_BACKUP='' ETHTOOL_VAL3_DEFAULT=on ETHTOOL_KEY4=tx-nocache-copy ETHTOOL_VAL4_DEFAULT=off ETHTOOL_KEY5=tx-checksum-ip-generic ETHTOOL_KEY5_BACKUP=tx-scatter-gather ETHTOOL_VAL5_DEFAULT=on USERNAME1=userone USERNAME1_SUDO=true USERNAME1_SSHKEY1="ssh-rsa abc123 comment" USERNAME2=usertwo USERNAME2_SUDO=false USERNAME2_SSHKEY1="ssh-rsa xyz456 comment" USERNAME2_SSHKEY2="ssh-rsa qwe789 comment" USERNAME2_SSHKEY3="ssh-rsa rfv000 comment" USERNAME2_CRYPT_PASSWD='$6$AF.NLpphOJjMVTYC$GD6wyUTy9vIgatoMbtTDYcVtEJqh/Mrx3BRetVstMsNodSyn3ZFIZOMRePpRpGbFArnAxgkL1PtQxsZHCgtFn/' USERNAME3=userthree USERNAME3_SUDO=true USERNAME4=userfour USERNAME4_SUDO=false APT_PACKAGE1=python-pbr APT_VERSION1=1.8.0-4ubuntu1 APT_PACKAGE2=mysql-server APT_PACKAGE3=python-simplejson APT_VERSION3=3.8.1-1ubuntu2 APT_PACKAGE4=less APT_PACKAGE5=python-setuptools APT_PACKAGE6=telnetd EXEC_DIR=/var/${NAME}/exec # this used in test_overrides to check amount of daemonsets defined EXPECTED_NUMBER_OF_DAEMONSETS=17 type lshw || apt -y install lshw type apparmor_parser || apt -y install apparmor nic_info="$(lshw -class network)" physical_nic='' IFS=$'\n' for line in ${nic_info}; do if [[ ${line} = *'physical id:'* ]]; then physical_nic=true fi if [ "${physical_nic}" = 'true' ] && [[ ${line} = *'logical name'* ]]; then DEVICE="$(echo "${line}" | cut -d':' -f2 | tr -d '[:space:]')" echo "Found device: '${DEVICE}' to use for ethtool testing" break fi done [ -n "${DEVICE}" ] || (echo Could not find physical NIC for tesing; exit 1) # Not all hardware has the same NIC tunables to use for testing if [[ $(/sbin/ethtool -k "${DEVICE}" | grep "${ETHTOOL_KEY3}:") =~ .*fixed.* ]]; then ETHTOOL_KEY3="${ETHTOOL_KEY3_BACKUP}" fi if [[ $(/sbin/ethtool -k "${DEVICE}" | grep "${ETHTOOL_KEY5}:") =~ .*fixed.* ]]; then ETHTOOL_KEY5="${ETHTOOL_KEY5_BACKUP}" fi exec >& >(while read line; do echo "${line}" | sudo tee -a ${LOG_NAME}; done) set -x purge_containers(){ local chart_status="$(helm list ${NAME})" if [ -n "${chart_status}" ]; then helm delete --purge ${NAME} fi } __set_systemd_name(){ if [ "${2}" = 'mount' ]; then SYSTEMD_NAME="$(systemd-escape -p --suffix=mount "${1}")" else SYSTEMD_NAME="$(systemd-escape -p --suffix=service "${1}")" fi } _teardown_systemd(){ __set_systemd_name "${1}" "${2}" sudo systemctl stop "${SYSTEMD_NAME}" >& /dev/null || true sudo systemctl disable "${SYSTEMD_NAME}" >& /dev/null || true sudo rm "/etc/systemd/system/${SYSTEMD_NAME}" >& /dev/null || true } clean_persistent_files(){ sudo rm -r /var/${NAME} >& /dev/null || true sudo rm -r /etc/sysctl.d/60-${NAME}-* >& /dev/null || true sudo rm -r /etc/security/limits.d/60-${NAME}-* >& /dev/null || true sudo rm -r /etc/apparmor.d/${NAME}-* >& /dev/null || true _teardown_systemd ${MOUNTS_PATH1} mount _teardown_systemd ${MOUNTS_PATH2} mount _teardown_systemd ${MOUNTS_PATH3} mount sudo systemctl daemon-reload } _write_sysctl(){ sudo /sbin/sysctl -w ${1}=${2} } _write_ethtool(){ local cur_val if [ -z "${2}" ]; then return fi cur_val="$(/sbin/ethtool -k ${1} | grep "${2}:" | cut -d':' -f2 | cut -d' ' -f2)" if [ "${cur_val}" != "${3}" ]; then sudo /sbin/ethtool -K ${1} ${2} ${3} || true fi } _reset_account(){ if [ -n "$1" ]; then sudo deluser $1 >& /dev/null || true sudo rm -r /home/$1 >& /dev/null || true sudo rm /etc/sudoers.d/*$1* >& /dev/null || true fi } init_default_state(){ purge_containers clean_persistent_files # set sysctl original vals _write_sysctl ${SYSCTL_KEY1} ${SYSCTL_VAL1_DEFAULT} _write_sysctl ${SYSCTL_KEY2} ${SYSCTL_VAL2_DEFAULT} _write_sysctl ${SYSCTL_KEY3} ${SYSCTL_VAL3_DEFAULT} _write_sysctl ${SYSCTL_KEY4} ${SYSCTL_VAL4_DEFAULT} # set ethtool original vals _write_ethtool ${DEVICE} ${ETHTOOL_KEY2} ${ETHTOOL_VAL2_DEFAULT} _write_ethtool ${DEVICE} "${ETHTOOL_KEY3}" ${ETHTOOL_VAL3_DEFAULT} _write_ethtool ${DEVICE} ${ETHTOOL_KEY4} ${ETHTOOL_VAL4_DEFAULT} _write_ethtool ${DEVICE} ${ETHTOOL_KEY5} ${ETHTOOL_VAL5_DEFAULT} # Remove any created accounts, SSH keys _reset_account ${USERNAME1} _reset_account ${USERNAME2} _reset_account ${USERNAME3} _reset_account ${USERNAME4} } install(){ purge_containers helm install --name="${NAME}" --debug "${NAME}" --namespace="${NAME}" "$@" } upgrade(){ helm upgrade --name="${NAME}" --debug "${NAME}" --namespace="${NAME}" "$@" } dry_run(){ helm install --name="${NAME}" --dry-run --debug "${NAME}" --namespace="${NAME}" "$@" } get_container_status(){ local deployment="${1}" local log_connect_timeout=60 local log_connect_sleep_interval=2 local wait_time=0 while : ; do container="$(kubectl get pods --namespace="${NAME}" | grep ${NAME}-${deployment} | grep -v Terminating | cut -d' ' -f1)" kubectl logs "${container}" --namespace="${NAME}" > /dev/null && break || \ echo "Waiting for container logs..." && \ wait_time=$((${wait_time} + ${log_connect_sleep_interval})) && \ sleep ${log_connect_sleep_interval} if [ ${wait_time} -ge ${log_connect_timeout} ]; then echo "Hit timeout while waiting for container logs to become available." exit 1 fi done local container_runtime_timeout=210 local container_runtime_sleep_interval=5 wait_time=0 while : ; do CLOGS="$(kubectl logs --namespace="${NAME}" "${container}" 2>&1)" local status="$(echo "${CLOGS}" | tail -1)" if [[ $(echo -e ${status} | tr -d '[:cntrl:]') = *ERROR* ]] || [[ $(echo -e ${status} | tr -d '[:cntrl:]') = *TRACE* ]]; then if [ "${2}" = 'expect_failure' ]; then echo 'Pod exited as expected' break else echo 'Expected pod to complete successfully, but pod reported errors' echo 'pod logs:' echo "${CLOGS}" exit 1 fi elif [[ $(echo -e ${status} | tr -d '[:cntrl:]') = *'INFO Putting the daemon to sleep.'* ]] || [[ $(echo -e ${status} | tr -d '[:cntrl:]') = *'DEBUG + exit 0'* ]]; then if [ "${2}" = 'expect_failure' ]; then echo 'Expected pod to die with error, but pod completed successfully' echo 'pod logs:' echo "${CLOGS}" exit 1 else echo 'Pod completed without errors.' break fi else wait_time=$((${wait_time} + ${container_runtime_sleep_interval})) sleep ${container_runtime_sleep_interval} fi if [ ${wait_time} -ge ${container_runtime_timeout} ]; then echo 'Hit timeout while waiting for container to complete work.' break fi done } _test_sysctl_default(){ test "$(/sbin/sysctl "${1}" | cut -d'=' -f2 | tr -d '[:space:]')" = "${2}" } _test_sysctl_value(){ _test_sysctl_default "${1}" "${2}" local key="${1//\//.}" test "$(cat /etc/sysctl.d/60-${NAME}-${key}.conf)" = "${key}=${2}" } _test_exec_match(){ expected_result="$1" exec_testfile="$2" testID="$3" if [[ $expected_result != $(cat $exec_testfile) ]]; then echo "[FAIL] exec $testID failed. Expected:" echo $expected_result echo but got: echo $(cat $exec_testfile) exit 1 fi rm $exec_testfile } _test_exec_count(){ script_location="${1}" script_name="${2}" script_expected_run_count="${3}" script_run_count=$(cat "${script_location}" | wc -l) if [[ ${script_run_count} -ne ${script_expected_run_count} ]]; then echo "[FAIL] Expected '${script_name}' to run '${script_expected_run_count}' times, but instead it ran '$script_run_count' times" exit 1 fi } _test_clog_msg(){ [[ $CLOGS = *${1}* ]] || (echo "Did not find expected string: '${1}'" echo "in container logs:" echo "${CLOGS}" exit 1) } alias install_base="install ${BASE_VALS}" alias dry_run_base="dry_run ${BASE_VALS}" shopt -s expand_aliases test_sysctl(){ # Test the first set of values local overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set1.yaml local val1=0 local val2=1 local val3=0 local val4=0 echo "conf: sysctl: $SYSCTL_KEY1: $val1 $SYSCTL_KEY2: $val2 $SYSCTL_KEY3: $val3 $SYSCTL_KEY4: $val4" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status sysctl _test_sysctl_value $SYSCTL_KEY1 $val1 _test_sysctl_value $SYSCTL_KEY2 $val2 _test_sysctl_value $SYSCTL_KEY3 $val3 _test_sysctl_value $SYSCTL_KEY4 $val4 echo '[SUCCESS] sysctl test1 passed successfully' >> "${TEST_RESULTS}" # Test an updated set of values overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set2.yaml val1=1 val2=0 val3=1 val4=1 echo "conf: sysctl: $SYSCTL_KEY1: $val1 $SYSCTL_KEY2: $val2 $SYSCTL_KEY3: $val3 $SYSCTL_KEY4: $val4" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status sysctl _test_sysctl_value $SYSCTL_KEY1 $val1 _test_sysctl_value $SYSCTL_KEY2 $val2 _test_sysctl_value $SYSCTL_KEY3 $val3 _test_sysctl_value $SYSCTL_KEY4 $val4 echo '[SUCCESS] sysctl test2 passed successfully' >> "${TEST_RESULTS}" # Test revert/rollback functionality install_base get_container_status sysctl _test_sysctl_default $SYSCTL_KEY1 $SYSCTL_VAL1_DEFAULT _test_sysctl_default $SYSCTL_KEY2 $SYSCTL_VAL2_DEFAULT _test_sysctl_default $SYSCTL_KEY3 $SYSCTL_VAL3_DEFAULT _test_sysctl_default $SYSCTL_KEY4 $SYSCTL_VAL4_DEFAULT echo '[SUCCESS] sysctl test3 passed successfully' >> "${TEST_RESULTS}" # Test invalid key overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-invalid1.yaml echo "conf: sysctl: this.is.a.bogus.key: 1" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status sysctl expect_failure _test_clog_msg 'sysctl: cannot stat /proc/sys/this/is/a/bogus/key: No such file or directory' echo '[SUCCESS] sysctl test4 passed successfully' >> "${TEST_RESULTS}" # Test invalid val overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-invalid2.yaml echo "conf: sysctl: $SYSCTL_KEY1: bogus" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" # Sysctl does not report a non-zero exit code for this failure condition per # https://bugzilla.redhat.com/show_bug.cgi?id=1264080 get_container_status sysctl _test_clog_msg 'sysctl: setting key "net.ipv4.conf.all.log_martians": Invalid argument' echo '[SUCCESS] sysctl test5 passed successfully' >> "${TEST_RESULTS}" } _test_limits_value(){ local limit=${1} local domain=${2} local type=${3} local item=${4} local value=${5} test "$(cat /etc/security/limits.d/60-${NAME}-${limit}.conf)" = \ "$domain $type $item $value" } test_limits(){ local overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}.yaml echo "conf: limits: limit1: domain: root type: hard item: core value: 0 limit2: domain: '0:' type: soft item: nofile value: 101" > "${overrides_yaml}" echo $(cat ${overrides_yaml}) install_base "--values=${overrides_yaml}" get_container_status limits _test_limits_value limit1 root hard core 0 _test_limits_value limit2 '0:' soft nofile 101 echo "[SUCCESS] test range loop for limits passed successfully" >> "${TEST_RESULTS}" } _test_perm_value(){ local file=${1} local owner=${2} local group=${3} local perm=${4} local r_owner="$(stat -c %U ${file})" local r_group="$(stat -c %G ${file})" local r_perm="$(stat -c %a ${file})" [ "${perm}"=="${r_perm}" ] && echo "+" || (echo "File ${file} permissions ${r_perm} but expected ${perm}"; exit 1) [ "${owner}"=="${r_owner}" ] && echo "+" || (echo "File ${file} owner ${r_owner} but expected ${owner}"; exit 1) [ "${group}"=="${r_group}" ] && echo "+" || (echo "File ${file} group ${r_group} but expected ${group}"; exit 1) } _perm_init_one(){ local file=${1} local user=${file##*.} useradd ${user} -U chmod 777 ${file} chown ${user}:${user} ${file} echo ${file} } _make_p_temp(){ echo $(mktemp "${TMPDIR:-/tmp}/${0##*/}.XXXXXX") } _perm_init(){ # global vars! p_test_file1=$(_perm_init_one $(_make_p_temp)) p_test_file2=$(_perm_init_one $(_make_p_temp)) } _perm_teardown_one(){ local file=${1} local user=${file##*.} deluser ${user} -q rm -f ${file} } _perm_teardown(){ # global vars! _perm_teardown_one ${p_test_file1} unset p_test_file1 _perm_teardown_one ${p_test_file2} unset p_test_file2 } test_perm(){ _perm_init local overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}.yaml echo "conf: perm: paths: - path: ${p_test_file1} owner: 'root' group: 'shadow' permissions: '0640' - path: ${p_test_file2} owner: 'root' group: 'shadow' permissions: '0640'" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status perm _test_perm_value ${p_test_file1} root shadow 640 _test_perm_value ${p_test_file2} root shadow 640 echo "[SUCCESS] Positive test for perm passed successfully" >> "${TEST_RESULTS}" echo "conf: perm: paths: - path: ${p_test_file1} owner: 'root' group: 'shadow' permissions: '0640'" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status perm _test_perm_value ${p_test_file1} root shadow 640 _test_perm_value ${p_test_file2} ${p_test_file2##*.} ${p_test_file2##*.} 777 echo "[SUCCESS] Backup test for perm passed successfully" >> "${TEST_RESULTS}" # Test invalid rerun_interval (too short) echo "conf: perm: rerun_interval: 30 paths: - path: ${p_test_file1} owner: 'root' group: 'shadow' permissions: '0640'" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" 2>&1 | grep 'BAD .rerun_interval. Got' || \ (echo "[FAIL] perm test invalid rerun_interval value did not receive expected 'BAD .rerun_interval. Got' error" && exit 1) echo '[SUCCESS] perm test invalid rerun_interval passed successfully' >> "${TEST_RESULTS}" # Test invalid rerun_interval combination echo "conf: perm: rerun_interval: 60 rerun_policy: once_successfully paths: - path: ${p_test_file1} owner: 'root' group: 'shadow' permissions: '0640'" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" 2>&1 | grep 'BAD COMBINATION' || \ (echo "[FAIL] perm invalid rerun_interval combination did not receive expected 'BAD COMBINATION' error" && exit 1) echo '[SUCCESS] perm invalid rerun_interval combination passed successfully' >> "${TEST_RESULTS}" # test rerun_interval echo "conf: perm: rerun_interval: 60 paths: - path: ${p_test_file1} owner: 'root' group: 'shadow' permissions: '0640'" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status perm sleep 72 get_container_status perm _test_perm_value ${p_test_file1} root shadow 640 echo '[SUCCESS] perm rerun_interval passed successfully' >> "${TEST_RESULTS}" _perm_teardown } _test_if_mounted_positive(){ mountpoint "${1}" || (echo "Expect ${1} to be mounted, but was not"; exit 1) df -h | grep "${1}" | grep "${2}" || (echo "Did not find expected mount size of ${2} in mount table"; exit 1) __set_systemd_name "${1}" mount systemctl is-enabled "${SYSTEMD_NAME}" || (echo "Expect ${SYSTEMD_NAME} to be flagged to start on boot, but is not" exit 1) } _test_if_mounted_negative(){ mountpoint "${1}" && (echo "Expect ${1} not to be mounted, but was" exit 1) || true __set_systemd_name "${1}" mount systemctl is-enabled "${SYSTEMD_NAME}" && (echo "Expect ${SYSTEMD_NAME} not to be flagged to start on boot, but was" exit 1) || true } test_mounts(){ # Test the first set of values local overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set1.yaml local mount_size=32M echo "conf: mounts: mnt: mnt_tgt: ${MOUNTS_PATH1} device: tmpfs type: tmpfs options: 'defaults,noatime,nosuid,nodev,noexec,mode=1777,size=${mount_size}' mnt2: mnt_tgt: ${MOUNTS_PATH2} device: tmpfs type: tmpfs options: 'defaults,noatime,nosuid,nodev,noexec,mode=1777,size=${mount_size}' mnt3: mnt_tgt: ${MOUNTS_PATH3} device: tmpfs type: tmpfs options: 'defaults,noatime,nosuid,nodev,noexec,mode=1777,size=${mount_size}' before: ntp.service after: dbus.service" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status mounts _test_if_mounted_positive ${MOUNTS_PATH1} ${mount_size} _test_if_mounted_positive ${MOUNTS_PATH2} ${mount_size} _test_if_mounted_positive ${MOUNTS_PATH3} ${mount_size} echo '[SUCCESS] mounts test1 passed successfully' >> "${TEST_RESULTS}" # Test an updated set of values overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set2.yaml mount_size=30M echo "conf: mounts: mnt: mnt_tgt: ${MOUNTS_PATH1} device: tmpfs type: tmpfs options: 'defaults,noatime,nosuid,nodev,noexec,mode=1777,size=${mount_size}' mnt2: mnt_tgt: ${MOUNTS_PATH2} device: tmpfs type: tmpfs options: 'defaults,noatime,nosuid,nodev,noexec,mode=1777,size=${mount_size}' mnt3: mnt_tgt: ${MOUNTS_PATH3} device: tmpfs type: tmpfs options: 'defaults,noatime,nosuid,nodev,noexec,mode=1777,size=${mount_size}' before: ntp.service after: dbus.service" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status mounts _test_if_mounted_positive ${MOUNTS_PATH1} ${mount_size} _test_if_mounted_positive ${MOUNTS_PATH2} ${mount_size} _test_if_mounted_positive ${MOUNTS_PATH3} ${mount_size} echo '[SUCCESS] mounts test2 passed successfully' >> "${TEST_RESULTS}" # Test revert/rollback functionality install_base get_container_status mounts _test_if_mounted_negative ${MOUNTS_PATH1} _test_if_mounted_negative ${MOUNTS_PATH2} _test_if_mounted_negative ${MOUNTS_PATH3} echo '[SUCCESS] mounts test3 passed successfully' >> "${TEST_RESULTS}" # Test invalid mount overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-invalid1.yaml echo "conf: mounts: mnt: mnt_tgt: '${MOUNTS_PATH1}' device: '/dev/bogus' type: 'bogus' options: 'defaults'" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status mounts expect_failure # systemd has long 3 min timeout __set_systemd_name "${MOUNTS_PATH1}" mount _test_clog_msg "${SYSTEMD_NAME} failed." echo '[SUCCESS] mounts test4 passed successfully' >> "${TEST_RESULTS}" } _test_ethtool_value(){ if [ -z "${1}" ]; then return fi test "$(/sbin/ethtool -k ${DEVICE} | grep "${1}:" | cut -d':' -f2 | tr -d '[:space:]')" = "${2}" } test_ethtool(){ # Test the first set of values local overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set1.yaml local val2=on local val3=off [ -n "${ETHTOOL_KEY3}" ] && local line2_1="${ETHTOOL_KEY3}: $val3" local val4=off echo "conf: ethtool: ${DEVICE}: $ETHTOOL_KEY2: $val2 $line2_1 $ETHTOOL_KEY4: $val4" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status ethtool _test_ethtool_value $ETHTOOL_KEY2 $val2 _test_ethtool_value "$ETHTOOL_KEY3" $val3 _test_ethtool_value $ETHTOOL_KEY4 $val4 echo '[SUCCESS] ethtool test1 passed successfully' >> "${TEST_RESULTS}" # Test an updated set of values overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set2.yaml val2=off val3=on [ -n "${ETHTOOL_KEY3}" ] && local line2_2="${ETHTOOL_KEY3}: $val3" val4=on echo "conf: ethtool: ${DEVICE}: $ETHTOOL_KEY2: $val2 $line2_2 $ETHTOOL_KEY4: $val4" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status ethtool _test_ethtool_value $ETHTOOL_KEY2 $val2 _test_ethtool_value "$ETHTOOL_KEY3" $val3 _test_ethtool_value $ETHTOOL_KEY4 $val4 echo '[SUCCESS] ethtool test2 passed successfully' >> "${TEST_RESULTS}" # Test revert/rollback functionality install_base get_container_status ethtool _test_ethtool_value $ETHTOOL_KEY2 $ETHTOOL_VAL2_DEFAULT _test_ethtool_value "$ETHTOOL_KEY3" $ETHTOOL_VAL3_DEFAULT _test_ethtool_value $ETHTOOL_KEY4 $ETHTOOL_VAL4_DEFAULT echo '[SUCCESS] ethtool test3 passed successfully' >> "${TEST_RESULTS}" # Test invalid key overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-invalid1.yaml echo "conf: ethtool: ${DEVICE}: this-is-a-bogus-key: $val2" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status ethtool expect_failure _test_clog_msg "Could not find requested param this-is-a-bogus-key for ${DEVICE}" echo '[SUCCESS] ethtool test4 passed successfully' >> "${TEST_RESULTS}" # Test invalid val overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-invalid2.yaml echo "conf: ethtool: ${DEVICE}: $ETHTOOL_KEY2: bogus" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status ethtool expect_failure _test_clog_msg "Expected 'on' or 'off', got 'bogus'" echo '[SUCCESS] ethtool test5 passed successfully' >> "${TEST_RESULTS}" # Test fixed (unchangeable) ethtool param overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-invalid3.yaml echo "conf: ethtool: ${DEVICE}: hw-tc-offload: on" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status ethtool expect_failure _test_clog_msg "does not permit changing the 'hw-tc-offload' setting" echo '[SUCCESS] ethtool test6 passed successfully' >> "${TEST_RESULTS}" # Test ethtool settings conflict overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-invalid4.yaml echo "conf: ethtool: ${DEVICE}: ${ETHTOOL_KEY2}: on ${ETHTOOL_KEY5}: off" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status ethtool expect_failure _test_clog_msg 'There is a conflict between settings chosen for this device.' echo '[SUCCESS] ethtool test7 passed successfully' >> "${TEST_RESULTS}" } _test_user_enabled(){ username=$1 user_enabled=$2 if [ "${user_enabled}" = "true" ]; then # verify the user is there and not set to expire getent passwd $username >& /dev/null test "$(chage -l ${username} | grep 'Account expires' | cut -d':' -f2 | tr -d '[:space:]')" = "never" else # Verify user is not non-expiring getent passwd $username >& /dev/null test "$(chage -l ${username} | grep 'Account expires' | cut -d':' -f2 | tr -d '[:space:]')" != "never" fi } _test_user_purged(){ username=$1 # Verify user is no longer defined getent passwd $username >& /dev/null && \ echo "Error: User '$username' exists, but was expected it to be purged" && \ return 1 if [ -d /home/$username ]; then echo "Error: User '$username' home dir exists; expected it to be purged" return 1 fi } _test_sudo_enabled(){ username=$1 sudo_enable=$2 sudoers_file=/etc/sudoers.d/*$username* if [ "${sudo_enable}" = "true" ]; then test -f $sudoers_file else test ! -f $sudoers_file fi } _test_ssh_keys(){ username=$1 sshkey=$2 ssh_file=/home/$username/.ssh/authorized_keys if [ "$sshkey" = "false" ]; then test ! -f "${ssh_file}" else grep "$sshkey" "${ssh_file}" fi } _test_user_passwd(){ username=$1 crypt_passwd="$2" if [ "$crypt_passwd" != "$(getent shadow $username | cut -d':' -f2)" ]; then echo "Error: User '$username' passwd did not match expected val '$crypt_passwd'" return 1 fi } test_uamlite(){ # Test the first set of values local overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set1.yaml echo "conf: uamlite: users: - user_name: ${USERNAME1} user_sudo: ${USERNAME1_SUDO} user_sshkeys: - ${USERNAME1_SSHKEY1} - user_name: ${USERNAME2} user_sudo: ${USERNAME2_SUDO} user_crypt_passwd: ${USERNAME2_CRYPT_PASSWD} user_sshkeys: - ${USERNAME2_SSHKEY1} - ${USERNAME2_SSHKEY2} - ${USERNAME2_SSHKEY3} - user_name: ${USERNAME3} user_sudo: ${USERNAME3_SUDO} - user_name: ${USERNAME4}" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status uamlite _test_user_enabled ${USERNAME1} true _test_sudo_enabled ${USERNAME1} ${USERNAME1_SUDO} _test_ssh_keys ${USERNAME1} "${USERNAME1_SSHKEY1}" _test_user_passwd ${USERNAME1} '*' _test_user_enabled ${USERNAME2} true _test_sudo_enabled ${USERNAME2} ${USERNAME2_SUDO} _test_ssh_keys ${USERNAME2} "${USERNAME2_SSHKEY1}" _test_ssh_keys ${USERNAME2} "${USERNAME2_SSHKEY2}" _test_ssh_keys ${USERNAME2} "${USERNAME2_SSHKEY3}" _test_user_passwd ${USERNAME2} ${USERNAME2_CRYPT_PASSWD} _test_user_enabled ${USERNAME3} true _test_sudo_enabled ${USERNAME3} ${USERNAME3_SUDO} _test_ssh_keys ${USERNAME3} false _test_user_passwd ${USERNAME3} '*' _test_user_enabled ${USERNAME4} true _test_sudo_enabled ${USERNAME4} ${USERNAME4_SUDO} _test_ssh_keys ${USERNAME4} false _test_user_passwd ${USERNAME4} '*' echo '[SUCCESS] uamlite test1 passed successfully' >> "${TEST_RESULTS}" # Test an updated set of values overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set2.yaml uname1_sudo=false uname2_sudo=true uname3_sudo=false echo "conf: uamlite: users: - user_name: ${USERNAME1} user_sudo: ${uname1_sudo} - user_name: ${USERNAME2} user_sudo: ${uname2_sudo} user_sshkeys: - ${USERNAME2_SSHKEY1} - ${USERNAME2_SSHKEY2} - user_name: ${USERNAME3} user_sudo: ${uname3_sudo} user_sshkeys: - ${USERNAME1_SSHKEY1} - ${USERNAME2_SSHKEY3} - user_name: ${USERNAME4}" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status uamlite _test_user_enabled ${USERNAME1} true _test_sudo_enabled ${USERNAME1} ${uname1_sudo} _test_ssh_keys ${USERNAME1} false _test_user_passwd ${USERNAME1} '*' _test_user_enabled ${USERNAME2} true _test_sudo_enabled ${USERNAME2} ${uname2_sudo} _test_ssh_keys ${USERNAME2} "${USERNAME2_SSHKEY1}" _test_ssh_keys ${USERNAME2} "${USERNAME2_SSHKEY2}" _test_user_passwd ${USERNAME2} '*' _test_user_enabled ${USERNAME3} true _test_sudo_enabled ${USERNAME3} ${uname3_sudo} _test_ssh_keys ${USERNAME3} "${USERNAME1_SSHKEY1}" _test_ssh_keys ${USERNAME3} "${USERNAME2_SSHKEY3}" _test_user_passwd ${USERNAME3} '*' _test_user_enabled ${USERNAME4} true _test_sudo_enabled ${USERNAME4} ${USERNAME4_SUDO} _test_ssh_keys ${USERNAME4} false _test_user_passwd ${USERNAME4} '*' echo '[SUCCESS] uamlite test2 passed successfully' >> "${TEST_RESULTS}" # Test revert/rollback functionality install_base get_container_status uamlite _test_user_enabled ${USERNAME1} false _test_sudo_enabled ${USERNAME1} false _test_user_enabled ${USERNAME2} false _test_sudo_enabled ${USERNAME2} false _test_user_enabled ${USERNAME3} false _test_sudo_enabled ${USERNAME3} false _test_user_enabled ${USERNAME4} false _test_sudo_enabled ${USERNAME4} false echo '[SUCCESS] uamlite test3 passed successfully' >> "${TEST_RESULTS}" # Test purge users flag overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set4.yaml echo "conf: uamlite: purge_expired_users: true" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status uamlite _test_user_purged ${USERNAME1} _test_user_purged ${USERNAME2} _test_user_purged ${USERNAME3} _test_user_purged ${USERNAME4} echo '[SUCCESS] uamlite test4 passed successfully' >> "${TEST_RESULTS}" # Test invalid password overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set5.yaml user2_crypt_passwd_invalid='plaintextPassword' echo "conf: uamlite: users: - user_name: ${USERNAME2} user_crypt_passwd: ${user2_crypt_passwd_invalid}" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" 2>&1 | grep 'BAD PASSWORD' || \ (echo "[FAIL] uamlite test5 did not receive expected 'BAD PASSWORD' error" && exit 1) echo '[SUCCESS] uamlite test5 passed successfully' >> "${TEST_RESULTS}" # Test invalid SSH key overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set6.yaml user2_bad_sshkey='AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmT key-comment' echo "conf: uamlite: users: - user_name: ${USERNAME2} user_sshkeys: - ${USERNAME2_SSHKEY1} - ${user2_bad_sshkey} - ${USERNAME2_SSHKEY3}" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" 2>&1 | grep 'BAD SSH KEY' || \ (echo "[FAIL] uamlite test6 did not receive expected 'BAD SSH KEY' error" && exit 1) echo '[SUCCESS] uamlite test6 passed successfully' >> "${TEST_RESULTS}" } _test_apt_package_version(){ local pkg_name=$1 local pkg_ver=$2 if [ ${pkg_ver} = "none" ]; then # Does not include residual-config if [[ $(dpkg -l | grep ${pkg_name} | grep -v ^rc) ]]; then echo "[FAIL] Package ${pkg_name} should not be installed" >> "${TEST_RESULTS}" return 1 fi elif [ ${pkg_ver} = "any" ]; then if [[ ! $(dpkg -l | grep ${pkg_name}) ]]; then echo "[FAIL] Package ${pkg_name} should be installed" >> "${TEST_RESULTS}" return 1 fi else if [ $(dpkg -l | awk "/[[:space:]]${pkg_name}[[:space:]]/"'{print $3}') != "${pkg_ver}" ]; then echo "[FAIL] Package ${pkg_name} should be of version ${pkg_ver}" >> "${TEST_RESULTS}" return 1 fi fi } test_apt(){ # Test the valid set of packages local overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set1.yaml echo "conf: apt: packages: - name: $APT_PACKAGE1 version: $APT_VERSION1 - name: $APT_PACKAGE2" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status apt _test_apt_package_version $APT_PACKAGE1 $APT_VERSION1 _test_apt_package_version $APT_PACKAGE2 any echo '[SUCCESS] apt test1 passed successfully' >> "${TEST_RESULTS}" # Test removal of one package and install of one new package local overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set2.yaml echo "conf: apt: packages: - name: $APT_PACKAGE2 debconf: - question: mysql-server/root_password question_type: password answer: rootpw - question: mysql-server/root_password_again question_type: password answer: rootpw - name: $APT_PACKAGE3 version: $APT_VERSION3" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status apt _test_apt_package_version $APT_PACKAGE1 none _test_apt_package_version $APT_PACKAGE2 any # Each entry in passwords.dat contains question value in Name and Template # field, so grepping root_password should return 4 lines if [[ $(grep root_password /var/cache/debconf/passwords.dat | wc -l) != 4 ]]; then echo "[FAIL] Package $APT_PACKAGE2 should have debconf values configured" >> "${TEST_RESULTS}" return 1 fi _test_apt_package_version $APT_PACKAGE3 $APT_VERSION3 echo '[SUCCESS] apt test2 passed successfully' >> "${TEST_RESULTS}" # Test removal of all installed packages and install of one that already exists local overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set3.yaml echo "conf: apt: packages: - name: $APT_PACKAGE4" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status apt _test_apt_package_version $APT_PACKAGE2 none _test_apt_package_version $APT_PACKAGE3 none echo '[SUCCESS] apt test3 passed successfully' >> "${TEST_RESULTS}" # Test package not installed by divingbell not removed local overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set4.yaml echo "conf: apt: packages: - name: $APT_PACKAGE5" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status apt _test_apt_package_version $APT_PACKAGE4 any # Should still be present _test_apt_package_version $APT_PACKAGE5 any echo '[SUCCESS] apt test4 passed successfully' >> "${TEST_RESULTS}" # Test invalid package name overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-invalid1.yaml echo "conf: apt: packages: - name: some-random-name version: whatever" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status apt expect_failure _test_clog_msg 'E: Unable to locate package some-random-name' echo '[SUCCESS] apt test5 passed successfully' >> "${TEST_RESULTS}" # Test blacklistpkgs local overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set1.yaml echo "conf: apt: packages: - name: $APT_PACKAGE6 blacklistpkgs: - $APT_PACKAGE6" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status apt _test_apt_package_version $APT_PACKAGE6 none echo '[SUCCESS] apt test6 passed successfully' >> "${TEST_RESULTS}" } # test exec module test_exec(){ # test script execution ordering, args, and env vars local overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set1.yaml echo 'conf: exec: 030-script5.sh: blocking_policy: foreground_halt_pod_on_failure env: env1: env1-val env2: env2-val env3: env3-val args: - arg1 - arg2 - arg3 data: | #!/bin/bash echo script name: ${BASH_SOURCE} >> exec_testfile echo args: "$@" >> exec_testfile echo env: "$env1 $env2 $env3" >> exec_testfile 005-script1.sh: blocking_policy: foreground data: | #!/bin/bash rm exec_testfile 2> /dev/null || true echo script name: ${BASH_SOURCE} >> exec_testfile 015-script3.sh: blocking_policy: foreground_halt_pod_on_failure data: | #!/bin/bash echo script name: ${BASH_SOURCE} >> exec_testfile 008-script2.sh: data: | #!/bin/bash echo script name: ${BASH_SOURCE} >> exec_testfile 025-script4.sh: data: | #!/bin/bash echo script name: ${BASH_SOURCE} >> exec_testfile' > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status exec expected_result='script name: ./005-script1.sh script name: ./008-script2.sh script name: ./015-script3.sh script name: ./025-script4.sh script name: ./030-script5.sh args: arg1 arg2 arg3 env: env1-val env2-val env3-val' _test_exec_match "$expected_result" "${EXEC_DIR}/exec_testfile" "test1" echo '[SUCCESS] exec test1 passed successfully' >> "${TEST_RESULTS}" # Test blocking_policy local overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set2.yaml echo 'conf: exec: 030-script5.sh: blocking_policy: foreground_halt_pod_on_failure env: env1: env1-val env2: env2-val env3: env3-val args: - arg1 - arg2 - arg3 data: | #!/bin/bash echo script name: ${BASH_SOURCE} >> exec_testfile echo args: "$@" >> exec_testfile echo env: "$env1 $env2 $env3" >> exec_testfile 005-script1.sh: blocking_policy: foreground data: | #!/bin/bash rm exec_testfile 2> /dev/null || true echo script name: ${BASH_SOURCE} >> exec_testfile 015-script3.sh: blocking_policy: foreground_halt_pod_on_failure data: | #!/bin/bash echo script name: ${BASH_SOURCE} >> exec_testfile false 008-script2.sh: data: | #!/bin/bash echo script name: ${BASH_SOURCE} >> exec_testfile 025-script4.sh: data: | #!/bin/bash echo script name: ${BASH_SOURCE} >> exec_testfile' > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status exec expect_failure expected_result='script name: ./005-script1.sh script name: ./008-script2.sh script name: ./015-script3.sh' _test_exec_match "$expected_result" "${EXEC_DIR}/exec_testfile" "test2" echo '[SUCCESS] exec test2 passed successfully' >> "${TEST_RESULTS}" # Test invalid rerun_policy overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set3.yaml echo 'conf: exec: 030-script5.sh: rerun_policy: foo data: | #!/bin/bash true' > "${overrides_yaml}" install_base "--values=${overrides_yaml}" 2>&1 | grep 'BAD .rerun_policy. FOR' || \ (echo "[FAIL] exec test3 did not receive expected 'BAD .rerun_policy. FOR' error" && exit 1) echo '[SUCCESS] exec test3 passed successfully' >> "${TEST_RESULTS}" # Test invalid blocking_policy overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set4.yaml echo 'conf: exec: 030-script5.sh: blocking_policy: foo data: | #!/bin/bash true' > "${overrides_yaml}" install_base "--values=${overrides_yaml}" 2>&1 | grep 'BAD .blocking_policy. FOR' || \ (echo "[FAIL] exec test4 did not receive expected 'BAD .blocking_policy. FOR' error" && exit 1) echo '[SUCCESS] exec test4 passed successfully' >> "${TEST_RESULTS}" # Test rerun_policies: # 1. Unspecified # 2. always # 3. once_successfully, when script passes # 4. once_successfully, when script fails # 5. never # first execution overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set5.yaml echo 'conf: exec: 001-script1.sh: data: | #!/bin/bash echo script name: ${BASH_SOURCE} >> script1 002-script2.sh: rerun_policy: always data: | #!/bin/bash echo script name: ${BASH_SOURCE} >> script2 003-script3.sh: rerun_policy: once_successfully data: | #!/bin/bash echo script name: ${BASH_SOURCE} >> script3 004-script4.sh: rerun_policy: once_successfully data: | #!/bin/bash echo script name: ${BASH_SOURCE} >> script4 false 005-script5.sh: rerun_policy: never data: | #!/bin/bash echo script name: ${BASH_SOURCE} >> script5 env: env3: env3-val env1: env1-val env2: env2-val args: - arg2 - arg1 - arg3 manifests: daemonset_ethtool: false daemonset_mounts: false daemonset_uamlite: false daemonset_sysctl: false daemonset_limits: false daemonset_apt: false daemonset_perm: false' > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status exec # run several times with the same values and evaluate results # (ensure no ordering issues cause hashing inconsistencies) for i in $(seq 0 11); do install_base "--values=${overrides_yaml}" get_container_status exec _test_exec_count "${EXEC_DIR}/script1" '001-script1.sh' $(($i + 2)) _test_exec_count "${EXEC_DIR}/script2" '002-script1.sh' $(($i + 2)) _test_exec_count "${EXEC_DIR}/script3" '003-script1.sh' '1' _test_exec_count "${EXEC_DIR}/script4" '004-script1.sh' $(($i + 2)) _test_exec_count "${EXEC_DIR}/script5" '005-script1.sh' '1' echo "[SUCCESS] exec test$(($i + 5)) passed successfully" >> "${TEST_RESULTS}" done # test timeout local overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set17.yaml echo 'conf: exec: 011-timeout.sh: timeout: 11 data: | #!/bin/bash sleep 60' > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status exec _test_clog_msg 'timeout waiting for' echo '[SUCCESS] exec test17 passed successfully' >> "${TEST_RESULTS}" # Test invalid timeout overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set18.yaml echo 'conf: exec: 011-timeout.sh: timeout: infinite data: | #!/bin/bash sleep 60' > "${overrides_yaml}" install_base "--values=${overrides_yaml}" 2>&1 | grep 'BAD .timeout. FOR' || \ (echo "[FAIL] exec test18 did not receive expected 'BAD .timeout. FOR' error" && exit 1) echo '[SUCCESS] exec test18 passed successfully' >> "${TEST_RESULTS}" # Test invalid rerun_interval (too short) overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set19.yaml echo 'conf: exec: 012-rerun-interval.sh: rerun_interval: 30 data: | #!/bin/bash true' > "${overrides_yaml}" install_base "--values=${overrides_yaml}" 2>&1 | grep 'BAD .rerun_interval. FOR' || \ (echo "[FAIL] exec test19 did not receive expected 'BAD .rerun_interval. FOR' error" && exit 1) echo '[SUCCESS] exec test19 passed successfully' >> "${TEST_RESULTS}" # Test invalid retry_interval (too short) overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set20.yaml echo 'conf: exec: 012-retry-interval.sh: retry_interval: 30 data: | #!/bin/bash true' > "${overrides_yaml}" install_base "--values=${overrides_yaml}" 2>&1 | grep 'BAD .retry_interval. FOR' || \ (echo "[FAIL] exec test20 did not receive expected 'BAD .retry_interval. FOR' error" && exit 1) echo '[SUCCESS] exec test20 passed successfully' >> "${TEST_RESULTS}" # Test invalid rerun_interval combination overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set21.yaml echo 'conf: exec: 012-rerun-interval.sh: rerun_interval: 60 rerun_policy: once_successfully data: | #!/bin/bash true' > "${overrides_yaml}" install_base "--values=${overrides_yaml}" 2>&1 | grep 'BAD COMBINATION' || \ (echo "[FAIL] exec test21 did not receive expected 'BAD COMBINATION' error" && exit 1) echo '[SUCCESS] exec test21 passed successfully' >> "${TEST_RESULTS}" # Test invalid retry_interval combination overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set22.yaml echo 'conf: exec: 012-retry-interval.sh: retry_interval: 60 rerun_policy: never data: | #!/bin/bash true' > "${overrides_yaml}" install_base "--values=${overrides_yaml}" 2>&1 | grep 'BAD COMBINATION' || \ (echo "[FAIL] exec test22 did not receive expected 'BAD COMBINATION' error" && exit 1) echo '[SUCCESS] exec test22 passed successfully' >> "${TEST_RESULTS}" # test rerun_interval overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set23.yaml echo 'conf: exec: 012-rerun-interval.sh: rerun_interval: 60 data: | #!/bin/bash echo script name: ${BASH_SOURCE} >> exec_testfile' > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status exec sleep 72 get_container_status exec expected_result='script name: ./012-rerun-interval.sh script name: ./012-rerun-interval.sh' _test_exec_match "$expected_result" "${EXEC_DIR}/exec_testfile" "test23" echo '[SUCCESS] exec test23 passed successfully' >> "${TEST_RESULTS}" # test retry_interval overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-set24.yaml echo 'conf: exec: 012-retry-interval.sh: retry_interval: 60 data: | #!/bin/bash echo script name: ${BASH_SOURCE} >> exec_testfile false' > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status exec sleep 72 get_container_status exec expected_result='script name: ./012-retry-interval.sh script name: ./012-retry-interval.sh' _test_exec_match "$expected_result" "${EXEC_DIR}/exec_testfile" "test24" echo '[SUCCESS] exec test24 passed successfully' >> "${TEST_RESULTS}" } # test daemonset value overrides for hosts and labels test_overrides(){ overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-dryrun.yaml echo "conf: sysctl: net.ipv4.ip_forward: 1 net.ipv6.conf.all.forwarding: 1 overrides: divingbell_sysctl: labels: - label: key: compute_type values: - dpdk - sriov conf: sysctl: net.ipv4.ip_forward: 1 - label: key: compute_type values: - special conf: sysctl: net.ipv4.ip_forward: 1 - label: key: compute_type values: - special conf: sysctl: net.ipv4.ip_forward: 1 hosts: - name: superhost conf: sysctl: net.ipv4.ip_forward: 0 net.ipv6.conf.all.forwarding: 0 - name: helm1 conf: sysctl: net.ipv6.conf.all.forwarding: 0 - name: specialhost conf: sysctl: net.ipv6.conf.all.forwarding: 1 divingbell_mounts: labels: - label: key: blarg values: - soup - chips conf: mounts: mnt: mnt_tgt: /mnt device: tmpfs type: tmpfs options: 'defaults,noatime,nosuid,nodev,noexec,mode=1777,size=32M' divingbell_ethtool: hosts: - name: ethtool-host conf: ethtool: ens3: hw-tc-offload: on divingbell_bogus: labels: - label: key: bogus values: - foo - bar conf: bogus: other_stuff: XYZ - label: key: bogus_label values: - bogus_value conf: bogus: more_stuff: ABC hosts: - name: superhost2 conf: bogus: other_stuff: FOO more_stuff: BAR" > "${overrides_yaml}" tc_output="$(dry_run_base "--values=${overrides_yaml}")" # Compare against expected number of generated daemonsets daemonset_count="$(echo "${tc_output}" | grep 'kind: DaemonSet' | wc -l)" if [ "${daemonset_count}" != "${EXPECTED_NUMBER_OF_DAEMONSETS}" ]; then echo '[FAILURE] overrides test 1 failed' >> "${TEST_RESULTS}" echo "Expected ${EXPECTED_NUMBER_OF_DAEMONSETS} daemonsets; got '${daemonset_count}'" >> "${TEST_RESULTS}" exit 1 else echo '[SUCCESS] overrides test 1 passed successfully' >> "${TEST_RESULTS}" fi # TODO: Implement more robust tests that do not depend on match expression # ordering. # Verify generated affinity for another_label echo "${tc_output}" | grep ' spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: another_label operator: In values: - "another_value" - key: kubernetes.io/hostname operator: NotIn values: - "superhost" - key: kubernetes.io/hostname operator: NotIn values: - "helm1" - key: kubernetes.io/hostname operator: NotIn values: - "specialhost"' && echo '[SUCCESS] overrides test 2 passed successfully' >> "${TEST_RESULTS}" || (echo '[FAILURE] overrides test 2 failed' && exit 1) # Verify generated affinity for compute_type echo "${tc_output}" | grep ' spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: compute_type operator: In values: - "special" - key: another_label operator: NotIn values: - "another_value" - key: kubernetes.io/hostname operator: NotIn values: - "superhost" - key: kubernetes.io/hostname operator: NotIn values: - "helm1" - key: kubernetes.io/hostname operator: NotIn values: - "specialhost"' && echo '[SUCCESS] overrides test 3 passed successfully' >> "${TEST_RESULTS}" || (echo '[FAILURE] overrides test 3 failed' && exit 1) # Verify generated affinity for compute_type echo "${tc_output}" | grep ' spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: compute_type operator: In values: - "dpdk" - "sriov" - key: compute_type operator: NotIn values: - "special" - key: another_label operator: NotIn values: - "another_value" - key: kubernetes.io/hostname operator: NotIn values: - "superhost" - key: kubernetes.io/hostname operator: NotIn values: - "helm1" - key: kubernetes.io/hostname operator: NotIn values: - "specialhost"' && echo '[SUCCESS] overrides test 4 passed successfully' >> "${TEST_RESULTS}" || (echo '[FAILURE] overrides test 4 failed' && exit 1) # Verify generated affinity for one of the daemonset hosts echo "${tc_output}" | grep ' spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: blarg operator: In values: - "soup" - "chips"' && echo '[SUCCESS] overrides test 5 passed successfully' >> "${TEST_RESULTS}" || (echo '[FAILURE] overrides test 5 failed' && exit 1) # Verify generated affinity for one of the daemonset defaults echo "${tc_output}" | grep ' spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: NotIn values: - "superhost" - key: kubernetes.io/hostname operator: NotIn values: - "helm1" - key: kubernetes.io/hostname operator: NotIn values: - "specialhost" - key: compute_type operator: NotIn values: - "dpdk" - "sriov" - key: compute_type operator: NotIn values: - "special" - key: another_label operator: NotIn values: - "another_value"' && echo '[SUCCESS] overrides test 6 passed successfully' >> "${TEST_RESULTS}" || (echo '[FAILURE] overrides test 6 failed' && exit 1) overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-functional.yaml key1_override_val=0 key2_non_override_val=0 echo "conf: sysctl: $SYSCTL_KEY1: 1 $SYSCTL_KEY2: $key2_non_override_val overrides: divingbell_sysctl: hosts: - name: $(hostname -f) conf: sysctl: $SYSCTL_KEY1: $key1_override_val" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status sysctl _test_sysctl_default $SYSCTL_KEY1 $key1_override_val _test_sysctl_default $SYSCTL_KEY2 $key2_non_override_val echo '[SUCCESS] overrides test 7 passed successfully' >> "${TEST_RESULTS}" } _test_apparmor_profile_added(){ local profile_file=$1 local profile_name=$2 local defaults_path='/var/divingbell/apparmor' local persist_path='/etc/apparmor.d' if [ ! -f "${defaults_path}/${profile_file}" ]; then return 1 fi if [ ! -L "${persist_path}/${profile_file}" ]; then return 1 fi profile_loaded=$(grep $profile_name /sys/kernel/security/apparmor/profiles || : ) if [ -z "$profile_loaded" ]; then return 1 fi return 0 } _test_apparmor_profile_removed(){ local profile_file=$1 local profile_name=$2 local defaults_path='/var/divingbell/apparmor' local persist_path='/etc/apparmor.d' if [ -f "${defaults_path}/${profile_file}" ]; then return 1 fi if [ -L "${persist_path}/${profile_file}" ]; then return 1 fi profile_loaded=$(grep $profile_name /sys/kernel/security/apparmor/profiles || : ) if [ ! -z "$profile_loaded" ]; then return 1 fi reboot_message_present=$(grep $profile_file /var/run/reboot-required.pkgs || : ) if [ -z "$reboot_message_present" ]; then return 1 fi return 0 } test_apparmor(){ local overrides_yaml=${LOGS_SUBDIR}/${FUNCNAME}-apparmor.yaml #Test1 - check new profile added and loaded echo "conf: apparmor: profiles: divingbell-profile-1: | #include /usr/sbin/profile-1 { #include #include #include capability dac_override, capability dac_read_search, capability net_bind_service, capability setgid, capability setuid, /data/www/safe/* r, deny /data/www/unsafe/* r, }" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status apparmor _test_apparmor_profile_added divingbell-profile-1 profile-1 echo '[SUCCESS] apparmor test1 passed successfully' >> "${TEST_RESULTS}" #Test2 - check new profile added and loaded, profile-1 still exist echo "conf: apparmor: profiles: divingbell-profile-1: | #include /usr/sbin/profile-1 { #include #include #include capability dac_override, capability dac_read_search, capability net_bind_service, capability setgid, capability setuid, /data/www/safe/* r, deny /data/www/unsafe/* r, } divingbell-profile-2: | #include /usr/sbin/profile-2 { #include #include #include capability dac_override, capability dac_read_search, capability net_bind_service, capability setgid, capability setuid, /data/www/safe/* r, deny /data/www/unsafe/* r, }" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status apparmor _test_apparmor_profile_added divingbell-profile-1 profile-1 _test_apparmor_profile_added divingbell-profile-2 profile-2 echo '[SUCCESS] apparmor test2 passed successfully' >> "${TEST_RESULTS}" #Test3 - check profile-2 removed, profile-1 still exist echo "conf: apparmor: complain_mode: true profiles: divingbell-profile-1: | #include /usr/sbin/profile-1 { #include #include #include capability dac_override, capability dac_read_search, capability net_bind_service, capability setgid, capability setuid, /data/www/safe/* r, deny /data/www/unsafe/* r, }" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status apparmor _test_apparmor_profile_added divingbell-profile-1 profile-1 _test_apparmor_profile_removed divingbell-profile-2 profile-2 echo '[SUCCESS] apparmor test3 passed successfully' >> "${TEST_RESULTS}" #Test4 - check for bad profile input echo "conf: apparmor: profiles: divingbell-profile-3: | #include /usr/sbin/profile-3 { bad data }" > "${overrides_yaml}" install_base "--values=${overrides_yaml}" get_container_status apparmor expect_failure _test_clog_msg 'AppArmor parser error for /etc/apparmor.d/divingbell-profile-3 in /etc/apparmor.d/divingbell-profile-3 at line 3: syntax error, unexpected TOK_ID, expecting TOK_MODE' echo '[SUCCESS] apparmor test4 passed successfully' >> "${TEST_RESULTS}" } # initialization init_default_state # run tests if [[ -z $SKIP_BASE_TESTS ]]; then install_base test_sysctl test_limits test_perm test_mounts test_ethtool test_uamlite test_apt test_exec test_apparmor fi purge_containers test_overrides # restore initial state init_default_state echo "All tests pass for ${NAME}"