diff --git a/tests/smoke/runtest.sh b/tests/smoke/runtest.sh new file mode 100644 index 0000000..efdb5dc --- /dev/null +++ b/tests/smoke/runtest.sh @@ -0,0 +1,348 @@ +#!/bin/bash + +# This file was autogenerated at 2019-05-13T13:43:38+02:00 from 90bd97ada89befa1a63133335a419ad7311c3d75 + +# Copyright (c) 2019, Red Hat, Inc. +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND RED HAT, INC. DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RED HAT, INC. BE LIABLE +# FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# +# Author: Jan Friesse + + +# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +# !!! Script overwrites corosync.conf, authkey and qdevice/qnetd certificates !!! +# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +# Home https://github.com/jfriesse/csts/tree/master/smoke + +# -e is really important +set -xe +set -o pipefail + +# Variables changing test behavior +PREFIX="/" + +COROSYNC_SYSCONFD="${PREFIX}etc/corosync" +COROSYNC_CONF="${COROSYNC_SYSCONFD}/corosync.conf" +COROSYNC_AUTHKEY="${COROSYNC_SYSCONFD}/authkey" +COROSYNC_CLUSTER_NAME="smoketestcluster" + +TOKEN_TIMEOUT=1000 +MAX_REPEATS=60 + +#################### +# Helper functions # +#################### +get_ip() { + ip_res=$(ip route get 8.8.8.8) + # Format is "8.8.8.8 via ROUTE_IPADDR dev DEV src IPADDR uid NUMBER" + # Remove everything up to "src " and then everything after " " + addr=${ip_res##*src } + addr=${addr%% *} + + echo "$addr" +} + +# generate_corosync_conf crypto [token] [qdevice] +# crypto can be on or off +# when token is defined it is used for token timeout +# when qdevice is set to on qdevice section is created and second node is added +generate_corosync_conf() { + case "$1" in + "on") + cipher="aes256" + hash="sha256" + ;; + "off") + cipher="none" + hash="none" + ;; + *) + # Unknown crypto + exit 1 + esac + + token=$TOKEN_TIMEOUT + if [ ! -z "$2" ];then + token="$2" + fi + qdevice="$3" + true_command=`which true` + +cat << _EOF_ + totem { + version: 2 + cluster_name: $COROSYNC_CLUSTER_NAME + transport: knet + crypto_cipher: $cipher + crypto_hash: $hash + token: $token + } + + logging { + to_logfile: yes + logfile: /var/log/cluster/corosync.log + to_syslog: yes + } + + quorum { + provider: corosync_votequorum +_EOF_ + + if [ "$qdevice" == "on" ];then +cat << _EOF_ + device { + votes: 1 + model: net + net { + host: $LOCAL_IP + algorithm: ffsplit + } + heuristics { + mode: sync + exec_true: $true_command + } + } +_EOF_ + fi + +cat << _EOF_ + } + + nodelist { + node { + nodeid: 1 + ring0_addr: $LOCAL_IP + } +_EOF_ + + if [ "$qdevice" == "on" ];then +cat << _EOF_ + node { + nodeid: 2 + ring0_addr: 192.0.2.2 + } +_EOF_ + fi + +cat << _EOF_ + } +_EOF_ +} + +# service_start service +service_start() { + # service service must be inactive + systemctl is-active "$1" && exit 1 || true + + systemctl start "$1" + + systemctl is-active "$1" +} + +# service_stop service +service_stop() { + systemctl is-active "$1" || exit 1 + + systemctl stop "$1" + + systemctl is-active "$1" && exit 1 || true +} + +###################### +# Computed variables # +###################### +LOCAL_IP=$(get_ip) + +################## +# C test sources # +################## + +# Test sources are encoded as a base64 string and piped to base64 to store them in /tmp +################## +# Test functions # +################## +test_corosync_qdevice_h() { + # Check that corosync-qdevice(-tool) binary exists and -h returns help text + res=`corosync-qdevice -h || true` + [ "$res" != "${res/usage/}" ] + res=`corosync-qdevice-tool -h || true` + [ "$res" != "${res/usage/}" ] +} + +test_corosync_qnetd_h() { + # Check that corosync-qnetd(-tool) binary exists and -h returns help text + res=`corosync-qnetd -h || true` + [ "$res" != "${res/usage/}" ] + res=`corosync-qnetd-tool -h || true` + [ "$res" != "${res/usage/}" ] +} + +test_crt_creation() { + # Erase old certificates + rm -rf "$COROSYNC_SYSCONFD/qdevice/net/nssdb" + rm -rf "$COROSYNC_SYSCONFD/qnetd/nssdb" + + corosync-qnetd-certutil -i + corosync-qdevice-net-certutil -i -c "$COROSYNC_SYSCONFD/qnetd/nssdb/qnetd-cacert.crt" + corosync-qdevice-net-certutil -r -n "$COROSYNC_CLUSTER_NAME" + corosync-qnetd-certutil -s -c "$COROSYNC_SYSCONFD/qdevice/net/nssdb/qdevice-net-node.crq" -n "$COROSYNC_CLUSTER_NAME" + corosync-qdevice-net-certutil -M -c "$COROSYNC_SYSCONFD/qnetd/nssdb/cluster-$COROSYNC_CLUSTER_NAME.crt" +} + +test_qnetd_start() { + service_start "corosync-qnetd" +} + +test_qdevice_start() { + service_start "corosync-qdevice" +} + +test_corosync_start() { + generate_corosync_conf "off" "" "on" > "$COROSYNC_CONF" + cat "$COROSYNC_CONF" + + service_start "corosync" +} + +test_qdevice_stop() { + service_stop "corosync-qdevice" +} + +test_qnetd_stop() { + service_stop "corosync-qnetd" +} + +test_corosync_stop() { + service_stop "corosync" +} + +# test_corosync_quorumtool quorate +# quorate can be yes or no +test_corosync_quorumtool() { + quorumtool_res_file=`mktemp` + # This is already fixed in upstream db38e3958c4f88d5d06e8f7c83d6d90334d9fbd2 + (corosync-quorumtool -ips || true) | tee "$quorumtool_res_file" + + # Ensure this is single node cluster + grep -qi '^Nodes:.*1$' "$quorumtool_res_file" + # Current node id is 1 + grep -qi '^Node ID:.*1$' "$quorumtool_res_file" + # Is quorate (libquorum) + if [ "$1" == "yes" ];then + grep -qi '^Quorate:.*Yes$' "$quorumtool_res_file" + else + grep -qi '^Quorate:.*No$' "$quorumtool_res_file" + fi + + # Quorum is 2 + grep -qi '^Quorum:.*2' "$quorumtool_res_file" + + # Is quorate (libvotequorum) + if [ "$1" == "yes" ];then + grep -qi '^Flags:.*Quorate' "$quorumtool_res_file" + fi + + rm -f "$quorumtool_res_file" +} + +# Test corosync-qdevice-tool by waiting for connected state and +# checking heuristics results +test_qdevice_tool() { + qdevice_tool_res_file=`mktemp` + + cont=true + repeats=0 + + while $cont;do + corosync-qdevice-tool -s | tee "$qdevice_tool_res_file" + + if grep -qi '^State:.*Connected' "$qdevice_tool_res_file";then + cont=false + else + repeats=$((repeats+1)) + [ "$repeats" -le "$MAX_REPEATS" ] + + sleep 1 + fi + done + + corosync-qdevice-tool -sv | tee "$qdevice_tool_res_file" + grep -qi '^Heuristics result:.*Pass ' "$qdevice_tool_res_file" + + rm -f "$qdevice_tool_res_file" +} + +# Test qnetd tool -s (check connected clients/clusters) and -l +# (check node id, membership and heuristics) +test_qnetd_tool() { + qnetd_tool_res_file=`mktemp` + + corosync-qnetd-tool -s | tee "$qnetd_tool_res_file" + + grep -qi '^Connected clients:.*1$' "$qnetd_tool_res_file" + grep -qi '^Connected clusters:.*1$' "$qnetd_tool_res_file" + + corosync-qnetd-tool -sv | tee "$qnetd_tool_res_file" + + corosync-qnetd-tool -l | tee "$qnetd_tool_res_file" + + grep -qi "^Cluster \"$COROSYNC_CLUSTER_NAME\":\$" "$qnetd_tool_res_file" + grep -qi 'Node ID 1:$' "$qnetd_tool_res_file" + grep -qi 'Membership node list:.*1$' "$qnetd_tool_res_file" + grep -qi 'Heuristics:.*Pass$' "$qnetd_tool_res_file" + + corosync-qnetd-tool -lv | tee "$qnetd_tool_res_file" + + rm -f "$qnetd_tool_res_file" "$qnetd_tool_res_file" +} + +test_qdevice_qnetd_man_pages() { + # At least these man pages should be installed + expected_mp="corosync-qnetd corosync-qnetd-certutil corosync-qnetd-tool + corosync-qdevice corosync-qdevice-net-certutil corosync-qdevice-tool" + + for mp in $expected_mp;do + man -w "$mp" + done +} + +######## +# main # +######## +if [ -z "$PREFIX" ];then + echo "PREFIX not defined. Do not run *.inc.sh directly" + exit 1 +fi + +test_corosync_qdevice_h +test_corosync_qnetd_h + +test_qdevice_qnetd_man_pages + +test_crt_creation + +test_qnetd_start +test_corosync_start + +test_corosync_quorumtool "no" + +test_qdevice_start + +test_qdevice_tool +test_qnetd_tool +test_corosync_quorumtool "yes" + +test_qdevice_stop +test_corosync_stop +test_qnetd_stop diff --git a/tests/tests.yml b/tests/tests.yml new file mode 100644 index 0000000..9239dcf --- /dev/null +++ b/tests/tests.yml @@ -0,0 +1,11 @@ +- hosts: localhost + roles: + - role: standard-test-basic + tags: + - classic + tests: + - smoke + required_packages: + - iproute + - corosync-qdevice + - corosync-qnetd