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