diff options
| author | Artur Pak <[email protected]> | 2025-02-17 14:19:01 +0800 |
|---|---|---|
| committer | Artur Pak <[email protected]> | 2025-02-18 15:24:37 +0800 |
| commit | c3e1f71e4c027e9165a55e05e3130ace2d3bcdf5 (patch) | |
| tree | 48b29bb15180eff84cf5abadef49cf7c5ba5b5e0 | |
| parent | 4136ef2984187244170024eff235b5875c2d8757 (diff) | |
Add script to trigger image deploy job many timesdeploy-50
| -rwxr-xr-x | trigger_image_deploy.py | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/trigger_image_deploy.py b/trigger_image_deploy.py new file mode 100755 index 0000000..bb76696 --- /dev/null +++ b/trigger_image_deploy.py @@ -0,0 +1,204 @@ +#!/usr/bin/env python3 +""" +This script can trigger infrastructure-image-deploy job multiple times. +After build is completed, a new job is triggered. + +If there is a job in Progress triggered by another user, then a Pending job is created. + +But if there is a Pending job by another user, then we wait for it to finish +then trigger our Pending job. +""" + +import sys +import logging +import argparse +import time + +from trigger_sanity_c3 import get_jenkins_connection + +logger = logging.getLogger("trigger-image-deploy") + + +def trigger_job(server, job_name, parameters, wait_timeout, dry_run=False): + """Trigger the Jenkins job with given parameters.""" + SLEEP_TIME = 180 + MAX_ATTEMPTS = int(wait_timeout / SLEEP_TIME + 1) + logger.debug(f"Attempting to trigger job: {job_name} with parameters: {parameters}") + try: + if dry_run: + logger.info(f"[DRY RUN] Would trigger job: {job_name} with parameters:") + for key, value in parameters.items(): + logger.info(f" {key}: {value}") + return None + else: + # Keep the last build number before we trigger + last_build_number = server.get_job_info(job_name)["lastBuild"]["number"] + logger.debug(f"last_build_number: {last_build_number}") + + # Don't trigger build if there are Pending jobs, because it will fail + PENDING_ATTEMPTS = 0 + while PENDING_ATTEMPTS < MAX_ATTEMPTS: + logger.debug(f"Pending jobs in Queue: {server.get_queue_info()}") + if server.get_queue_info(): + logger.info( + f"Found Pending job in queue. Waiting {SLEEP_TIME} sec..." + ) + time.sleep(SLEEP_TIME) + PENDING_ATTEMPTS += 1 + else: + break + MAX_ATTEMPTS -= PENDING_ATTEMPTS + + # Trigger our job + # If job is already running, then we trigger a new Pending job + server.build_job(job_name, parameters=parameters) + for attempt in range(MAX_ATTEMPTS): + # job started + current_build_number = server.get_job_info(job_name)["lastBuild"][ + "number" + ] + logger.debug(f"current_build_number: {current_build_number}") + if current_build_number > last_build_number: + logger.info( + f"Successfully triggered {job_name} build {current_build_number}" + ) + return current_build_number + logger.debug( + f"Waiting for the new build to be triggered...Sleep {SLEEP_TIME} sec" + ) + time.sleep(SLEEP_TIME) + + # Build was not triggered + logger.error( + f"Failed to trigger {job_name} after build {last_build_number}" + ) + return False + except Exception as e: + logger.error(f"Failed to trigger job {job_name}: {e}") + return False + + +def verify_job_success(server, job_name, build_number, wait_timeout): + """Poll the Jenkins job status until it completes and return True if successful.""" + SLEEP_TIME = 180 + MAX_ATTEMPTS = int(wait_timeout / SLEEP_TIME + 1) + logger.debug( + f"Set timeout after {MAX_ATTEMPTS} tries. Sleep after try: {SLEEP_TIME} sec" + ) + + for attempt in range(MAX_ATTEMPTS): + try: + # Fetch job info + job_info = server.get_build_info(job_name, build_number) + logger.debug(f"job_info for build {build_number}: {job_info}") + status = job_info.get("result") + if status is None: + logger.info( + f"Build {build_number} is still running... Sleep {SLEEP_TIME} sec..." + ) + time.sleep(SLEEP_TIME) + elif status == "SUCCESS": + logger.info(f"Build {build_number} completed successfully.") + return True + else: + logger.error(f"Build {build_number} failed with status: {status}") + return False + except Exception as e: + logger.error(f"Error fetching job info on attempt {attempt}: {e}") + time.sleep(SLEEP_TIME) + + logger.error("Max attempts reached. Unable to verify job status.") + return False + + +def parse_arguments(): + parser = argparse.ArgumentParser( + description="Trigger infrastructure-image-deploy job" + ) + parser.add_argument( + "--iso-url", help="URL to ISO file (required when --cid is not provided)" + ) + parser.add_argument( + "--cid", + help="Specific CID to trigger the job on. If not provided, we search C3 for all compatible machines", + ) + parser.add_argument( + "--job-name", + default="infrastructure-image-deploy", + help="Jenkins job name (default: infrastructure-image-deploy)", + ) + parser.add_argument( + "--put-dell-embargo", + action="store_true", + help="Put Dell embargo on the results", + ) + parser.add_argument( + "--dry-run", action="store_true", help="Run without triggering Jenkins jobs" + ) + parser.add_argument( + "--wait-success", + action="store_true", + help="Wait for the job to succeed after trigger (single CID only)", + ) + parser.add_argument( + "--wait-timeout", + type=int, + default=3600, + help="Timeout period with --wait-success in seconds (Default: 3600 seconds)", + ) + parser.add_argument( + "--trigger-times", + type=int, + default=1, + help="Number of times to trigger the job (Default: 1 time)", + ) + parser.add_argument("--debug", action="store_true", help="Enable debug logging") + args = parser.parse_args() + + # Validate arguments + if not args.cid or not args.iso_url: + parser.error("URL and CID are required") + + return args + + +def main(): + args = parse_arguments() + + # Set up logging based on debug flag + log_level = logging.DEBUG if args.debug else logging.INFO + logging.basicConfig( + level=log_level, format="%(asctime)s - %(levelname)s - %(message)s" + ) + + parameters = {} + parameters["ISO_URL"] = args.iso_url + parameters["TARGET_IDs"] = args.cid + job_name = "infrastructure-image-deploy" + if args.job_name: + job_name = args.job_name + + jenkins_server = get_jenkins_connection() + + for trigger_count in range(args.trigger_times): + logger.info(f"Trigger counter: {trigger_count}") + logger.info(f"Triggering job: {job_name} for {args.cid}") + + build_number = trigger_job( + jenkins_server, job_name, parameters, args.wait_timeout, args.dry_run + ) + if not build_number: + logger.error(f"Failed to trigger job: {job_name}") + sys.exit(1) + if not args.dry_run and args.wait_success and build_number: + # poll the job status untill it succeed + if not verify_job_success( + jenkins_server, job_name, build_number, args.wait_timeout + ): + logger.error(f"Triggered job was not successful: {job_name}") + sys.exit(1) + logger.info(f"Job completed successfully: {job_name}") + + +if __name__ == "__main__": + main() |
