This commit is contained in:
Stephen Simpson
2025-11-26 08:15:00 -06:00
parent 3cbd4525a0
commit bb829c9b63
18 changed files with 2440 additions and 349 deletions

138
Jenkinsfile vendored
View File

@@ -34,40 +34,46 @@ set -e
echo "Preparing standard golden image..."
# Update system
dnf update -y
# NOTE: This runs inside virt-customize (offline mode)
# Cannot use firewall-cmd, hostnamectl, or systemctl start/restart
# Only systemctl enable works (creates symlinks)
# Install common testing dependencies
# Update system (optional - can be slow, commented out by default)
# dnf update -y
# Install common testing dependencies including Raku/Sparrowdo
dnf install -y \\
perl \\
git \\
wget \\
tar \\
openssh-server \\
firewalld \\
chrony \\
vim
vim \\
rakudo \\
rakudo-zef
# Configure services
# Enable services (works offline)
systemctl enable sshd
systemctl enable firewalld
systemctl enable chronyd
# Configure firewall
firewall-cmd --permanent --add-service=ssh
firewall-cmd --reload
# Create rocky user (standard non-root user)
useradd -m rocky 2>/dev/null || true
echo "rocky:rockypass" | chpasswd
# Set consistent hostname
hostnamectl set-hostname test-node
# Add rocky to sudoers (needed for sparrowdo --bootstrap)
echo "rocky ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/rocky
chmod 0440 /etc/sudoers.d/rocky
# Create testing user
# Create testuser for backward compatibility
useradd -m testuser 2>/dev/null || true
echo "testuser:testpass" | chpasswd
echo "testuser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers
# Add to sudoers
echo "testuser ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers.d/testuser
chmod 0440 /etc/sudoers.d/testuser
echo "Golden image preparation complete!"
''',
description: 'Shell script to run inside the golden image'
description: 'Shell script to run inside the golden image (virt-customize offline mode)'
)
// Test Selection
@@ -84,6 +90,13 @@ echo "Golden image preparation complete!"
description: 'Maximum concurrent VMs'
)
// Image Download Control
booleanParam(
name: 'REDOWNLOAD_IMAGE',
defaultValue: false,
description: 'Force re-download of base QCOW2 image even if it exists'
)
// Cleanup Control
booleanParam(
name: 'KEEP_GOLDEN_IMAGE',
@@ -142,18 +155,42 @@ echo "Golden image preparation complete!"
steps {
script {
dir(IMAGES_DIR) {
sh '''
if [ ! -f "base-${BUILD_ID}.qcow2" ]; then
// Extract filename from URL for caching
def imageFilename = params.QCOW2_URL.split('/').last()
def cachedImagePath = "${IMAGES_DIR}/${imageFilename}"
def buildImagePath = "${IMAGES_DIR}/base-${BUILD_ID}.qcow2"
if (params.REDOWNLOAD_IMAGE) {
echo "REDOWNLOAD_IMAGE is enabled - forcing fresh download"
sh """
echo "Downloading QCOW2 image from: ${QCOW2_URL}"
curl -L --progress-bar -o "base-${BUILD_ID}.qcow2" "${QCOW2_URL}"
curl -L --progress-bar -o "${buildImagePath}" "${QCOW2_URL}"
echo ""
echo "Image downloaded successfully:"
qemu-img info "base-${BUILD_ID}.qcow2" | head -5
else
echo "Using cached base image"
fi
'''
env.BASE_IMAGE_PATH = "${IMAGES_DIR}/base-${BUILD_ID}.qcow2"
qemu-img info "${buildImagePath}" | head -5
"""
} else {
sh """
if [ -f "${cachedImagePath}" ]; then
echo "Found cached image: ${cachedImagePath}"
echo "Creating copy for build ${BUILD_ID}..."
cp "${cachedImagePath}" "${buildImagePath}"
qemu-img info "${buildImagePath}" | head -5
else
echo "No cached image found at: ${cachedImagePath}"
echo "Downloading QCOW2 image from: ${QCOW2_URL}"
curl -L --progress-bar -o "${cachedImagePath}" "${QCOW2_URL}"
echo ""
echo "Image downloaded successfully:"
qemu-img info "${cachedImagePath}" | head -5
echo "Creating copy for build ${BUILD_ID}..."
cp "${cachedImagePath}" "${buildImagePath}"
fi
"""
}
env.BASE_IMAGE_PATH = buildImagePath
echo "Base image ready at: ${buildImagePath}"
}
}
}
@@ -192,6 +229,30 @@ echo "Golden image preparation complete!"
}
}
stage('Bootstrap Golden Image') {
steps {
script {
echo "=========================================="
echo "Bootstrapping Sparrowdo in Golden Image"
echo "=========================================="
echo "This installs Sparrowdo ONCE in the golden image"
echo "All test VMs will inherit this and skip bootstrap"
echo ""
// Expand SSH private key path
def sshPrivateKey = params.SSH_PRIVATE_KEY_PATH.replace('${HOME}', env.HOME)
sh """
./scripts/bootstrap_golden.sh \\
${GOLDEN_IMAGE_PATH} \\
${sshPrivateKey}
"""
echo "Golden image successfully bootstrapped"
}
}
}
stage('Parse Test Matrix') {
steps {
script {
@@ -265,29 +326,38 @@ echo "Golden image preparation complete!"
echo "[${testName}] Cloning test repository..."
sh "git clone -b ${testBranch} ${testUrl} test-repo || true"
// Verify sparrowfile exists
// Verify sparrowfile exists (check for main.raku or sparrowfile)
def sparrowfilePath = sh(
script: 'find test-repo -name sparrowfile -type f | head -1',
script: 'find test-repo -name main.raku -type f | head -1',
returnStdout: true
).trim()
if (!sparrowfilePath) {
error "No sparrowfile found in test repository"
sparrowfilePath = sh(
script: 'find test-repo -name sparrowfile -type f | head -1',
returnStdout: true
).trim()
}
if (!sparrowfilePath) {
error "No sparrowfile or main.raku found in test repository"
}
echo "[${testName}] Found sparrowfile: ${sparrowfilePath}"
// Run test
echo "[${testName}] Running Sparrowdo..."
// Run test (bootstrap was already done on golden image)
echo "[${testName}] Running Sparrowdo test..."
sh """
mkdir -p logs
timeout 900 sparrowdo \\
--host=${targetIp} \\
--ssh_user=root \\
--ssh_user=rocky \\
--ssh_private_key=${sshPrivateKey} \\
--ssh_args='-o StrictHostKeyChecking=no -o ConnectTimeout=10' \\
--ssh_args='-o StrictHostKeyChecking=no -o ConnectTimeout=10 -o UserKnownHostsFile=/dev/null' \\
--no_sudo \\
--sparrowfile=${sparrowfilePath} 2>&1 | tee logs/test.log
--sparrowfile=${sparrowfilePath} \\
--verbose \\
--color 2>&1 | tee logs/test.log
"""
echo "[${testName}] Test completed successfully"