summaryrefslogtreecommitdiff
diff options
authorArtur Pak <[email protected]>2025-02-17 14:19:01 +0800
committerArtur Pak <[email protected]>2025-02-18 15:24:37 +0800
commitc3e1f71e4c027e9165a55e05e3130ace2d3bcdf5 (patch)
tree48b29bb15180eff84cf5abadef49cf7c5ba5b5e0
parent4136ef2984187244170024eff235b5875c2d8757 (diff)
Add script to trigger image deploy job many timesdeploy-50
-rwxr-xr-xtrigger_image_deploy.py204
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()