Merge lp:~sinzui/juju-ci-tools/build-from-s3 into lp:juju-ci-tools

Proposed by Curtis Hovey
Status: Merged
Merged at revision: 1908
Proposed branch: lp:~sinzui/juju-ci-tools/build-from-s3
Merge into: lp:juju-ci-tools
Diff against target: 260 lines (+113/-56)
2 files modified
build_juju.py (+30/-16)
tests/test_build_juju.py (+83/-40)
To merge this branch: bzr merge lp:~sinzui/juju-ci-tools/build-from-s3
Reviewer Review Type Date Requested Status
Juju Release Engineering Pending
Review via email: mp+312835@code.launchpad.net

Description of the change

Build juju agents from s3 artifacts.

Many of the canonical machines do not have access to the jenkins jobs to pickup assets to build. They do have access to s3. This branch switched build_juju.py to use s3ci.py instead of jujuci.py. These changes have been used in anger to build juju agents for s390x, ppc64el, arm64, and amd64.
    build-ubuntu-s390x-agent
    build-ubuntu-ppc64el-agent
    build-ubuntu-arm64-agent
    build-ubuntu-amd64-agent

build_juju.py now needs to know the s3 config to get the build-revision's juju tarfile. It also needs to know the architecture to pass to the crossbuild.py script. Only the "ubuntu-agent" subcommand takes the arch option, so we only append --goarch when needed.

