pipeline { agent any environment { DOCKER_IMAGE = 'postgres:18-alpine' COMPOSE_FILE = 'docker-compose.yml' BACKUP_RETENTION = '7' POSTGRES_DB = 'datashield' POSTGRES_USER = 'collabhubmaster' POSTGRES_PASSWORD = credentials('postgres-password') } options { buildDiscarder(logRotator(numToKeepStr: '10')) timeout(time: 20 unit: 'MINUTES') timestamps() } triggers { // Poll SCM every hour for changes pollSCM('H * * * *') // Deploy every night at 2 AM cron('H 2 * * *') } stages { stage('Checkout') { steps { script { // Clean workspace cleanWs() // Checkout code checkout scm echo "โœ… Code checked out successfully" echo "๐Ÿ“‚ Working directory: ${pwd()}" echo "๐ŸŒฟ Git branch: ${env.BRANCH_NAME}" echo "๐Ÿท๏ธ Git commit: ${env.GIT_COMMIT}" } } } stage('Validate Configuration') { steps { script { echo "๐Ÿ” Validating configuration files..." // Check if required files exist def requiredFiles = [ 'docker-compose.postgres.yml' 'docker-compose.postgres.prod.yml' 'postgresql/conf/postgresql.conf' 'postgresql/conf/pg_hba.conf' 'postgresql/init/01-init-database.sh' 'postgresql/scripts/deploy.sh' ] requiredFiles.each { file -> if (!fileExists(file)) { error "โŒ Required file missing: ${file}" } else { echo "โœ… Found: ${file}" } } // Validate docker-compose syntax sh """ echo "๐Ÿณ Validating Docker Compose files..." docker-compose -f ${env.COMPOSE_FILE} config --quiet docker-compose -f ${env.COMPOSE_FILE} config --quiet """ // Validate PostgreSQL configuration sh """ echo "๐Ÿ—„๏ธ Validating PostgreSQL configuration..." # Basic syntax check for postgresql.conf grep -E '^(shared_buffers|effective_cache_size|work_mem)' postgresql/conf/postgresql.conf """ } } } stage('System Health Check') { steps { script { echo "๐Ÿ” Checking system resources..." // Check Docker availability sh """ if ! docker info >/dev/null 2>&1; then echo "โŒ Docker is not running" exit 1 fi echo "โœ… Docker is running" # Check system resources echo "๐Ÿ’พ Memory information:" free -h echo "๐Ÿ’ฟ Disk space:" df -h . echo "๐Ÿ–ฅ๏ธ CPU information:" nproc """ } } } stage('Deploy PostgreSQL') { when { anyOf { branch 'main' branch 'master' changeset "**/*.yml" changeset "**/*.yaml" changeset "**/conf/**" changeset "**/init/**" } } steps { script { def isProduction = env.BRANCH_NAME == 'main' || env.BRANCH_NAME == 'master' def environment = isProduction ? 'production' : 'development' echo "๐Ÿš€ Deploying PostgreSQL in ${environment} mode..." try { // Set script permissions sh 'chmod +x postgresql/scripts/*.sh' // Deploy based on environment if (isProduction) { echo "๐Ÿญ Production deployment..." sh """ docker-compose -f ${env.COMPOSE_FILE} down docker-compose -f ${env.COMPOSE_FILE} up -d """ } else { echo "๐Ÿงช Development deployment..." sh """ docker-compose -f ${env.COMPOSE_FILE} down docker-compose -f ${env.COMPOSE_FILE} up -d """ } // Wait for database to be ready echo "โณ Waiting for database to be ready..." timeout(time: 2 unit: 'MINUTES') { sh ''' while ! docker exec datashield-postgres pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}; do echo "โณ Waiting for PostgreSQL..." sleep 5 done ''' } echo "โœ… PostgreSQL deployed successfully" } catch (Exception e) { echo "โŒ Deployment failed: ${e.getMessage()}" // Show logs for debugging sh 'docker logs datashield-postgres' throw e } } } } stage('Verify Deployment') { steps { script { echo "๐Ÿ” Verifying deployment..." // Check containers sh """ echo "๐Ÿณ Container status:" docker ps | grep datashield || echo "โŒ No datashield containers running" """ // Test database connection sh """ echo "๐Ÿ”— Testing database connection..." docker exec datashield-postgres psql -U ${POSTGRES_USER} -d ${POSTGRES_DB} -c "SELECT 1 as connection_test;" echo "๐Ÿ“Š Database statistics:" docker exec datashield-postgres psql -U ${POSTGRES_USER} -d ${POSTGRES_DB} -c " SELECT 'datashield schema exists' as check COUNT(*)::text as result FROM information_schema.schemata WHERE schema_name = 'datashield'; " """ // Test backup system sh """ echo "๐Ÿ’พ Testing backup system..." docker exec datashield-backup /scripts/backup_check.sh || echo "โš ๏ธ Backup check not available (container might be starting)" """ echo "โœ… Deployment verification completed" } } } stage('Performance Test') { when { anyOf { branch 'main' branch 'master' } } steps { script { echo "โšก Running performance tests..." sh """ echo "๐Ÿ“ˆ Running basic performance queries..." docker exec datashield-postgres psql -U ${POSTGRES_USER} -d ${POSTGRES_DB} -c " -- Test basic query performance EXPLAIN ANALYZE SELECT COUNT(*) FROM datashield.users; -- Test index usage EXPLAIN ANALYZE SELECT * FROM datashield.users WHERE email LIKE 'test%@example.com' LIMIT 10; -- Test materialized view SELECT COUNT(*) FROM datashield.user_analytics; " || echo "โš ๏ธ Performance test queries failed (might be empty database)" """ echo "โœ… Performance tests completed" } } } stage('Create Backup') { when { anyOf { branch 'main' branch 'master' buildingTag() } } steps { script { def timestamp = new Date().format('yyyyMMdd_HHmmss') def backupFile = "jenkins_backup_${timestamp}.sql" echo "๐Ÿ’พ Creating deployment backup: ${backupFile}" sh """ # Create backup directory mkdir -p jenkins_backups # Create backup docker exec datashield-postgres pg_dump \ -U ${POSTGRES_USER} \ -d ${POSTGRES_DB} \ --format=custom \ --compress=9 \ --file="/tmp/${backupFile}" # Copy backup from container docker cp datashield-postgres:/tmp/${backupFile} jenkins_backups/ # Create checksum cd jenkins_backups sha256sum ${backupFile} > ${backupFile}.sha256 echo "โœ… Backup created: jenkins_backups/${backupFile}" ls -lh jenkins_backups/${backupFile} """ // Archive backup artifacts archiveArtifacts artifacts: 'jenkins_backups/*.sqljenkins_backups/*.sha256' fingerprint: true allowEmptyArchive: true } } } } post { always { script { echo "๐Ÿ“‹ Pipeline completed with status: ${currentBuild.currentResult}" // Generate pipeline summary def summary = """ ๐ŸŽฏ DataShield PostgreSQL Deployment Pipeline ๐Ÿ“… Build: ${env.BUILD_NUMBER} ๐ŸŒฟ Branch: ${env.BRANCH_NAME} ๐Ÿท๏ธ Commit: ${env.GIT_COMMIT?.take(8)} โฑ๏ธ Duration: ${currentBuild.durationString} โœ… Status: ${currentBuild.currentResult} """ echo summary // Clean up old artifacts (keep last 5) sh 'find jenkins_backups -name "*.sql" -type f | sort -r | tail -n +6 | xargs rm -f || true' } } success { script { echo "๐ŸŽ‰ PostgreSQL deployment successful!" // Send success notification (customize as needed) // emailext ( // subject: "โœ… DataShield PostgreSQL deployed successfully" // body: "PostgreSQL has been deployed successfully on ${env.NODE_NAME}.\\n\\nBuild: ${env.BUILD_URL}" // to: "${env.CHANGE_AUTHOR_EMAIL}" // ) } } failure { script { echo "โŒ PostgreSQL deployment failed!" // Show container logs for debugging sh ''' echo "๐Ÿณ Container logs:" docker logs datashield-postgres 2>&1 | tail -n 50 || echo "Could not get container logs" echo "๐Ÿ“‹ System status:" docker ps -a | grep datashield || echo "No datashield containers found" ''' // Send failure notification (customize as needed) // emailext ( // subject: "โŒ DataShield PostgreSQL deployment failed" // body: "PostgreSQL deployment failed on ${env.NODE_NAME}.\\n\\nBuild: ${env.BUILD_URL}\\n\\nPlease check the logs for details." // to: "${env.CHANGE_AUTHOR_EMAIL}" // ) } } unstable { script { echo "โš ๏ธ PostgreSQL deployment completed with warnings!" } } cleanup { script { echo "๐Ÿงน Cleaning up workspace..." // Remove temporary files sh 'rm -f *.tmp || true' // Stop development containers on non-main branches if (env.BRANCH_NAME != 'main' && env.BRANCH_NAME != 'master') { sh 'docker-compose -f docker-compose.yml down || true' } } } } }