Dennis Dmitriev | 3ec2e53 | 2018-06-08 04:33:34 +0300 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | |
| 3 | import argparse |
| 4 | import os |
| 5 | import sys |
| 6 | |
| 7 | import json |
| 8 | |
| 9 | sys.path.append(os.getcwd()) |
| 10 | try: |
| 11 | from tcp_tests.managers.jenkins.client import JenkinsClient |
| 12 | except ImportError: |
| 13 | print("ImportError: Run the application from the tcp-qa directory or " |
| 14 | "set the PYTHONPATH environment variable to directory which contains" |
| 15 | " ./tcp_tests") |
| 16 | sys.exit(1) |
| 17 | |
| 18 | |
| 19 | EXIT_CODES = { |
| 20 | "SUCCESS": 0, |
| 21 | # 1 - python runtime execution error |
| 22 | # 2 - job unknown status |
| 23 | "FAILURE": 3, |
| 24 | "UNSTABLE": 4, |
| 25 | "ABORTED": 5, |
| 26 | "DISABLED": 6 |
| 27 | # 10 - invalid cli options |
| 28 | } |
| 29 | |
| 30 | |
| 31 | def load_params(): |
| 32 | """ |
| 33 | Parse CLI arguments and environment variables |
| 34 | |
| 35 | Returns: ArgumentParser instance |
| 36 | """ |
| 37 | env_host = os.environ.get('JENKINS_URL', None) |
| 38 | env_username = os.environ.get('JENKINS_USER', None) |
| 39 | env_password = os.environ.get('JENKINS_PASS', None) |
| 40 | env_start_timeout = os.environ.get('JENKINS_START_TIMEOUT', 1800) |
| 41 | env_build_timeout = os.environ.get('JENKINS_BUILD_TIMEOUT', 3600 * 4) |
| 42 | |
| 43 | parser = argparse.ArgumentParser(description=( |
| 44 | 'Host, username and password may be specified either by the command ' |
| 45 | 'line arguments or using environment variables: JENKINS_URL, ' |
| 46 | 'JENKINS_USER, JENKINS_PASS, JENKINS_START_TIMEOUT, ' |
| 47 | 'JENKINS_BUILD_TIMEOUT. \nCommand line arguments have the highest ' |
| 48 | 'priority, after that the environment variables are used as defaults.' |
| 49 | )) |
| 50 | parser.add_argument('--host', |
| 51 | metavar='JENKINS_URL', |
| 52 | help='Jenkins Host', |
| 53 | default=env_host) |
| 54 | parser.add_argument('--username', |
| 55 | metavar='JENKINS_USER', |
| 56 | help='Jenkins Username', default=env_username) |
| 57 | parser.add_argument('--password', |
| 58 | metavar='JENKINS_PASS', |
| 59 | help='Jenkins Password or API token', |
| 60 | default=env_password) |
| 61 | parser.add_argument('--start-timeout', |
| 62 | metavar='JENKINS_START_TIMEOUT', |
| 63 | help='Timeout waiting until build is started', |
| 64 | default=env_start_timeout, |
| 65 | type=int) |
| 66 | parser.add_argument('--build-timeout', |
| 67 | metavar='JENKINS_BUILD_TIMEOUT', |
| 68 | help='Timeout waiting until build is finished', |
| 69 | default=env_build_timeout, |
| 70 | type=int) |
| 71 | parser.add_argument('--job-name', |
| 72 | help='Jenkins job name to run', |
| 73 | default=None) |
| 74 | parser.add_argument('--job-parameters', |
| 75 | metavar='json-dict', |
| 76 | help=('Job parameters to use instead of default ' |
| 77 | 'values, as a json string, for example: ' |
| 78 | '--job-parameters=\'{"SALT_MASTER_URL": ' |
| 79 | '"http://localhost:6969"}\''), |
| 80 | default={}, type=json.loads) |
| 81 | parser.add_argument('--job-output-prefix', |
| 82 | help=('Jenkins job output prefix for each line in the ' |
| 83 | 'output, if --verbose is enabled. Useful for the' |
| 84 | ' pipelines that use multiple different runs of ' |
| 85 | 'jobs. The string is a template for python ' |
| 86 | 'format() function where the following arguments' |
| 87 | ' are allowed: job_name, build_number. ' |
| 88 | 'Example: --job-output-prefix=\"[ {job_name} ' |
| 89 | '#{build_number}, core ]\"'), |
| 90 | default='', |
| 91 | type=str) |
| 92 | parser.add_argument('--verbose', |
| 93 | action='store_const', |
| 94 | const=True, |
| 95 | help='Show build console output', |
| 96 | default=False) |
| 97 | return parser |
| 98 | |
| 99 | |
Dennis Dmitriev | 2a49873 | 2018-12-21 18:30:23 +0200 | [diff] [blame] | 100 | def print_build_header(build, job_params, build_timeout): |
Dennis Dmitriev | 3ec2e53 | 2018-06-08 04:33:34 +0300 | [diff] [blame] | 101 | print('\n#############################################################') |
| 102 | print('##### Building job [{0}] #{1} (timeout={2}) with the following ' |
Dennis Dmitriev | 2a49873 | 2018-12-21 18:30:23 +0200 | [diff] [blame] | 103 | 'parameters:'.format(build[0], build[1], build_timeout)) |
Dennis Dmitriev | 3ec2e53 | 2018-06-08 04:33:34 +0300 | [diff] [blame] | 104 | print('##### ' + '\n##### '.join( |
| 105 | [str(key) + ": " + str(val) for key, val in job_params.iteritems()] |
| 106 | )) |
| 107 | print('#############################################################') |
| 108 | |
| 109 | |
| 110 | def print_build_footer(build, result, url): |
| 111 | print('\n\n#############################################################') |
| 112 | print('##### Completed job [{0}] #{1} at {2}: {3}' |
| 113 | .format(build[0], build[1], url, result)) |
| 114 | print('#############################################################\n') |
| 115 | |
| 116 | |
Dennis Dmitriev | 2a49873 | 2018-12-21 18:30:23 +0200 | [diff] [blame] | 117 | def run_job(host, username, password, |
| 118 | job_name, job_parameters=None, job_output_prefix='', |
| 119 | start_timeout=1800, build_timeout=3600 * 4, verbose=False): |
Dennis Dmitriev | 3ec2e53 | 2018-06-08 04:33:34 +0300 | [diff] [blame] | 120 | |
| 121 | jenkins = JenkinsClient( |
Dennis Dmitriev | 2a49873 | 2018-12-21 18:30:23 +0200 | [diff] [blame] | 122 | host=host, |
| 123 | username=username, |
| 124 | password=password) |
Dennis Dmitriev | 3ec2e53 | 2018-06-08 04:33:34 +0300 | [diff] [blame] | 125 | |
Hanna Arhipova | 874c68f | 2021-03-29 15:57:19 +0300 | [diff] [blame] | 126 | job_params = jenkins.make_defaults_params(job_name) |
Dennis Dmitriev | 2a49873 | 2018-12-21 18:30:23 +0200 | [diff] [blame] | 127 | if job_parameters is not None: # job_parameters = {} |
| 128 | job_params.update(job_parameters) |
Dennis Dmitriev | 3ec2e53 | 2018-06-08 04:33:34 +0300 | [diff] [blame] | 129 | |
Dennis Dmitriev | 2a49873 | 2018-12-21 18:30:23 +0200 | [diff] [blame] | 130 | build = jenkins.run_build(job_name, |
Dennis Dmitriev | 3ec2e53 | 2018-06-08 04:33:34 +0300 | [diff] [blame] | 131 | job_params, |
Dennis Dmitriev | 2a49873 | 2018-12-21 18:30:23 +0200 | [diff] [blame] | 132 | verbose=verbose, |
| 133 | timeout=start_timeout) |
| 134 | if verbose: |
| 135 | print_build_header(build, job_params, build_timeout) |
Dennis Dmitriev | 3ec2e53 | 2018-06-08 04:33:34 +0300 | [diff] [blame] | 136 | |
Dennis Dmitriev | 13e804b | 2018-10-09 19:25:14 +0300 | [diff] [blame] | 137 | try: |
| 138 | jenkins.wait_end_of_build( |
| 139 | name=build[0], |
| 140 | build_id=build[1], |
Dennis Dmitriev | 2a49873 | 2018-12-21 18:30:23 +0200 | [diff] [blame] | 141 | timeout=build_timeout, |
Dennis Dmitriev | 13e804b | 2018-10-09 19:25:14 +0300 | [diff] [blame] | 142 | interval=1, |
Dennis Dmitriev | 2a49873 | 2018-12-21 18:30:23 +0200 | [diff] [blame] | 143 | verbose=verbose, |
| 144 | job_output_prefix=job_output_prefix) |
Dennis Dmitriev | efe5c0b | 2018-10-24 20:35:26 +0300 | [diff] [blame] | 145 | except Exception as e: |
Dennis Dmitriev | 13e804b | 2018-10-09 19:25:14 +0300 | [diff] [blame] | 146 | print(str(e)) |
| 147 | raise |
| 148 | |
Dennis Dmitriev | 3ec2e53 | 2018-06-08 04:33:34 +0300 | [diff] [blame] | 149 | result = jenkins.build_info(name=build[0], |
| 150 | build_id=build[1])['result'] |
Dennis Dmitriev | 2a49873 | 2018-12-21 18:30:23 +0200 | [diff] [blame] | 151 | if verbose: |
| 152 | print_build_footer(build, result, host) |
Dennis Dmitriev | 3ec2e53 | 2018-06-08 04:33:34 +0300 | [diff] [blame] | 153 | |
Dennis Dmitriev | 2a49873 | 2018-12-21 18:30:23 +0200 | [diff] [blame] | 154 | return result |
Dennis Dmitriev | 3ec2e53 | 2018-06-08 04:33:34 +0300 | [diff] [blame] | 155 | |
| 156 | |
| 157 | def main(args=None): |
| 158 | parser = load_params() |
| 159 | opts = parser.parse_args() |
| 160 | |
| 161 | if opts.host is None or opts.job_name is None: |
| 162 | print("JENKINS_URL and a job name are required!") |
| 163 | parser.print_help() |
| 164 | return 10 |
| 165 | else: |
Dennis Dmitriev | 2a49873 | 2018-12-21 18:30:23 +0200 | [diff] [blame] | 166 | result = run_job( |
| 167 | opts.host, |
| 168 | opts.username, |
| 169 | opts.password, |
| 170 | opts.job_name, |
| 171 | opts.job_parameters, |
| 172 | opts.job_output_prefix, |
| 173 | opts.start_timeout, |
| 174 | opts.build_timeout, |
| 175 | opts.verbose) |
| 176 | return EXIT_CODES.get(result, 2) |
Dennis Dmitriev | 3ec2e53 | 2018-06-08 04:33:34 +0300 | [diff] [blame] | 177 | |
| 178 | |
| 179 | if __name__ == "__main__": |
| 180 | sys.exit(main()) |