Merge lp:~frankban/charms/oneiric/buildbot-master/upgrade-charm into lp:~yellow/charms/oneiric/buildbot-master/trunk

Proposed by Francesco Banconi
Status: Merged
Approved by: Graham Binns
Approved revision: 44
Merged at revision: 38
Proposed branch: lp:~frankban/charms/oneiric/buildbot-master/upgrade-charm
Merge into: lp:~yellow/charms/oneiric/buildbot-master/trunk
Diff against target: 252 lines (+78/-23)
6 files modified
hooks/buildbot-relation-broken (+1/-1)
hooks/config-changed (+1/-1)
hooks/helpers.py (+42/-10)
hooks/install (+3/-1)
revision (+0/-1)
tests/buildbot-master.test (+31/-9)
To merge this branch: bzr merge lp:~frankban/charms/oneiric/buildbot-master/upgrade-charm
Reviewer Review Type Date Requested Status
Graham Binns (community) code Approve
Review via email: mp+95535@code.launchpad.net

Description of the change

== Changes ==

- Added upgrade-charm symlink
- Updated helpers (with some refactoring to functions running "juju status")
- Updated install hook: now it runs config-changed during charm upgrade
- Some changes in functional tests

The file helper.py is in sync with the one present in
lp:~frankban/charms/oneiric/buildbot-slave/upgrade-charm

Currently the upgrade-charm test does not work due to a bug of juju:
see https://bugs.launchpad.net/juju/+bug/941873