This cannot merge without me also updating these jobs to pass in the s3 config.
    build-centos
    build-osx-client
    build-win-agent
    build-win-client

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'build_juju.py'
2--- build_juju.py 2016-12-01 15:34:05 +0000
3+++ build_juju.py 2016-12-08 15:43:29 +0000
4@@ -9,14 +9,13 @@
5 import traceback
6
7 from candidate import run_command
8+from jujuconfig import get_juju_home
9 from jujuci import (
10 add_artifacts,
11- add_credential_args,
12- get_artifacts,
13- get_credentials,
14 BUILD_REVISION,
15 setup_workspace,
16 )
17+import s3ci
18
19
20 DEFAULT_JUJU_RELEASE_TOOLS = os.path.realpath(
21@@ -42,8 +41,17 @@
22 return script
23
24
25+def get_juju_tarfile(s3cfg_path, build, workspace_dir):
26+ bucket = s3ci.get_qa_data_bucket(s3cfg_path)
27+ files = s3ci.fetch_files(
28+ bucket, build, BUILD_REVISION, 'juju-core_.*.tar.gz',
29+ workspace_dir)
30+ return files[0]
31+
32+
33 def build_juju(credentials, product, workspace_dir, build,
34- juju_release_tools=None, dry_run=False, verbose=False):
35+ juju_release_tools=None, goarch=None,
36+ dry_run=False, verbose=False):
37 """Build the juju product from a Juju CI build-revision in a workspace.
38
39 The product is passed to juju-release-tools/crossbuild.py. The options
40@@ -53,13 +61,12 @@
41 to crossbuild.py.
42 """
43 setup_workspace(workspace_dir, dry_run=dry_run, verbose=verbose)
44- artifacts = get_artifacts(
45- credentials, BUILD_REVISION, build, 'juju-core_*.tar.gz',
46- workspace_dir, archive=False, dry_run=dry_run, verbose=verbose)
47- tar_artifact = artifacts[0]
48+ tarfile = get_juju_tarfile(credentials, build, workspace_dir)
49 crossbuild = get_crossbuild_script(juju_release_tools)
50- command = [
51- crossbuild, product, '-b', '~/crossbuild', tar_artifact.file_name]
52+ command = [crossbuild, product, '-b', '~/crossbuild']
53+ if product == 'ubuntu-agent' and goarch:
54+ command.extend(['--goarch', goarch])
55+ command.append(tarfile)
56 run_command(command, dry_run=dry_run, verbose=verbose)
57 add_artifacts(workspace_dir, ARTIFACT_GLOBS, dry_run=dry_run,
58 verbose=verbose)
59@@ -68,6 +75,7 @@
60 def parse_args(args=None):
61 """Return the argument parser for this program."""
62 parser = ArgumentParser("Build and package juju for an non-debian OS.")
63+ default_config = os.path.join(get_juju_home(), 'juju-qa.s3cfg')
64 parser.add_argument(
65 '-d', '--dry-run', action='store_true', default=False,
66 help='Do not make changes.')
67@@ -82,23 +90,29 @@
68 help='The path to the juju-release-tools dir, default: %s' %
69 DEFAULT_JUJU_RELEASE_TOOLS)
70 parser.add_argument(
71+ '-c', '--config', default=default_config,
72+ help=('s3cmd config file for credentials. Default to '
73+ 'juju-qa.s3cfg in juju home.'))
74+ parser.add_argument(
75+ '-a', '--goarch', default=os.environ.get('GOARCH', None),
76+ help=('The GOARCH. Defaults to GOARCH in the env.'))
77+ parser.add_argument(
78 'product', choices=['win-client', 'win-agent', 'osx-client', 'centos',
79 'ubuntu-agent'],
80 help='the kind of juju to make and package.')
81 parser.add_argument(
82- 'workspace', help='The path to the workspace to build in.')
83- add_credential_args(parser)
84+ 'workspace', help='The path to the workspace to build in.')
85 parsed = parser.parse_args(args)
86- return parsed, get_credentials(parsed)
87+ return parsed
88
89
90 def main(argv):
91 """Build and package juju for an non-debian OS."""
92- args, credentials = parse_args(argv)
93+ args = parse_args(argv)
94 try:
95 build_juju(
96- credentials, args.product, args.workspace, args.build,
97- juju_release_tools=args.juju_release_tools,
98+ args.config, args.product, args.workspace, args.build,
99+ juju_release_tools=args.juju_release_tools, goarch=args.goarch,
100 dry_run=args.dry_run, verbose=args.verbose)
101 except Exception as e:
102 print(e)
103
104=== modified file 'tests/test_build_juju.py'
105--- tests/test_build_juju.py 2016-12-01 15:34:05 +0000
106+++ tests/test_build_juju.py 2016-12-08 15:43:29 +0000
107@@ -1,15 +1,15 @@
108-from mock import patch
109+from mock import (
110+ Mock,
111+ patch,
112+ )
113 import os
114 from unittest import TestCase
115
116-from jujuci import (
117- Artifact,
118- Credentials,
119- )
120 from build_juju import (
121 ARTIFACT_GLOBS,
122 build_juju,
123 get_crossbuild_script,
124+ get_juju_tarfile,
125 main,
126 )
127 from utility import temp_dir
128@@ -19,50 +19,80 @@
129
130 def test_main_options(self):
131 with patch('build_juju.build_juju', autospec=True) as mock:
132- main(['-d', '-v', '-b', '1234', 'win-client', './foo',
133- '--user', 'jrandom', '--password', 'password1'])
134- args, kwargs = mock.call_args
135- self.assertEqual(
136- (Credentials('jrandom', 'password1'), 'win-client', './foo',
137- '1234'), args)
138- self.assertTrue(kwargs['dry_run'])
139- self.assertTrue(kwargs['verbose'])
140+ main(['-d', '-v', '-b', '1234', 'win-client', './foo'])
141+ s3cfg = os.path.join(os.environ.get('JUJU_HOME'), 'juju-qa.s3cfg')
142+ mock.assert_called_once_with(
143+ s3cfg, 'win-client', './foo', '1234', goarch=None,
144+ dry_run=True, juju_release_tools=None, verbose=True)
145+
146+ def test_main_options_with_arch(self):
147+ with patch('build_juju.build_juju', autospec=True) as mock:
148+ main(['-d', '-v', '-b', '1234', '-a', 's390x',
149+ 'ubuntu-agent', './foo'])
150+ s3cfg = os.path.join(os.environ.get('JUJU_HOME'), 'juju-qa.s3cfg')
151+ mock.assert_called_once_with(
152+ s3cfg, 'ubuntu-agent', './foo', '1234', goarch='s390x',
153+ dry_run=True, juju_release_tools=None, verbose=True)
154
155 def test_build_juju(self):
156- credentials = Credentials('jrandom', 'password1')
157 with temp_dir() as base_dir:
158 work_dir = os.path.join(base_dir, 'workspace')
159 with patch('build_juju.setup_workspace', autospec=True) as sw_mock:
160- artifacts = [
161- Artifact('juju-core_1.2.3.tar.gz', 'http:...')]
162- with patch('build_juju.get_artifacts',
163- return_value=artifacts, autospec=True) as ga_mock:
164+ with patch('build_juju.get_juju_tarfile',
165+ return_value='juju-core_1.2.3.tar.gz',
166+ autospec=True) as gt_mock:
167 with patch('build_juju.run_command') as rc_mock:
168 with patch('build_juju.add_artifacts', autospec=True
169 ) as aa_mock:
170 build_juju(
171- credentials, 'win-client', work_dir,
172- 'lastSucessful', dry_run=True, verbose=True)
173- self.assertEqual((work_dir, ), sw_mock.call_args[0])
174- self.assertEqual(
175- {'dry_run': True, 'verbose': True}, sw_mock.call_args[1])
176- self.assertEqual(
177- (credentials, 'build-revision', 'lastSucessful',
178- 'juju-core_*.tar.gz', work_dir,),
179- ga_mock.call_args[0])
180- self.assertEqual(
181- {'archive': False, 'dry_run': True, 'verbose': True},
182- ga_mock.call_args[1])
183- crossbuild = get_crossbuild_script()
184- self.assertEqual(
185- ([crossbuild, 'win-client', '-b', '~/crossbuild',
186- 'juju-core_1.2.3.tar.gz'], ),
187- rc_mock.call_args[0])
188- self.assertEqual(
189- {'dry_run': True, 'verbose': True}, rc_mock.call_args[1])
190- self.assertEqual((work_dir, ARTIFACT_GLOBS), aa_mock.call_args[0])
191- self.assertEqual(
192- {'dry_run': True, 'verbose': True}, aa_mock.call_args[1])
193+ 's3cfg', 'win-client', work_dir, '1234',
194+ dry_run=True, verbose=True)
195+ sw_mock.assert_called_once_with(
196+ work_dir, dry_run=True, verbose=True)
197+ gt_mock.assert_called_once_with('s3cfg', '1234', work_dir)
198+ crossbuild = get_crossbuild_script()
199+ rc_mock.assert_called_once_with(
200+ [crossbuild, 'win-client', '-b', '~/crossbuild',
201+ 'juju-core_1.2.3.tar.gz'], dry_run=True, verbose=True)
202+ aa_mock.assert_called_once_with(
203+ work_dir, ARTIFACT_GLOBS, dry_run=True, verbose=True)
204+
205+ def test_build_juju_with_goarch_ubuntu_agent(self):
206+ with temp_dir() as base_dir:
207+ work_dir = os.path.join(base_dir, 'workspace')
208+ with patch('build_juju.setup_workspace', autospec=True):
209+ with patch('build_juju.get_juju_tarfile',
210+ return_value='juju-core_1.2.3.tar.gz',
211+ autospec=True):
212+ with patch('build_juju.run_command') as rc_mock:
213+ with patch('build_juju.add_artifacts', autospec=True):
214+ build_juju(
215+ 's3cfg', 'ubuntu-agent', work_dir, '1234',
216+ goarch='s390x', dry_run=True, verbose=True)
217+ crossbuild = get_crossbuild_script()
218+ rc_mock.assert_called_once_with(
219+ [crossbuild, 'ubuntu-agent', '-b', '~/crossbuild',
220+ '--goarch', 's390x', 'juju-core_1.2.3.tar.gz'],
221+ dry_run=True, verbose=True)
222+
223+ def test_build_juju_with_goarch_non_ubuntu_agent(self):
224+ # GOARCH is never set when the product is not ubuntu-agent
225+ with temp_dir() as base_dir:
226+ work_dir = os.path.join(base_dir, 'workspace')
227+ with patch('build_juju.setup_workspace', autospec=True):
228+ with patch('build_juju.get_juju_tarfile',
229+ return_value='juju-core_1.2.3.tar.gz',
230+ autospec=True):
231+ with patch('build_juju.run_command') as rc_mock:
232+ with patch('build_juju.add_artifacts', autospec=True):
233+ build_juju(
234+ 's3cfg', 'win-client', work_dir, '1234',
235+ goarch='s390x', dry_run=True, verbose=True)
236+ crossbuild = get_crossbuild_script()
237+ rc_mock.assert_called_once_with(
238+ [crossbuild, 'win-client', '-b', '~/crossbuild',
239+ 'juju-core_1.2.3.tar.gz'],
240+ dry_run=True, verbose=True)
241
242 def test_get_crossbuild_script(self):
243 self.assertEqual(
244@@ -73,3 +103,16 @@
245 self.assertEqual(
246 os.path.join(parent_dir, 'juju-release-tools', 'crossbuild.py'),
247 get_crossbuild_script())
248+
249+ def test_get_juju_tarfile(self):
250+ s3cfg_path = './cloud-city/juju-qa.s3cfg'
251+ bucket = Mock()
252+ with patch('build_juju.s3ci.get_qa_data_bucket',
253+ return_value=bucket, autospec=True) as gb_mock:
254+ with patch('build_juju.s3ci.fetch_files', autospec=True,
255+ return_value=['./juju-core_1.2.3.tar.gz']) as ff_mock:
256+ tarfile = get_juju_tarfile(s3cfg_path, '1234', './')
257+ self.assertEqual('./juju-core_1.2.3.tar.gz', tarfile)
258+ gb_mock.assert_called_once_with('./cloud-city/juju-qa.s3cfg')
259+ ff_mock.assert_called_once_with(
260+ bucket, '1234', 'build-revision', 'juju-core_.*.tar.gz', './')

Subscribers

People subscribed via source and target branches