274 lines
8.9 KiB
Bash
274 lines
8.9 KiB
Bash
#!/usr/bin/bash
|
|
# vim: sw=2:et:
|
|
|
|
# Reusable function, which waits for a given host to respond to SSH
|
|
function _instanceWaitSSH() {
|
|
local HOST="$1"
|
|
|
|
for LOOP_COUNTER in {0..30}; do
|
|
if ssh-keyscan "$HOST" > /dev/null 2>&1; then
|
|
echo "SSH is up!"
|
|
ssh-keyscan "$HOST" | sudo tee -a /root/.ssh/known_hosts
|
|
break
|
|
fi
|
|
echo "Retrying in 5 seconds... $LOOP_COUNTER"
|
|
sleep 5
|
|
done
|
|
}
|
|
|
|
function _instanceCheck() {
|
|
echo "✔️ Instance checking"
|
|
local _ssh="$1"
|
|
|
|
# Retry loop to wait for instance to be ready
|
|
# This is here especially because of gcp test
|
|
RETRIES=10
|
|
for i in $(seq 1 $RETRIES); do
|
|
echo "Attempt $i of $RETRIES: Checking instance status..."
|
|
if eval "$_ssh true"; then
|
|
echo "Instance is up and ready!"
|
|
break
|
|
else
|
|
echo "Instance is still booting or SSH key not propagated, retrying in 30 seconds..."
|
|
sleep 30
|
|
fi
|
|
done
|
|
|
|
# Check if postgres is installed
|
|
$_ssh rpm -q postgresql dummy
|
|
|
|
|
|
MODULE=$(cat "$REQUEST_FILE" | jq -r .customizations.enabled_modules[0])
|
|
if [ "$MODULE" = "nodejs:20" ]; then
|
|
echo "checking if nodejs 20 is installed: $($_ssh rpm -q nodejs)"
|
|
$_ssh rpm -q nodejs | grep -q nodejs-20
|
|
fi
|
|
|
|
# Verify subscribe status. Loop check since the system may not be registered such early(RHEL only)
|
|
if [[ "$ID" == "rhel" ]]; then
|
|
set +eu
|
|
for LOOP_COUNTER in {1..10}; do
|
|
subscribe_org_id=$($_ssh sudo subscription-manager identity | grep 'org ID')
|
|
if [[ "$subscribe_org_id" == "org ID: $API_TEST_SUBSCRIPTION_ORG_ID" ]]; then
|
|
echo "System is subscribed."
|
|
break
|
|
else
|
|
echo "System is not subscribed. Retrying in 30 seconds...($LOOP_COUNTER/10)"
|
|
sleep 30
|
|
fi
|
|
done
|
|
set -eu
|
|
[[ "$subscribe_org_id" == "org ID: $API_TEST_SUBSCRIPTION_ORG_ID" ]]
|
|
|
|
FACTS=$($_ssh sudo subscription-manager facts)
|
|
if ! grep -q "image-builder.osbuild-composer.api-type: cloudapi-v2" <<< "$FACTS"; then
|
|
echo "System doesn't contain the expected image-builder.osbuild-composer facts"
|
|
echo "$FACTS" | grep image-builder
|
|
exit 1
|
|
fi
|
|
|
|
if [ -n "$OPENSCAP_CUSTOMIZATION_BLOCK" ]; then
|
|
if ! grep -q "image-builder.insights.compliance-profile-id: pci-dss" <<< "$FACTS"; then
|
|
echo "System doesn't contain the expected image-builder.insights facts (profile-id)"
|
|
echo "$FACTS"| grep image-builder
|
|
exit 1
|
|
fi
|
|
if ! grep -q "image-builder.insights.compliance-policy-id: 1af6cced-581c-452c-89cd-33b7bddb816a" <<< "$FACTS"; then
|
|
echo "System doesn't contain the expected image-builder.insights facts (policy-id)"
|
|
echo "$FACTS"| grep image-builder
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# Unregister subscription
|
|
$_ssh sudo subscription-manager unregister
|
|
else
|
|
echo "Not RHEL OS. Skip subscription check."
|
|
fi
|
|
|
|
# Verify that directories and files customization worked as expected
|
|
verify_dirs_files_customization "$_ssh"
|
|
|
|
verify_repository_customization "$_ssh"
|
|
verify_openscap_customization "$_ssh"
|
|
verify_cacert_customization "$_ssh"
|
|
|
|
echo "✔️ Checking timezone customization"
|
|
TZ=$($_ssh timedatectl show -p Timezone --value)
|
|
if [ "$TZ" != "Europe/Prague" ]; then
|
|
echo "Timezone $TZ isn't Europe/Prague"
|
|
exit 1
|
|
fi
|
|
|
|
echo "✔️ Checking firewall customization"
|
|
if $_ssh rpm -q firewalld; then
|
|
FW_SERVICES=$($_ssh sudo firewall-cmd --list-services)
|
|
if ! grep -q "nfs" <<< "$FW_SERVICES"; then
|
|
echo "firewalld nfs service isn't enabled: $FW_SERVICES"
|
|
exit 1
|
|
fi
|
|
else
|
|
echo "firewalld not available on host, that's fine"
|
|
fi
|
|
}
|
|
|
|
WORKER_REFRESH_TOKEN_PATH="/etc/osbuild-worker/token"
|
|
|
|
# Fetch a JWT token.
|
|
# The token is fetched using the refresh token configured in the worker.
|
|
function access_token {
|
|
local refresh_token
|
|
refresh_token="$(cat $WORKER_REFRESH_TOKEN_PATH)"
|
|
access_token_with_org_id "$refresh_token"
|
|
}
|
|
|
|
# Fetch a JWT token.
|
|
# The token is fetched using the refresh token provided as an argument.
|
|
function access_token_with_org_id {
|
|
local refresh_token="$1"
|
|
curl --request POST \
|
|
--data "grant_type=refresh_token" \
|
|
--data "refresh_token=$refresh_token" \
|
|
--header "Content-Type: application/x-www-form-urlencoded" \
|
|
--silent \
|
|
--show-error \
|
|
--fail \
|
|
localhost:8081/token | jq -r .access_token
|
|
}
|
|
|
|
# Get the compose status using a JWT token.
|
|
# The token is fetched using the refresh token configured in the worker.
|
|
function compose_status {
|
|
local compose="$1"
|
|
local refresh_token
|
|
refresh_token="$(cat $WORKER_REFRESH_TOKEN_PATH)"
|
|
compose_status_with_org_id "$compose" "$refresh_token"
|
|
}
|
|
|
|
# Get the compose status using a JWT token.
|
|
# The token is fetched using the refresh token provided as the second argument.
|
|
function compose_status_with_org_id {
|
|
local compose="$1"
|
|
local refresh_token="$2"
|
|
curl \
|
|
--silent \
|
|
--show-error \
|
|
--fail \
|
|
--header "Authorization: Bearer $(access_token_with_org_id "$refresh_token")" \
|
|
"http://localhost:443/api/image-builder-composer/v2/composes/$compose"
|
|
}
|
|
|
|
# Verify that directories and files customization worked as expected
|
|
function verify_dirs_files_customization {
|
|
echo "✔️ Checking custom directories and files"
|
|
local _ssh="$1"
|
|
local _error=0
|
|
|
|
# verify that `/etc/custom_dir/dir1` exists and has mode `0775`
|
|
local cust_dir1_mode
|
|
cust_dir1_mode=$($_ssh stat -c '%a' /etc/custom_dir/dir1)
|
|
if [[ "$cust_dir1_mode" != "775" ]]; then
|
|
echo "Directory /etc/custom_dir/dir1 has wrong mode: $cust_dir1_mode"
|
|
_error=1
|
|
fi
|
|
|
|
# verify that `/etc/custom_dir/custom_file.txt` exists and contains `image builder is the best\n`
|
|
local cust_file_content
|
|
cust_file_content=$($_ssh cat /etc/custom_dir/custom_file.txt)
|
|
if [[ "$cust_file_content" != "image builder is the best" ]]; then
|
|
echo "File /etc/custom_dir/custom_file.txt has wrong content: $cust_file_content"
|
|
_error=1
|
|
fi
|
|
|
|
# verify that `/etc/custom_dir2/empty_file.txt` exists and is empty
|
|
local cust_file2_content
|
|
cust_file2_content=$($_ssh cat /etc/custom_dir2/empty_file.txt)
|
|
if [[ "$cust_file2_content" != "" ]]; then
|
|
echo "File /etc/custom_dir2/empty_file.txt has wrong content: $cust_file2_content"
|
|
_error=1
|
|
fi
|
|
|
|
if [[ "$_error" == "1" ]]; then
|
|
echo "Testing of custom directories and files failed."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Verify that repository customizations worked as expected
|
|
function verify_repository_customization {
|
|
echo "✔️ Checking custom repositories"
|
|
local _ssh="$1"
|
|
local _error=0
|
|
|
|
local _custom_repo_file="/etc/yum.repos.d/example.repo"
|
|
local _key_file_path="/etc/pki/rpm-gpg/RPM-GPG-KEY-example-0"
|
|
|
|
# verify that `/etc/yum.repos.d/example.repo` exists
|
|
# and contains path to gpg key file
|
|
local cust_repo_contains_key_path
|
|
cust_repo_contains_key_path=$($_ssh cat "$_custom_repo_file" | grep -c "${_key_file_path}")
|
|
if [[ "$cust_repo_contains_key_path" -le 0 ]]; then
|
|
echo "File $_custom_repo_file does not contain ${_key_file_path}}"
|
|
_error=1
|
|
fi
|
|
|
|
# verify that gpg key file has been saved to image
|
|
# and the contents match the expected gpg key
|
|
local local_key remote_key key_diff
|
|
local_key=$(echo -e "$CUSTOM_GPG_KEY")
|
|
remote_key=$($_ssh cat "${_key_file_path}")
|
|
key_diff=$(diff <(echo "$local_key") <(echo "$remote_key") | wc -l)
|
|
if [[ "$key_diff" -gt 0 ]]; then
|
|
echo "File $_key_file_path has wrong content"
|
|
_error=1
|
|
fi
|
|
|
|
if [[ "$_error" == "1" ]]; then
|
|
echo "Testing of custom repositories failed."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Verify that tailoring file was created
|
|
function verify_openscap_customization {
|
|
echo "✔️ Checking OpenSCAP customizations"
|
|
local _ssh="$1"
|
|
local _error=0
|
|
|
|
# NOTE: We are only checking the creation of the tailoring file and ensuring it exists
|
|
# since running openscap tests here requires more memory and causes some out-of-memory issues.
|
|
local tailoring_file_content
|
|
tailoring_file_path="/oscap_data/tailoring.xml"
|
|
tailoring_file_content=$($_ssh cat "${tailoring_file_path}" \
|
|
| grep 'idref="xccdf_org.ssgproject.content_rule_rpm_verify_permissions" selected="false"' -c
|
|
)
|
|
if [[ "$tailoring_file_content" -eq 0 ]]; then
|
|
echo "File ${tailoring_file_path} has wrong content"
|
|
_error=1
|
|
fi
|
|
|
|
if [[ "$_error" == "1" ]]; then
|
|
echo "Testing of OpenSCAP customizations has failed."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Verify that CA cert file was extracted
|
|
function verify_cacert_customization {
|
|
echo "✔️ Checking CA cert extration"
|
|
local _ssh="$1"
|
|
local _serial="27894af897dd2423607045716438a725f28a6d0b"
|
|
local _cn="Test CA for osbuild"
|
|
|
|
if ! $_ssh "test -e /etc/pki/ca-trust/source/anchors/${_serial}.pem"; then
|
|
echo "Anchor CA file does not exist, directory contents:"
|
|
$_ssh "find /etc/pki/ca-trust/source/anchors"
|
|
exit 1
|
|
fi
|
|
|
|
if ! $_ssh "grep -q \"${_cn}\" /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem"; then
|
|
echo "Extracted CA file is not present, bundle contents:"
|
|
$_ssh "grep '^#' /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem"
|
|
exit 1
|
|
fi
|
|
}
|