To post a comment you must log in.
Revision history for this message
Graham Binns (gmb) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'hooks/buildbot-relation-broken'
2--- hooks/buildbot-relation-broken 2012-02-13 15:59:35 +0000
3+++ hooks/buildbot-relation-broken 2012-03-02 11:26:19 +0000
4@@ -3,12 +3,12 @@
5 # Copyright 2012 Canonical Ltd. This software is licensed under the
6 # GNU Affero General Public License version 3 (see the file LICENSE).
7
8+from shelltoolbox import su
9 from helpers import (
10 log,
11 log_entry,
12 log_exit,
13 run,
14- su,
15 )
16 from local import (
17 buildbot_reconfig,
18
19=== modified file 'hooks/config-changed'
20--- hooks/config-changed 2012-02-29 22:43:30 +0000
21+++ hooks/config-changed 2012-03-02 11:26:19 +0000
22@@ -78,7 +78,7 @@
23 install_extra_repositories(extra_repo)
24 except subprocess.CalledProcessError as e:
25 log('Error adding repository: ' + extra_repo)
26- log(e)
27+ log(str(e))
28 raise
29 restart_required = True
30 if extra_pkgs and 'extra-packages' in added_or_changed:
31
32=== modified file 'hooks/helpers.py'
33--- hooks/helpers.py 2012-02-29 22:43:30 +0000
34+++ hooks/helpers.py 2012-03-02 11:26:19 +0000
35@@ -6,15 +6,21 @@
36 __metaclass__ = type
37 __all__ = [
38 'get_config',
39+ 'juju_status',
40 'log',
41 'log_entry',
42 'log_exit',
43+ 'make_charm_config_file',
44 'relation_get',
45 'relation_set',
46 'unit_info',
47+ 'wait_for_machine',
48+ 'wait_for_page_contents',
49+ 'wait_for_relation',
50+ 'wait_for_unit',
51 ]
52
53-from collections import namedtuple
54+from contextlib import contextmanager
55 import json
56 import operator
57 from shelltoolbox import (
58@@ -22,14 +28,13 @@
59 run,
60 script_name,
61 )
62+import os
63 import tempfile
64 import time
65 import urllib2
66 import yaml
67
68
69-Env = namedtuple('Env', 'uid gid home')
70-
71 log = command('juju-log')
72
73
74@@ -67,10 +72,18 @@
75 return charm_config_file
76
77
78+def juju_status(key):
79+ return yaml.safe_load(run('juju', 'status'))[key]
80+
81+
82+def get_charm_revision(service_name):
83+ service = juju_status('services')[service_name]
84+ return int(service['charm'].split('-')[-1])
85+
86+
87 def unit_info(service_name, item_name, data=None):
88- if data is None:
89- data = yaml.safe_load(run('juju', 'status'))
90- service = data['services'].get(service_name)
91+ services = juju_status('services') if data is None else data['services']
92+ service = services.get(service_name)
93 if service is None:
94 # XXX 2012-02-08 gmb:
95 # This allows us to cope with the race condition that we
96@@ -83,8 +96,27 @@
97 return item
98
99
100-def get_machine_data():
101- return yaml.safe_load(run('juju', 'status'))['machines']
102+@contextmanager
103+def maintain_charm_revision(path=None):
104+ if path is None:
105+ path = os.path.join(os.path.dirname(__file__), '..', 'revision')
106+ revision = open(path).read()
107+ try:
108+ yield revision
109+ finally:
110+ with open(path, 'w') as f:
111+ f.write(revision)
112+
113+
114+def upgrade_charm(service_name, timeout=120):
115+ next_revision = get_charm_revision(service_name) + 1
116+ start_time = time.time()
117+ run('juju', 'upgrade-charm', service_name)
118+ while get_charm_revision(service_name) != next_revision:
119+ if time.time() - start_time >= timeout:
120+ raise RuntimeError('timeout waiting for charm to be upgraded')
121+ time.sleep(0.1)
122+ return next_revision
123
124
125 def wait_for_machine(num_machines=1, timeout=300):
126@@ -98,7 +130,7 @@
127 # to tell what environment we're working in (LXC vs EC2) is to check
128 # the dns-name of the first machine. If it's localhost we're in LXC
129 # and we can just return here.
130- if get_machine_data()[0]['dns-name'] == 'localhost':
131+ if juju_status('machines')[0]['dns-name'] == 'localhost':
132 return
133 start_time = time.time()
134 while True:
135@@ -106,7 +138,7 @@
136 # not a machine that we need to wait for. This will only work
137 # for EC2 environments, which is why we return early above if
138 # we're in LXC.
139- machine_data = get_machine_data()
140+ machine_data = juju_status('machines')
141 non_zookeeper_machines = [
142 machine_data[key] for key in machine_data.keys()[1:]]
143 if len(non_zookeeper_machines) >= num_machines:
144
145=== modified file 'hooks/install'
146--- hooks/install 2012-03-01 14:06:36 +0000
147+++ hooks/install 2012-03-02 11:26:19 +0000
148@@ -110,10 +110,12 @@
149 old_config = config_json.get()
150 buildbot_dir = old_config.get('installdir', config['installdir'])
151 cleanup(buildbot_dir)
152+ if os.path.basename(__file__) == 'upgrade-charm':
153+ log('Running config-changed from upgrade-charm hook.')
154+ run('hooks/config-changed')
155
156
157 if __name__ == '__main__':
158-
159 log_entry()
160 try:
161 main()
162
163=== added symlink 'hooks/upgrade-charm'
164=== target is u'install'
165=== modified file 'revision'
166--- revision 2012-02-29 09:57:12 +0000
167+++ revision 2012-03-02 11:26:19 +0000
168@@ -1,2 +1,1 @@
169 1
170-
171
172=== modified file 'tests/buildbot-master.test'
173--- tests/buildbot-master.test 2012-02-13 10:59:34 +0000
174+++ tests/buildbot-master.test 2012-03-02 11:26:19 +0000
175@@ -5,11 +5,14 @@
176 from helpers import (
177 command,
178 make_charm_config_file,
179+ maintain_charm_revision,
180 unit_info,
181+ upgrade_charm,
182 wait_for_page_contents,
183 wait_for_unit,
184 )
185 import os.path
186+import time
187 import unittest
188
189 juju = command('juju')
190@@ -27,27 +30,35 @@
191 additional_args.append('--config=' + charm_config_file.name)
192 juju('deploy', 'buildbot-master', *additional_args)
193 wait_for_unit('buildbot-master')
194+
195+ def expose_and_check_page(self):
196 juju('expose', 'buildbot-master')
197 addr = unit_info('buildbot-master', 'public-address')
198 url = 'http://{}:8010'.format(addr)
199 wait_for_page_contents(url, 'Welcome to the Buildbot')
200
201+ def get_config_file_contents(self):
202+ bb_config_path = os.path.join(os.path.dirname(__file__), 'test.cfg')
203+ return open(bb_config_path).read()
204+
205+ def get_config(self):
206+ return {
207+ 'buildbot-master': {
208+ 'extra-packages': 'git',
209+ 'installdir': '/tmp/buildbot',
210+ 'config-file': self.get_config_file_contents(),
211+ }}
212+
213 def test_port_opened(self):
214 # Deploying a buildbot master should result in it opening a port and
215 # serving its status via HTTP.
216- bb_config_path = os.path.join(os.path.dirname(__file__), 'test.cfg')
217- charm_config = {
218- 'buildbot-master': {
219- 'extra-packages': 'git',
220- 'installdir': '/tmp/buildbot',
221- 'config-file': open(bb_config_path).read(),
222- }}
223- self.deploy(charm_config)
224+ self.deploy(self.get_config())
225+ self.expose_and_check_page()
226
227 def test_lpbuildbot(self):
228 # Deploying a Launchpad-specific buildbot master does a good job of
229 # exercising the configuration parameters. For example, the
230- # configuration in this test adds a repositroy (lucid main universe),
231+ # configuration in this test adds a repository (lucid main universe),
232 # installs a non-default buildbot package, and fetches the buildbot
233 # configuration from bzr.
234 charm_config = {
235@@ -62,6 +73,17 @@
236 'installdir': '/var/lib/buildbot/masters/lpbuildbot',
237 }}
238 self.deploy(charm_config)
239+ self.expose_and_check_page()
240+
241+ def test_upgrade_charm(self):
242+ # Ensure the charm can be upgraded without errors.
243+ self.deploy(self.get_config())
244+ with maintain_charm_revision():
245+ upgrade_charm('buildbot-master')
246+ # Wait for the charm to upgrade using sleep, since there is no
247+ # other confirmation at the moment but the state to remain 'started'.
248+ time.sleep(10)
249+ self.expose_and_check_page()
250
251
252 if __name__ == '__main__':

Subscribers

People subscribed via source and target branches