diff --git a/Jenkinsfile b/Jenkinsfile index b1fd001..828d556 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -42,6 +42,7 @@ pipeline { environment { ANSIBLE_HOST_KEY_CHECKING = 'False' ANSIBLE_FORCE_COLOR = 'true' + OPNSENSE_HOST = '192.168.0.1' } stages { @@ -94,30 +95,58 @@ pipeline { } } - stage('Wait for Machine to Boot') { + stage('Get VM IP from DHCP') { steps { - script { - // Use template hostname for ping since the cloned machine still has the template's hostname - def templateHost = params.PROVISION_TYPE == 'VM' ? 'ubuntu24vm' : 'ubuntu24lxc' - def targetHost = "${templateHost}.lan" - echo "Waiting for ${targetHost} (template hostname) to become available..." + withCredentials([usernamePassword(credentialsId: 'opnsense-api', usernameVariable: 'OPNSENSE_KEY', passwordVariable: 'OPNSENSE_SECRET')]) { + script { + def templateHost = params.PROVISION_TYPE == 'VM' ? 'ubuntu24vm' : 'ubuntu24lxc' + echo "Looking up DHCP lease for hostname: ${templateHost}" - // Wait up to 5 minutes for the machine to respond to ping - timeout(time: 5, unit: 'MINUTES') { - waitUntil { - // Flush DNS cache before each ping attempt - sh(script: "sudo systemd-resolve --flush-caches 2>/dev/null || sudo resolvectl flush-caches 2>/dev/null || sudo nscd -i hosts 2>/dev/null || true", returnStatus: true) + // Wait for DHCP lease to appear + def vmIp = '' + timeout(time: 5, unit: 'MINUTES') { + waitUntil { + sleep(time: 10, unit: 'SECONDS') - def result = sh( - script: "ping -c 1 ${targetHost} > /dev/null 2>&1", - returnStatus: true - ) - return result == 0 + // Query OPNSense DHCP leases API + def response = sh( + script: """ + curl -s -k -u "\${OPNSENSE_KEY}:\${OPNSENSE_SECRET}" \ + "https://${OPNSENSE_HOST}/api/dhcpv4/leases/searchLease" + """, + returnStdout: true + ).trim() + + // Parse JSON and find the lease with matching hostname + def leases = readJSON text: response + def matchingLease = leases.rows?.find { it.hostname == templateHost || it['client-hostname'] == templateHost } + + if (matchingLease) { + vmIp = matchingLease.address + echo "Found IP address: ${vmIp} for hostname: ${templateHost}" + return true + } + echo "DHCP lease not found yet, retrying..." + return false + } } - } - // Additional wait for SSH to be ready - sleep(time: 30, unit: 'SECONDS') + // Store IP for subsequent stages + env.VM_IP = vmIp + echo "VM IP address: ${env.VM_IP}" + + // Wait for SSH to be ready + timeout(time: 3, unit: 'MINUTES') { + waitUntil { + def result = sh( + script: "nc -z -w5 ${env.VM_IP} 22", + returnStatus: true + ) + return result == 0 + } + } + sleep(time: 10, unit: 'SECONDS') + } } } } @@ -125,13 +154,8 @@ pipeline { stage('Copy Jenkins SSH Key') { steps { script { - def templateHost = params.PROVISION_TYPE == 'VM' ? 'ubuntu24vm' : 'ubuntu24lxc' - def targetHost = "${templateHost}.lan" - - // Use sshpass or expect to handle the initial connection - // This assumes the template has a default user that accepts the key sh """ - sudo -u jenkins ssh-copy-id -i /var/lib/jenkins/.ssh/id_ed25519.pub -o StrictHostKeyChecking=no jenkins@${targetHost} + sudo -u jenkins ssh-copy-id -i /var/lib/jenkins/.ssh/id_ed25519.pub -o StrictHostKeyChecking=no jenkins@${env.VM_IP} """ } } @@ -140,16 +164,14 @@ pipeline { stage('Set Hostname') { steps { script { - def templateHost = params.PROVISION_TYPE == 'VM' ? 'ubuntu24vm' : 'ubuntu24lxc' - def currentHost = "${templateHost}.lan" def newHostname = params.HOSTNAME - // Create a temporary inventory file with the current host + // Create a temporary inventory file with the VM IP writeFile file: 'temp_inventory.yml', text: """--- all: hosts: new_host: - ansible_host: ${currentHost} + ansible_host: ${env.VM_IP} ansible_user: jenkins ansible_ssh_private_key_file: /var/lib/jenkins/.ssh/id_ed25519 """ @@ -159,20 +181,6 @@ all: -i temp_inventory.yml \ -e "new_hostname=${newHostname}" """ - - // Wait for the machine to come back up with the new hostname - echo "Waiting for ${newHostname}.lan to become available..." - sleep(time: 30, unit: 'SECONDS') - - timeout(time: 3, unit: 'MINUTES') { - waitUntil { - def result = sh( - script: "ping -c 1 ${newHostname}.lan > /dev/null 2>&1", - returnStatus: true - ) - return result == 0 - } - } } } } @@ -180,14 +188,12 @@ all: stage('Configure Machine') { steps { script { - def targetHost = "${params.HOSTNAME}.lan" - - // Create a temporary inventory file with the new host + // Create a temporary inventory file - still use IP since DNS may not have updated writeFile file: 'temp_inventory.yml', text: """--- all: hosts: new_host: - ansible_host: ${targetHost} + ansible_host: ${env.VM_IP} ansible_user: jenkins ansible_ssh_private_key_file: /var/lib/jenkins/.ssh/id_ed25519 """ @@ -210,7 +216,7 @@ all: } success { echo "Successfully provisioned ${params.PROVISION_TYPE} '${params.HOSTNAME}' on ${params.TARGET_NODE}" - echo "Machine is accessible at ${params.HOSTNAME}.lan" + echo "Machine is accessible at ${params.HOSTNAME}.lan (IP: ${env.VM_IP})" } failure { echo "Failed to provision ${params.PROVISION_TYPE} '${params.HOSTNAME}'"