747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
1 |
#!/usr/bin/python
|
749.1.18
by Curtis Hovey
Get the build-revision from the job parameters. |
2 |
"""Manage the blessed juju revision testing candiates."""
|
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
3 |
|
4 |
from __future__ import print_function |
|
5 |
||
6 |
from argparse import ArgumentParser |
|
822.1.1
by John George
While publishing weekly streams, backup the buildvars.json files to S3, to maintain a record of the builds that have been published. |
7 |
import datetime |
749.1.3
by Curtis Hovey
Added extract command to canidate module. |
8 |
import json |
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
9 |
import os |
10 |
import shutil |
|
749.1.3
by Curtis Hovey
Added extract command to canidate module. |
11 |
import subprocess |
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
12 |
import sys |
13 |
import traceback |
|
14 |
||
15 |
from jujuci import ( |
|
849.1.1
by Aaron Bentley
Use credentials for candidate download. |
16 |
add_credential_args, |
776.1.8
by Curtis Hovey
Move juju-ci job names to jujuci.py. |
17 |
BUILD_REVISION, |
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
18 |
get_build_data, |
19 |
get_artifacts, |
|
849.1.1
by Aaron Bentley
Use credentials for candidate download. |
20 |
get_credentials, |
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
21 |
JENKINS_URL, |
776.1.8
by Curtis Hovey
Move juju-ci job names to jujuci.py. |
22 |
PUBLISH_REVISION
|
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
23 |
)
|
822.1.1
by John George
While publishing weekly streams, backup the buildvars.json files to S3, to maintain a record of the builds that have been published. |
24 |
from utility import ( |
889.6.6
by Aaron Bentley
Extract extract_deb. |
25 |
extract_deb, |
889.6.1
by Aaron Bentley
Make utility for determining architecture. |
26 |
get_deb_arch, |
1522.1.1
by Aaron Bentley
Use common code for finding revision build in candidates. |
27 |
get_revision_build, |
1001.1.1
by John George
Add openstack_basic_check.py |
28 |
run_command, |
822.1.1
by John George
While publishing weekly streams, backup the buildvars.json files to S3, to maintain a record of the builds that have been published. |
29 |
s3_cmd, |
30 |
temp_dir, |
|
31 |
)
|
|
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
32 |
|
33 |
||
849.1.1
by Aaron Bentley
Use credentials for candidate download. |
34 |
def find_publish_revision_number(credentials, br_number, limit=20): |
747.2.2
by Curtis Hovey
Fix doc. |
35 |
"""Return the publish-revsion number paired with build-revision number."""
|
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
36 |
found_number = None |
37 |
job_number = 'lastSuccessfulBuild' |
|
38 |
for i in range(limit): |
|
39 |
build_data = get_build_data( |
|
849.1.1
by Aaron Bentley
Use credentials for candidate download. |
40 |
JENKINS_URL, credentials, PUBLISH_REVISION, build=job_number) |
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
41 |
if not build_data: |
42 |
return None |
|
43 |
# Ensure we have the real job number (an int), not an alias.
|
|
44 |
job_number = build_data['number'] |
|
1522.1.1
by Aaron Bentley
Use common code for finding revision build in candidates. |
45 |
if get_revision_build(build_data) == str(br_number): |
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
46 |
found_number = job_number |
47 |
break
|
|
48 |
job_number = job_number - 1 |
|
49 |
return found_number |
|
50 |
||
51 |
||
749.1.3
by Curtis Hovey
Added extract command to canidate module. |
52 |
def prepare_dir(dir_path, dry_run=False, verbose=False): |
1063.2.1
by seman.said at canonical
Updated to extract OS X client from the artifacts directory. |
53 |
"""Create to clean a directory."""
|
749.1.3
by Curtis Hovey
Added extract command to canidate module. |
54 |
if os.path.isdir(dir_path): |
55 |
if verbose: |
|
56 |
print('Cleaning %s' % dir_path) |
|
57 |
if not dry_run: |
|
58 |
shutil.rmtree(dir_path) |
|
59 |
else: |
|
60 |
if verbose: |
|
61 |
print('Creating %s' % dir_path) |
|
62 |
if not dry_run: |
|
63 |
os.makedirs(dir_path) |
|
64 |
||
65 |
||
1052.2.1
by seman.said at canonical
Updated to rename the candidate directories to version numbers rather than branches. |
66 |
def download_candidate_files(credentials, release_number, path, br_number, |
749.1.19
by Curtis Hovey
Rename update_candidate to download_candidate_files. |
67 |
pr_number=None, dry_run=False, verbose=False): |
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
68 |
"""Download the files from the build-revision and publish-revision jobs.
|
69 |
||
70 |
The buildvars.json for the specific build-revision number is downloaded.
|
|
71 |
All the binary and source packages from the last successful build of
|
|
72 |
publish revision are downloaded.
|
|
73 |
"""
|
|
1052.2.1
by seman.said at canonical
Updated to rename the candidate directories to version numbers rather than branches. |
74 |
artifact_dir_name = '%s-artifacts' % release_number |
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
75 |
candidate_dir = os.path.join(path, artifact_dir_name) |
749.1.3
by Curtis Hovey
Added extract command to canidate module. |
76 |
prepare_dir(candidate_dir, dry_run, verbose) |
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
77 |
get_artifacts( |
849.1.1
by Aaron Bentley
Use credentials for candidate download. |
78 |
credentials, BUILD_REVISION, br_number, 'buildvars.json', |
79 |
candidate_dir, dry_run=dry_run, verbose=verbose) |
|
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
80 |
if not pr_number: |
849.1.1
by Aaron Bentley
Use credentials for candidate download. |
81 |
pr_number = find_publish_revision_number(credentials, br_number) |
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
82 |
get_artifacts( |
849.1.1
by Aaron Bentley
Use credentials for candidate download. |
83 |
credentials, PUBLISH_REVISION, pr_number, 'juju-core*', candidate_dir, |
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
84 |
dry_run=dry_run, verbose=verbose) |
85 |
||
86 |
||
749.1.3
by Curtis Hovey
Added extract command to canidate module. |
87 |
def get_artifact_dirs(path): |
749.1.14
by Curtis Hovey
Added tests for run_command. |
88 |
"""List the directories that contain artifacts."""
|
749.1.3
by Curtis Hovey
Added extract command to canidate module. |
89 |
dirs = [] |
90 |
for name in os.listdir(path): |
|
91 |
artifacts_path = os.path.join(path, name) |
|
92 |
if name.endswith('-artifacts') and os.path.isdir(artifacts_path): |
|
93 |
dirs.append(name) |
|
94 |
return dirs |
|
95 |
||
96 |
||
97 |
def get_package(artifacts_path, version): |
|
749.1.14
by Curtis Hovey
Added tests for run_command. |
98 |
"""Return the path to the expected juju-core package for the localhost."""
|
749.1.3
by Curtis Hovey
Added extract command to canidate module. |
99 |
release = subprocess.check_output(['lsb_release', '-sr']).strip() |
889.6.1
by Aaron Bentley
Make utility for determining architecture. |
100 |
arch = get_deb_arch() |
1287
by Curtis Hovey
Revert juju-core2 support. |
101 |
package_name = 'juju-core_{}-0ubuntu1~{}.1~juju1_{}.deb'.format( |
102 |
version, release, arch) |
|
749.1.3
by Curtis Hovey
Added extract command to canidate module. |
103 |
package_path = os.path.join(artifacts_path, package_name) |
104 |
return package_path |
|
105 |
||
106 |
||
107 |
def extract_candidates(path, dry_run=False, verbose=False): |
|
749.1.14
by Curtis Hovey
Added tests for run_command. |
108 |
"""Extract all the candidate juju binaries for the local machine.
|
109 |
||
1052.2.1
by seman.said at canonical
Updated to rename the candidate directories to version numbers rather than branches. |
110 |
Each candidate will be extracted to a directory named after the version
|
749.1.14
by Curtis Hovey
Added tests for run_command. |
111 |
the artifacts (packages) were made from. Thus the package that matches
|
112 |
the localhost's series and architecture in the master-artifacts/ directory
|
|
113 |
will be extracted to a sibling directory named "master/" The buildvars.json
|
|
114 |
data will be copied to the top of "master" to provide information about
|
|
115 |
the origin of the binaries.
|
|
116 |
"""
|
|
749.1.3
by Curtis Hovey
Added extract command to canidate module. |
117 |
for dir_name in get_artifact_dirs(path): |
118 |
artifacts_path = os.path.join(path, dir_name) |
|
119 |
buildvars_path = os.path.join(artifacts_path, 'buildvars.json') |
|
120 |
with open(buildvars_path) as bf: |
|
121 |
buildvars = json.load(bf) |
|
122 |
version = buildvars['version'] |
|
1086.1.1
by seman.said at canonical
Remove extracting OSX client into the candidate directory. |
123 |
package_path = get_package(artifacts_path, version) |
124 |
candidate_path = os.path.join(path, version) |
|
749.1.3
by Curtis Hovey
Added extract command to canidate module. |
125 |
if verbose: |
126 |
print('extracting %s to %s' % (package_path, candidate_path)) |
|
127 |
prepare_dir(candidate_path, dry_run, verbose) |
|
128 |
if not dry_run: |
|
1086.1.1
by seman.said at canonical
Remove extracting OSX client into the candidate directory. |
129 |
extract_deb(package_path, candidate_path) |
749.1.3
by Curtis Hovey
Added extract command to canidate module. |
130 |
if verbose: |
749.1.4
by Curtis Hovey
Cope buildvars.json to the candiate path, not the bin dir. |
131 |
print('Copying %s to %s' % (buildvars_path, candidate_path)) |
749.1.3
by Curtis Hovey
Added extract command to canidate module. |
132 |
if not dry_run: |
749.1.12
by Curtis Hovey
Added tests for extract_candidates. |
133 |
new_path = os.path.join(candidate_path, 'buildvars.json') |
134 |
shutil.copyfile(buildvars_path, new_path) |
|
935.1.1
by Curtis Hovey
Copy stats after copying buildvars. |
135 |
shutil.copystat(buildvars_path, new_path) |
749.1.3
by Curtis Hovey
Added extract command to canidate module. |
136 |
|
137 |
||
749.1.6
by Curtis Hovey
Added an untested publish function. |
138 |
def get_scripts(juju_release_tools=None): |
749.1.14
by Curtis Hovey
Added tests for run_command. |
139 |
"""Return a tuple paths to the assemble_script and publish_scripts."""
|
749.1.6
by Curtis Hovey
Added an untested publish function. |
140 |
assemble_script = 'assemble-streams.bash' |
141 |
publish_script = 'publish-public-tools.bash' |
|
142 |
if juju_release_tools: |
|
143 |
assemble_script = os.path.join( |
|
144 |
juju_release_tools, assemble_script) |
|
145 |
publish_script = os.path.join( |
|
146 |
juju_release_tools, publish_script) |
|
147 |
return assemble_script, publish_script |
|
148 |
||
149 |
||
150 |
def publish_candidates(path, streams_path, |
|
151 |
juju_release_tools=None, dry_run=False, verbose=False): |
|
749.1.14
by Curtis Hovey
Added tests for run_command. |
152 |
"""Assemble and publish weekly streams from the candidates."""
|
822.1.1
by John George
While publishing weekly streams, backup the buildvars.json files to S3, to maintain a record of the builds that have been published. |
153 |
timestamp = datetime.datetime.utcnow().strftime('%Y_%m_%dT%H_%M_%S') |
749.1.14
by Curtis Hovey
Added tests for run_command. |
154 |
with temp_dir() as debs_path: |
155 |
for dir_name in get_artifact_dirs(path): |
|
156 |
artifacts_path = os.path.join(path, dir_name) |
|
822.1.1
by John George
While publishing weekly streams, backup the buildvars.json files to S3, to maintain a record of the builds that have been published. |
157 |
branch_name = dir_name.split('-')[0] |
749.1.14
by Curtis Hovey
Added tests for run_command. |
158 |
for deb_name in os.listdir(artifacts_path): |
159 |
deb_path = os.path.join(artifacts_path, deb_name) |
|
749.1.17
by Curtis Hovey
Added tests for publish_candidates. |
160 |
if verbose: |
161 |
print('Copying %s' % deb_path) |
|
749.1.14
by Curtis Hovey
Added tests for run_command. |
162 |
new_path = os.path.join(debs_path, deb_name) |
163 |
shutil.copyfile(deb_path, new_path) |
|
822.1.1
by John George
While publishing weekly streams, backup the buildvars.json files to S3, to maintain a record of the builds that have been published. |
164 |
if deb_name == 'buildvars.json': |
165 |
# buildvars.json is also in the artifacts_path; copied by
|
|
166 |
# download_candidate_files(). Set it aside so it can be
|
|
167 |
# sync'd to S3 as a record of what was published.
|
|
168 |
buildvar_dir = '{}/weekly/{}/{}'.format( |
|
169 |
path, timestamp, branch_name) |
|
170 |
if not os.path.isdir(buildvar_dir): |
|
171 |
os.makedirs(buildvar_dir) |
|
172 |
buildvar_path = '{}/{}'.format(buildvar_dir, deb_name) |
|
173 |
shutil.copyfile(deb_path, buildvar_path) |
|
749.1.14
by Curtis Hovey
Added tests for run_command. |
174 |
assemble_script, publish_script = get_scripts(juju_release_tools) |
175 |
# XXX sinzui 2014-12-01: IGNORE uses the local juju, but when
|
|
176 |
# testing juju's that change generate-tools, we may need to use
|
|
177 |
# the highest version.
|
|
178 |
command = [ |
|
980.1.2
by Curtis Hovey
Hush lint. |
179 |
assemble_script, '-t', debs_path, 'weekly', 'IGNORE', |
749.1.14
by Curtis Hovey
Added tests for run_command. |
180 |
streams_path] |
749.1.6
by Curtis Hovey
Added an untested publish function. |
181 |
run_command(command, dry_run=dry_run, verbose=verbose) |
1003.3.4
by Curtis Hovey
Use publish to retry stream publication. |
182 |
publish(streams_path, publish_script, dry_run=dry_run, verbose=verbose) |
822.1.1
by John George
While publishing weekly streams, backup the buildvars.json files to S3, to maintain a record of the builds that have been published. |
183 |
# Sync buildvars.json files out to s3.
|
184 |
url = 's3://juju-qa-data/juju-releases/weekly/' |
|
185 |
s3_path = '{}/weekly/{}'.format(path, timestamp) |
|
186 |
if verbose: |
|
187 |
print('Calling s3cmd to sync %s out to %s' % (s3_path, url)) |
|
188 |
if not dry_run: |
|
189 |
s3_cmd(['sync', s3_path, url]) |
|
749.1.21
by Curtis Hovey
publish_candidates calls extract_candidates when the streams are created. |
190 |
extract_candidates(path, dry_run=dry_run, verbose=verbose) |
749.1.6
by Curtis Hovey
Added an untested publish function. |
191 |
|
192 |
||
1003.3.3
by Curtis Hovey
Added publish() to retry jobs. |
193 |
def publish(streams_path, publish_script, dry_run=False, verbose=False): |
1003.3.2
by Curtis Hovey
Incremental change for a function to test. |
194 |
juju_dist_path = os.path.join(streams_path, 'juju-dist') |
1003.3.6
by Curtis Hovey
Don't create command more than once. |
195 |
command = [publish_script, 'weekly', juju_dist_path, 'cpc'] |
1003.3.2
by Curtis Hovey
Incremental change for a function to test. |
196 |
for attempt in range(3): |
197 |
try: |
|
198 |
run_command(command, dry_run=dry_run, verbose=verbose) |
|
199 |
break
|
|
200 |
except subprocess.CalledProcessError: |
|
201 |
# Raise an error when the third attempt fails; the cloud is ill.
|
|
202 |
if attempt == 2: |
|
203 |
raise
|
|
204 |
||
205 |
||
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
206 |
def parse_args(args=None): |
207 |
"""Return the argument parser for this program."""
|
|
208 |
parser = ArgumentParser("Manage the successful Juju CI candidates.") |
|
209 |
parser.add_argument( |
|
210 |
'-d', '--dry-run', action='store_true', default=False, |
|
211 |
help='Do not make changes.') |
|
212 |
parser.add_argument( |
|
213 |
'-v', '--verbose', action='store_true', default=False, |
|
214 |
help='Increase verbosity.') |
|
749.1.2
by Curtis Hovey
Use subparsers to manage the args for the update and future publish and extract |
215 |
subparsers = parser.add_subparsers(help='sub-command help', dest="command") |
749.1.19
by Curtis Hovey
Rename update_candidate to download_candidate_files. |
216 |
# ./candidate download -b 1234 master ~/candidate
|
217 |
parser_update = subparsers.add_parser( |
|
849.1.1
by Aaron Bentley
Use credentials for candidate download. |
218 |
'download', help='download a candidate') |
749.1.2
by Curtis Hovey
Use subparsers to manage the args for the update and future publish and extract |
219 |
parser_update.add_argument( |
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
220 |
'-b', '--br-number', default='lastSuccessfulBuild', |
221 |
help="The specific build-revision number.") |
|
749.1.2
by Curtis Hovey
Use subparsers to manage the args for the update and future publish and extract |
222 |
parser_update.add_argument( |
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
223 |
'-p', '--pr-number', |
224 |
help="The specific publish-revision-revision number.") |
|
749.1.2
by Curtis Hovey
Use subparsers to manage the args for the update and future publish and extract |
225 |
parser_update.add_argument( |
1052.2.1
by seman.said at canonical
Updated to rename the candidate directories to version numbers rather than branches. |
226 |
'release_number', help='The successfully test branch release number.') |
749.1.2
by Curtis Hovey
Use subparsers to manage the args for the update and future publish and extract |
227 |
parser_update.add_argument( |
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
228 |
'path', help='The path to save the candiate data to.') |
849.1.1
by Aaron Bentley
Use credentials for candidate download. |
229 |
add_credential_args(parser_update) |
749.1.3
by Curtis Hovey
Added extract command to canidate module. |
230 |
# ./candidate extract master ~/candidate
|
749.1.6
by Curtis Hovey
Added an untested publish function. |
231 |
parser_extract = subparsers.add_parser( |
232 |
'extract', |
|
233 |
help='extract candidates that match the local series and arch.') |
|
749.1.3
by Curtis Hovey
Added extract command to canidate module. |
234 |
parser_extract.add_argument( |
749.1.5
by Curtis Hovey
Fixed help. |
235 |
'path', help='The path to the candiate data dir.') |
749.1.8
by Curtis Hovey
Added tests for prepare_dir. |
236 |
# ./candidate --juju-release-tools $JUJU_RELEASE_TOOLS \
|
237 |
# publish ~/candidate ~/streams
|
|
749.1.6
by Curtis Hovey
Added an untested publish function. |
238 |
parser_publish = subparsers.add_parser( |
239 |
'publish', help='Publish streams for the candidates') |
|
240 |
parser_publish.add_argument( |
|
241 |
'-t', '--juju-release-tools', |
|
242 |
help='The path to the juju-release-tools dir.') |
|
243 |
parser_publish.add_argument( |
|
244 |
'path', help='The path to the candiate data dir.') |
|
245 |
parser_publish.add_argument( |
|
246 |
'streams_path', help='The path to the streams data dir.') |
|
849.1.1
by Aaron Bentley
Use credentials for candidate download. |
247 |
parsed_args = parser.parse_args(args) |
248 |
return parsed_args, get_credentials(parsed_args) |
|
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
249 |
|
250 |
||
251 |
def main(argv): |
|
747.2.2
by Curtis Hovey
Fix doc. |
252 |
"""Manage successful Juju CI candiates."""
|
849.1.1
by Aaron Bentley
Use credentials for candidate download. |
253 |
args, credentials = parse_args(argv) |
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
254 |
try: |
749.1.19
by Curtis Hovey
Rename update_candidate to download_candidate_files. |
255 |
if args.command == 'download': |
256 |
download_candidate_files( |
|
1052.2.1
by seman.said at canonical
Updated to rename the candidate directories to version numbers rather than branches. |
257 |
credentials, args.release_number, args.path, args.br_number, |
849.1.1
by Aaron Bentley
Use credentials for candidate download. |
258 |
args.pr_number, dry_run=args.dry_run, verbose=args.verbose) |
749.1.3
by Curtis Hovey
Added extract command to canidate module. |
259 |
elif args.command == 'extract': |
260 |
extract_candidates( |
|
261 |
args.path, dry_run=args.dry_run, verbose=args.verbose) |
|
749.1.6
by Curtis Hovey
Added an untested publish function. |
262 |
elif args.command == 'publish': |
263 |
publish_candidates( |
|
264 |
args.path, args.streams_path, |
|
265 |
juju_release_tools=args.juju_release_tools, |
|
266 |
dry_run=args.dry_run, verbose=args.verbose) |
|
747.2.1
by Curtis Hovey
Added an untested, but usable script to collect the candidate artificats |
267 |
except Exception as e: |
268 |
print(e) |
|
269 |
if args.verbose: |
|
270 |
traceback.print_tb(sys.exc_info()[2]) |
|
271 |
return 2 |
|
272 |
if args.verbose: |
|
273 |
print("Done.") |
|
274 |
return 0 |
|
275 |
||
276 |
||
277 |
if __name__ == '__main__': |
|
278 |
sys.exit(main(sys.argv[1:])) |