(MAINT) test vmpooler #1016
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- | |
name: Install test matrix | |
on: | |
pull_request: | |
paths: | |
- .github/workflows/**/* | |
- spec/**/* | |
- lib/**/* | |
- tasks/**/* | |
- functions/**/* | |
- types/**/* | |
- plans/**/* | |
- hiera/**/* | |
- manifests/**/* | |
- templates/**/* | |
- files/**/* | |
- metadata.json | |
- Rakefile | |
- Gemfile | |
- provision.yaml | |
- .rspec | |
- .rubocop.yml | |
- .puppet-lint.rc | |
- .fixtures.yml | |
branches: [main] | |
workflow_dispatch: {} | |
jobs: | |
test-install: | |
name: PE ${{ matrix.version }} ${{ matrix.architecture }} on ${{ matrix.image }} | |
runs-on: ubuntu-latest | |
env: | |
BOLT_GEM: true | |
BOLT_DISABLE_ANALYTICS: true | |
LANG: en_US.UTF-8 | |
strategy: | |
fail-fast: false | |
matrix: | |
architecture: [standard-with-dr] | |
version: [2025.6.0] | |
image: [litmusimage/ubuntu:24.04] | |
steps: | |
- name: Checkout Source | |
uses: actions/checkout@v4 | |
- name: Activate Ruby 3.1 | |
uses: ruby/setup-ruby@v1 | |
with: | |
ruby-version: '3.1' | |
bundler-cache: true | |
- name: Print bundle environment | |
if: ${{ github.repository_owner == 'puppetlabs' }} | |
run: | | |
echo ::group::info:bundler | |
bundle env | |
echo ::endgroup:: | |
- name: Provision test cluster | |
timeout-minutes: 15 | |
run: | | |
echo ::group::prepare | |
mkdir -p $HOME/.ssh | |
echo 'Host *' > $HOME/.ssh/config | |
echo ' ServerAliveInterval 150' >> $HOME/.ssh/config | |
echo ' ServerAliveCountMax 2' >> $HOME/.ssh/config | |
echo ' StrictHostKeyChecking no' >> $HOME/.ssh/config | |
echo ' UserKnownHostsFile /dev/null' >> $HOME/.ssh/config | |
echo ' ConnectTimeout 30' >> $HOME/.ssh/config | |
echo ' ConnectionAttempts 10' >> $HOME/.ssh/config | |
bundle exec rake spec_prep | |
echo ::endgroup:: | |
echo ::group::provision | |
bundle exec bolt plan run peadm_spec::provision_test_cluster \ | |
--modulepath spec/fixtures/modules \ | |
provider=docker \ | |
image=${{ matrix.image }} \ | |
architecture=${{ matrix.architecture }} \ | |
--log-level trace | |
echo ::endgroup:: | |
echo ::group::list modules | |
ls -l ./spec/fixtures/modules || true; echo | |
echo ::endgroup:: | |
echo ::group::show original inventory | |
echo "=== Original inventory.yaml ===" | |
cat ./inventory.yaml || echo "No inventory.yaml found" | |
echo ::endgroup:: | |
echo ::group::create docker transport inventory | |
echo "=== Creating Docker transport inventory ===" | |
# Get container information | |
container_info=$(docker ps --format "{{.Names}}" | grep -v NAMES) | |
# Create new inventory with version 2 format and Docker transport | |
cat > ./inventory.yaml << 'EOF' | |
version: 2 | |
groups: | |
- name: pe_nodes | |
targets: | |
EOF | |
# Add each container as a target | |
for container_name in $container_info; do | |
echo " - name: $container_name" >> ./inventory.yaml | |
echo " uri: $container_name" >> ./inventory.yaml | |
echo " config:" >> ./inventory.yaml | |
echo " transport: docker" >> ./inventory.yaml | |
echo " docker:" >> ./inventory.yaml | |
echo " container-name: $container_name" >> ./inventory.yaml | |
done | |
echo "=== New Docker transport inventory.yaml ===" | |
cat ./inventory.yaml | |
echo ::endgroup:: | |
echo ::group::info:request | |
cat request.json || true; echo | |
echo ::endgroup:: | |
echo ::group::create docker transport inventory | |
echo "=== Creating Docker transport inventory ===" | |
# Get container information | |
container_info=($(docker ps --format "{{.Names}}" | grep -v NAMES)) | |
container_count=${#container_info[@]} | |
# Create new inventory with version 2 format and Docker transport | |
cat > ./inventory.yaml << 'EOF' | |
version: 2 | |
groups: | |
- name: pe_nodes | |
targets: | |
EOF | |
# Assign roles based on architecture | |
case "${{ matrix.architecture }}" in | |
"standard") | |
if [ $container_count -ge 1 ]; then | |
echo " - name: ${container_info[0]}" >> ./inventory.yaml | |
echo " uri: ${container_info[0]}" >> ./inventory.yaml | |
echo " vars:" >> ./inventory.yaml | |
echo " role: primary" >> ./inventory.yaml | |
echo " config:" >> ./inventory.yaml | |
echo " transport: docker" >> ./inventory.yaml | |
echo " docker:" >> ./inventory.yaml | |
echo " container: ${container_info[0]}" >> ./inventory.yaml | |
fi | |
;; | |
"standard-with-dr") | |
if [ $container_count -ge 2 ]; then | |
# Primary | |
echo " - name: ${container_info[0]}" >> ./inventory.yaml | |
echo " uri: ${container_info[0]}" >> ./inventory.yaml | |
echo " vars:" >> ./inventory.yaml | |
echo " role: primary" >> ./inventory.yaml | |
echo " config:" >> ./inventory.yaml | |
echo " transport: docker" >> ./inventory.yaml | |
echo " docker:" >> ./inventory.yaml | |
echo " container: ${container_info[0]}" >> ./inventory.yaml | |
# Replica | |
echo " - name: ${container_info[1]}" >> ./inventory.yaml | |
echo " uri: ${container_info[1]}" >> ./inventory.yaml | |
echo " vars:" >> ./inventory.yaml | |
echo " role: replica" >> ./inventory.yaml | |
echo " config:" >> ./inventory.yaml | |
echo " transport: docker" >> ./inventory.yaml | |
echo " docker:" >> ./inventory.yaml | |
echo " container: ${container_info[1]}" >> ./inventory.yaml | |
fi | |
;; | |
"large") | |
if [ $container_count -ge 2 ]; then | |
# Primary | |
echo " - name: ${container_info[0]}" >> ./inventory.yaml | |
echo " uri: ${container_info[0]}" >> ./inventory.yaml | |
echo " vars:" >> ./inventory.yaml | |
echo " role: primary" >> ./inventory.yaml | |
echo " config:" >> ./inventory.yaml | |
echo " transport: docker" >> ./inventory.yaml | |
echo " docker:" >> ./inventory.yaml | |
echo " container: ${container_info[0]}" >> ./inventory.yaml | |
# Compiler(s) | |
for ((i=1; i<container_count; i++)); do | |
echo " - name: ${container_info[i]}" >> ./inventory.yaml | |
echo " uri: ${container_info[i]}" >> ./inventory.yaml | |
echo " vars:" >> ./inventory.yaml | |
echo " role: compiler" >> ./inventory.yaml | |
echo " config:" >> ./inventory.yaml | |
echo " transport: docker" >> ./inventory.yaml | |
echo " docker:" >> ./inventory.yaml | |
echo " container: ${container_info[i]}" >> ./inventory.yaml | |
done | |
fi | |
;; | |
# Add other architectures as needed | |
*) | |
echo "Architecture ${{ matrix.architecture }} not fully implemented, using simple setup" | |
for container_name in "${container_info[@]}"; do | |
echo " - name: $container_name" >> ./inventory.yaml | |
echo " uri: $container_name" >> ./inventory.yaml | |
echo " vars:" >> ./inventory.yaml | |
echo " role: primary" >> ./inventory.yaml # Default to primary for now | |
echo " config:" >> ./inventory.yaml | |
echo " transport: docker" >> ./inventory.yaml | |
echo " docker:" >> ./inventory.yaml | |
echo " container: $container_name" >> ./inventory.yaml | |
done | |
;; | |
esac | |
echo "=== New Docker transport inventory.yaml ===" | |
cat ./inventory.yaml | |
echo ::endgroup:: | |
- name: Debug container setup | |
run: | | |
echo ::group::debug_container_setup | |
for container in $(docker ps --format "table {{.Names}}" | tail -n +2); do | |
echo "=== Container: $container ===" | |
# Check if SSH service is actually running | |
echo "SSH service status:" | |
docker exec $container systemctl is-active ssh || docker exec $container service ssh status || echo "SSH service check failed" | |
# Check SSH daemon logs | |
echo "SSH daemon logs:" | |
docker exec $container journalctl -u ssh --no-pager -n 10 || docker exec $container tail -10 /var/log/auth.log || echo "No SSH logs found" | |
# Check root password is set | |
echo "Root account status:" | |
docker exec $container passwd -S root || echo "Cannot check root account" | |
# Try to manually set root password | |
echo "Setting root password to 'root':" | |
docker exec $container bash -c 'echo "root:root" | chpasswd' || echo "Failed to set root password" | |
# Check authorized_keys | |
echo "Authorized keys:" | |
docker exec $container cat /root/.ssh/authorized_keys 2>/dev/null || echo "No authorized_keys file" | |
# Check if we can exec into container | |
echo "Test container exec:" | |
docker exec $container whoami || echo "Cannot exec into container" | |
done | |
echo ::endgroup:: | |
- name: Debug SSH connectivity | |
run: | | |
echo ::group::debug_ssh_connectivity | |
# Install sshpass for password authentication | |
sudo apt-get update && sudo apt-get install -y sshpass | |
# Check if containers are running | |
docker ps | |
# Check SSH processes in containers | |
for container in $(docker ps --format "table {{.Names}}" | tail -n +2); do | |
echo "Testing SSH to container: $container" | |
echo "SSH processes in $container:" | |
docker exec $container ps aux | grep sshd || echo "No sshd processes found in $container" | |
# Test SSH connectivity directly with password | |
echo "Testing direct SSH connection to $container:" | |
container_ip=$(docker inspect $container | jq -r '.[0].NetworkSettings.IPAddress') | |
echo "Container IP: $container_ip" | |
# Get the mapped SSH port | |
ssh_port=$(docker port $container 22 | cut -d: -f2) | |
echo "SSH port mapping: localhost:$ssh_port -> $container:22" | |
# Test SSH connection with sshpass and root password | |
echo "Testing SSH with sshpass and root/root:" | |
timeout 10 sshpass -p "root" ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 -p $ssh_port root@localhost 'echo "SSH connection successful to '$container'"' || echo "SSH connection failed to $container" | |
# Also check what's actually listening on the SSH port | |
echo "Checking what's listening on port $ssh_port:" | |
netstat -ln | grep ":$ssh_port " || echo "Nothing listening on port $ssh_port" | |
# Check SSH config inside container | |
echo "SSH configuration in $container:" | |
docker exec $container cat /etc/ssh/sshd_config | grep -E "(PasswordAuthentication|PermitRootLogin|PubkeyAuthentication)" || true | |
# Check if root account is set up correctly | |
echo "Root account info in $container:" | |
docker exec $container passwd -S root || true | |
done | |
echo ::endgroup:: | |
- name: Wait for Docker connectivity to be ready | |
run: | | |
echo ::group::wait_for_docker | |
# Wait for Docker connectivity to be available on all containers via Bolt | |
for i in {1..12}; do | |
echo "Attempt $i: Testing Bolt Docker connectivity..." | |
# Test Docker transport connectivity | |
if bundle exec bolt command run 'echo "Bolt Docker test successful"' \ | |
--inventoryfile ./inventory.yaml \ | |
--targets pe_nodes; then | |
echo "All containers are accessible via Bolt Docker transport!" | |
break | |
fi | |
if [ $i -eq 12 ]; then | |
echo "Containers failed to become accessible after 12 attempts" | |
echo "Final inventory check:" | |
cat ./inventory.yaml | |
echo "=== Docker container status ===" | |
docker ps | |
exit 1 | |
fi | |
echo "Waiting 5 seconds before retry..." | |
sleep 5 | |
done | |
echo ::endgroup:: | |
- name: Check container SSH configuration | |
run: | | |
echo ::group::container_ssh_config | |
for container in $(docker ps --format "table {{.Names}}" | tail -n +2); do | |
echo "=== SSH config for $container ===" | |
docker exec $container cat /etc/ssh/sshd_config | grep -E "(PasswordAuthentication|PubkeyAuthentication|PermitRootLogin)" || true | |
echo "=== Test password auth ===" | |
ssh_port=$(docker port $container 22 | cut -d: -f2) | |
# Try common passwords | |
for password in "root" "password" "litmus"; do | |
echo "Trying password: $password" | |
timeout 5 sshpass -p "$password" ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 -p $ssh_port root@localhost 'echo "Password auth successful with: $password"' && break | |
done || echo "Password authentication failed" | |
done | |
echo ::endgroup:: | |
- name: Install PE on test cluster | |
timeout-minutes: 120 | |
run: | | |
echo "=== Starting PE installation with Docker transport ===" | |
echo "Using inventory file:" | |
cat ./inventory.yaml | |
bundle exec bolt plan run peadm_spec::install_test_cluster \ | |
--inventoryfile ./inventory.yaml \ | |
--modulepath spec/fixtures/modules \ | |
architecture=${{ matrix.architecture }} \ | |
version=${{ matrix.version }} \ | |
console_password=${{ secrets.CONSOLE_PASSWORD }} \ | |
--targets pe_nodes \ | |
--verbose | |
- name: output value of bolt-debug.log | |
if: ${{ failure() }} | |
run: | | |
echo ::group::bolt-debug-log | |
if [ -f bolt-debug.log ]; then | |
echo "=== bolt-debug.log contents ===" | |
cat bolt-debug.log || echo "bolt-debug.log is empty" | |
else | |
echo "No bolt-debug.log file found" | |
fi | |
echo ::endgroup:: | |
- name: Tear down test cluster | |
if: ${{ always() }} | |
continue-on-error: true | |
run: |- | |
if [ -f spec/fixtures/litmus_inventory.yaml ]; then | |
echo ::group::tear_down | |
bundle exec rake 'litmus:tear_down' | |
echo ::endgroup:: | |
echo ::group::info:request | |
cat request.json || true; echo | |
echo ::endgroup:: | |
fi |