Merge lp:~lazypower/charms/trusty/mongodb/fixing_st00f into lp:charms/mongodb
- Trusty Tahr (14.04)
- fixing_st00f
- Merge into trunk
Proposed by
Charles Butler
Status: | Rejected |
---|---|
Rejected by: | Charles Butler |
Proposed branch: | lp:~lazypower/charms/trusty/mongodb/fixing_st00f |
Merge into: | lp:charms/mongodb |
Diff against target: |
1403 lines (+597/-274) 11 files modified
.bzrignore (+3/-0) Makefile (+9/-1) hooks/charmhelpers/core/fstab.py (+116/-0) hooks/charmhelpers/core/hookenv.py (+103/-5) hooks/charmhelpers/core/host.py (+38/-8) hooks/charmhelpers/fetch/__init__.py (+130/-81) hooks/charmhelpers/fetch/bzrurl.py (+2/-1) hooks/hooks.py (+148/-171) hooks/install (+0/-5) metadata.yaml (+5/-2) tests/200_relate_ceilometer.test (+43/-0) |
To merge this branch: | bzr merge lp:~lazypower/charms/trusty/mongodb/fixing_st00f |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Charles Butler (community) | Needs Fixing | ||
Benjamin Saller (community) | Needs Fixing | ||
Review via email: mp+228714@code.launchpad.net |
Commit message
Description of the change
Proposed resolution for MongoDB - refactors to use charmhelpers, adds a basic relation test to validate ceilometer client integration isn't broken, and various fixes relating to clustering.
This is a rework of patch 49 that was reverted.
To post a comment you must log in.
- 54. By Charles Butler
-
Backports Storage Subordinate work into the charmhelpers revision
- 55. By Charles Butler
-
Fixes typo in raise statement of test
- 56. By Charles Butler
-
Dirty merge cleanup
Revision history for this message
Charles Butler (lazypower) wrote : | # |
And just noticed this "dirty merge cleanup" leaves a ton of stuff around. WIll revert, and re-try, again.
review:
Needs Fixing
Revision history for this message
Charles Butler (lazypower) wrote : | # |
Rejecting - this was an olllld merge that was bubbling up in the queue - and has been merged from a different, cleaner branch.
Revision history for this message
Marco Ceppi (marcoceppi) wrote : | # |
Thanks for removing from the queue.
Unmerged revisions
- 56. By Charles Butler
-
Dirty merge cleanup
- 55. By Charles Butler
-
Fixes typo in raise statement of test
- 54. By Charles Butler
-
Backports Storage Subordinate work into the charmhelpers revision
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file '.bzrignore' |
2 | --- .bzrignore 1970-01-01 00:00:00 +0000 |
3 | +++ .bzrignore 2014-07-29 16:34:12 +0000 |
4 | @@ -0,0 +1,3 @@ |
5 | +.git |
6 | +bin/* |
7 | +scripts/charm-helpers-sync.py |
8 | |
9 | === modified file 'Makefile' |
10 | --- Makefile 2014-04-11 20:55:42 +0000 |
11 | +++ Makefile 2014-07-29 16:34:12 +0000 |
12 | @@ -13,9 +13,17 @@ |
13 | # You should have received a copy of the GNU Affero General Public License |
14 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
15 | |
16 | +PYTHON := /usr/bin/env python |
17 | |
18 | unittest: |
19 | tests/10-unit.test |
20 | |
21 | sync: |
22 | - @charm-helper-sync -c charm-helpers-sync.yaml |
23 | + @mkdir -p bin |
24 | + @bzr cat lp:charm-helpers/tools/charm_helpers_sync/charm_helpers_sync.py > bin/charm_helpers_sync.py |
25 | + @$(PYTHON) bin/charm_helpers_sync.py -c charm-helpers-sync.yaml |
26 | + |
27 | +clean: |
28 | + @find . -name \*.pyc -delete |
29 | + @find . -name '*.bak' -delete |
30 | + |
31 | |
32 | === added file '__init__.py' |
33 | === added directory 'bin' |
34 | === added file 'hooks/charmhelpers/core/fstab.py' |
35 | --- hooks/charmhelpers/core/fstab.py 1970-01-01 00:00:00 +0000 |
36 | +++ hooks/charmhelpers/core/fstab.py 2014-07-29 16:34:12 +0000 |
37 | @@ -0,0 +1,116 @@ |
38 | +#!/usr/bin/env python |
39 | +# -*- coding: utf-8 -*- |
40 | + |
41 | +__author__ = 'Jorge Niedbalski R. <jorge.niedbalski@canonical.com>' |
42 | + |
43 | +import os |
44 | + |
45 | + |
46 | +class Fstab(file): |
47 | + """This class extends file in order to implement a file reader/writer |
48 | + for file `/etc/fstab` |
49 | + """ |
50 | + |
51 | + class Entry(object): |
52 | + """Entry class represents a non-comment line on the `/etc/fstab` file |
53 | + """ |
54 | + def __init__(self, device, mountpoint, filesystem, |
55 | + options, d=0, p=0): |
56 | + self.device = device |
57 | + self.mountpoint = mountpoint |
58 | + self.filesystem = filesystem |
59 | + |
60 | + if not options: |
61 | + options = "defaults" |
62 | + |
63 | + self.options = options |
64 | + self.d = d |
65 | + self.p = p |
66 | + |
67 | + def __eq__(self, o): |
68 | + return str(self) == str(o) |
69 | + |
70 | + def __str__(self): |
71 | + return "{} {} {} {} {} {}".format(self.device, |
72 | + self.mountpoint, |
73 | + self.filesystem, |
74 | + self.options, |
75 | + self.d, |
76 | + self.p) |
77 | + |
78 | + DEFAULT_PATH = os.path.join(os.path.sep, 'etc', 'fstab') |
79 | + |
80 | + def __init__(self, path=None): |
81 | + if path: |
82 | + self._path = path |
83 | + else: |
84 | + self._path = self.DEFAULT_PATH |
85 | + file.__init__(self, self._path, 'r+') |
86 | + |
87 | + def _hydrate_entry(self, line): |
88 | + # NOTE: use split with no arguments to split on any |
89 | + # whitespace including tabs |
90 | + return Fstab.Entry(*filter( |
91 | + lambda x: x not in ('', None), |
92 | + line.strip("\n").split())) |
93 | + |
94 | + @property |
95 | + def entries(self): |
96 | + self.seek(0) |
97 | + for line in self.readlines(): |
98 | + try: |
99 | + if not line.startswith("#"): |
100 | + yield self._hydrate_entry(line) |
101 | + except ValueError: |
102 | + pass |
103 | + |
104 | + def get_entry_by_attr(self, attr, value): |
105 | + for entry in self.entries: |
106 | + e_attr = getattr(entry, attr) |
107 | + if e_attr == value: |
108 | + return entry |
109 | + return None |
110 | + |
111 | + def add_entry(self, entry): |
112 | + if self.get_entry_by_attr('device', entry.device): |
113 | + return False |
114 | + |
115 | + self.write(str(entry) + '\n') |
116 | + self.truncate() |
117 | + return entry |
118 | + |
119 | + def remove_entry(self, entry): |
120 | + self.seek(0) |
121 | + |
122 | + lines = self.readlines() |
123 | + |
124 | + found = False |
125 | + for index, line in enumerate(lines): |
126 | + if not line.startswith("#"): |
127 | + if self._hydrate_entry(line) == entry: |
128 | + found = True |
129 | + break |
130 | + |
131 | + if not found: |
132 | + return False |
133 | + |
134 | + lines.remove(line) |
135 | + |
136 | + self.seek(0) |
137 | + self.write(''.join(lines)) |
138 | + self.truncate() |
139 | + return True |
140 | + |
141 | + @classmethod |
142 | + def remove_by_mountpoint(cls, mountpoint, path=None): |
143 | + fstab = cls(path=path) |
144 | + entry = fstab.get_entry_by_attr('mountpoint', mountpoint) |
145 | + if entry: |
146 | + return fstab.remove_entry(entry) |
147 | + return False |
148 | + |
149 | + @classmethod |
150 | + def add(cls, device, mountpoint, filesystem, options=None, path=None): |
151 | + return cls(path=path).add_entry(Fstab.Entry(device, |
152 | + mountpoint, filesystem, |
153 | + options=options)) |
154 | |
155 | === modified file 'hooks/charmhelpers/core/hookenv.py' |
156 | --- hooks/charmhelpers/core/hookenv.py 2014-04-11 20:55:42 +0000 |
157 | +++ hooks/charmhelpers/core/hookenv.py 2014-07-29 16:34:12 +0000 |
158 | @@ -25,7 +25,7 @@ |
159 | def cached(func): |
160 | """Cache return values for multiple executions of func + args |
161 | |
162 | - For example: |
163 | + For example:: |
164 | |
165 | @cached |
166 | def unit_get(attribute): |
167 | @@ -155,6 +155,100 @@ |
168 | return os.path.basename(sys.argv[0]) |
169 | |
170 | |
171 | +class Config(dict): |
172 | + """A Juju charm config dictionary that can write itself to |
173 | + disk (as json) and track which values have changed since |
174 | + the previous hook invocation. |
175 | + |
176 | + Do not instantiate this object directly - instead call |
177 | + ``hookenv.config()`` |
178 | + |
179 | + Example usage:: |
180 | + |
181 | + >>> # inside a hook |
182 | + >>> from charmhelpers.core import hookenv |
183 | + >>> config = hookenv.config() |
184 | + >>> config['foo'] |
185 | + 'bar' |
186 | + >>> config['mykey'] = 'myval' |
187 | + >>> config.save() |
188 | + |
189 | + |
190 | + >>> # user runs `juju set mycharm foo=baz` |
191 | + >>> # now we're inside subsequent config-changed hook |
192 | + >>> config = hookenv.config() |
193 | + >>> config['foo'] |
194 | + 'baz' |
195 | + >>> # test to see if this val has changed since last hook |
196 | + >>> config.changed('foo') |
197 | + True |
198 | + >>> # what was the previous value? |
199 | + >>> config.previous('foo') |
200 | + 'bar' |
201 | + >>> # keys/values that we add are preserved across hooks |
202 | + >>> config['mykey'] |
203 | + 'myval' |
204 | + >>> # don't forget to save at the end of hook! |
205 | + >>> config.save() |
206 | + |
207 | + """ |
208 | + CONFIG_FILE_NAME = '.juju-persistent-config' |
209 | + |
210 | + def __init__(self, *args, **kw): |
211 | + super(Config, self).__init__(*args, **kw) |
212 | + self._prev_dict = None |
213 | + self.path = os.path.join(charm_dir(), Config.CONFIG_FILE_NAME) |
214 | + if os.path.exists(self.path): |
215 | + self.load_previous() |
216 | + |
217 | + def load_previous(self, path=None): |
218 | + """Load previous copy of config from disk so that current values |
219 | + can be compared to previous values. |
220 | + |
221 | + :param path: |
222 | + |
223 | + File path from which to load the previous config. If `None`, |
224 | + config is loaded from the default location. If `path` is |
225 | + specified, subsequent `save()` calls will write to the same |
226 | + path. |
227 | + |
228 | + """ |
229 | + self.path = path or self.path |
230 | + with open(self.path) as f: |
231 | + self._prev_dict = json.load(f) |
232 | + |
233 | + def changed(self, key): |
234 | + """Return true if the value for this key has changed since |
235 | + the last save. |
236 | + |
237 | + """ |
238 | + if self._prev_dict is None: |
239 | + return True |
240 | + return self.previous(key) != self.get(key) |
241 | + |
242 | + def previous(self, key): |
243 | + """Return previous value for this key, or None if there |
244 | + is no "previous" value. |
245 | + |
246 | + """ |
247 | + if self._prev_dict: |
248 | + return self._prev_dict.get(key) |
249 | + return None |
250 | + |
251 | + def save(self): |
252 | + """Save this config to disk. |
253 | + |
254 | + Preserves items in _prev_dict that do not exist in self. |
255 | + |
256 | + """ |
257 | + if self._prev_dict: |
258 | + for k, v in self._prev_dict.iteritems(): |
259 | + if k not in self: |
260 | + self[k] = v |
261 | + with open(self.path, 'w') as f: |
262 | + json.dump(self, f) |
263 | + |
264 | + |
265 | @cached |
266 | def config(scope=None): |
267 | """Juju charm configuration""" |
268 | @@ -163,7 +257,10 @@ |
269 | config_cmd_line.append(scope) |
270 | config_cmd_line.append('--format=json') |
271 | try: |
272 | - return json.loads(subprocess.check_output(config_cmd_line)) |
273 | + config_data = json.loads(subprocess.check_output(config_cmd_line)) |
274 | + if scope is not None: |
275 | + return config_data |
276 | + return Config(config_data) |
277 | except ValueError: |
278 | return None |
279 | |
280 | @@ -348,18 +445,19 @@ |
281 | class Hooks(object): |
282 | """A convenient handler for hook functions. |
283 | |
284 | - Example: |
285 | + Example:: |
286 | + |
287 | hooks = Hooks() |
288 | |
289 | # register a hook, taking its name from the function name |
290 | @hooks.hook() |
291 | def install(): |
292 | - ... |
293 | + pass # your code here |
294 | |
295 | # register a hook, providing a custom hook name |
296 | @hooks.hook("config-changed") |
297 | def config_changed(): |
298 | - ... |
299 | + pass # your code here |
300 | |
301 | if __name__ == "__main__": |
302 | # execute a hook based on the name the program is called by |
303 | |
304 | === modified file 'hooks/charmhelpers/core/host.py' |
305 | --- hooks/charmhelpers/core/host.py 2014-04-11 20:55:42 +0000 |
306 | +++ hooks/charmhelpers/core/host.py 2014-07-29 16:34:12 +0000 |
307 | @@ -16,6 +16,7 @@ |
308 | from collections import OrderedDict |
309 | |
310 | from hookenv import log |
311 | +from fstab import Fstab |
312 | |
313 | |
314 | def service_start(service_name): |
315 | @@ -34,7 +35,8 @@ |
316 | |
317 | |
318 | def service_reload(service_name, restart_on_failure=False): |
319 | - """Reload a system service, optionally falling back to restart if reload fails""" |
320 | + """Reload a system service, optionally falling back to restart if |
321 | + reload fails""" |
322 | service_result = service('reload', service_name) |
323 | if not service_result and restart_on_failure: |
324 | service_result = service('restart', service_name) |
325 | @@ -143,7 +145,19 @@ |
326 | target.write(content) |
327 | |
328 | |
329 | -def mount(device, mountpoint, options=None, persist=False): |
330 | +def fstab_remove(mp): |
331 | + """Remove the given mountpoint entry from /etc/fstab |
332 | + """ |
333 | + return Fstab.remove_by_mountpoint(mp) |
334 | + |
335 | + |
336 | +def fstab_add(dev, mp, fs, options=None): |
337 | + """Adds the given device entry to the /etc/fstab file |
338 | + """ |
339 | + return Fstab.add(dev, mp, fs, options=options) |
340 | + |
341 | + |
342 | +def mount(device, mountpoint, options=None, persist=False, filesystem="ext3"): |
343 | """Mount a filesystem at a particular mountpoint""" |
344 | cmd_args = ['mount'] |
345 | if options is not None: |
346 | @@ -154,9 +168,9 @@ |
347 | except subprocess.CalledProcessError, e: |
348 | log('Error mounting {} at {}\n{}'.format(device, mountpoint, e.output)) |
349 | return False |
350 | + |
351 | if persist: |
352 | - # TODO: update fstab |
353 | - pass |
354 | + return fstab_add(device, mountpoint, filesystem, options=options) |
355 | return True |
356 | |
357 | |
358 | @@ -168,9 +182,9 @@ |
359 | except subprocess.CalledProcessError, e: |
360 | log('Error unmounting {}\n{}'.format(mountpoint, e.output)) |
361 | return False |
362 | + |
363 | if persist: |
364 | - # TODO: update fstab |
365 | - pass |
366 | + return fstab_remove(mountpoint) |
367 | return True |
368 | |
369 | |
370 | @@ -197,13 +211,13 @@ |
371 | def restart_on_change(restart_map, stopstart=False): |
372 | """Restart services based on configuration files changing |
373 | |
374 | - This function is used a decorator, for example |
375 | + This function is used a decorator, for example:: |
376 | |
377 | @restart_on_change({ |
378 | '/etc/ceph/ceph.conf': [ 'cinder-api', 'cinder-volume' ] |
379 | }) |
380 | def ceph_client_changed(): |
381 | - ... |
382 | + pass # your code here |
383 | |
384 | In this example, the cinder-api and cinder-volume services |
385 | would be restarted if /etc/ceph/ceph.conf is changed by the |
386 | @@ -295,3 +309,19 @@ |
387 | if 'link/ether' in words: |
388 | hwaddr = words[words.index('link/ether') + 1] |
389 | return hwaddr |
390 | + |
391 | + |
392 | +def cmp_pkgrevno(package, revno, pkgcache=None): |
393 | + '''Compare supplied revno with the revno of the installed package |
394 | + |
395 | + * 1 => Installed revno is greater than supplied arg |
396 | + * 0 => Installed revno is the same as supplied arg |
397 | + * -1 => Installed revno is less than supplied arg |
398 | + |
399 | + ''' |
400 | + import apt_pkg |
401 | + if not pkgcache: |
402 | + apt_pkg.init() |
403 | + pkgcache = apt_pkg.Cache() |
404 | + pkg = pkgcache[package] |
405 | + return apt_pkg.version_compare(pkg.current_ver.ver_str, revno) |
406 | |
407 | === modified file 'hooks/charmhelpers/fetch/__init__.py' |
408 | --- hooks/charmhelpers/fetch/__init__.py 2014-04-11 20:55:42 +0000 |
409 | +++ hooks/charmhelpers/fetch/__init__.py 2014-07-29 16:34:12 +0000 |
410 | @@ -1,4 +1,5 @@ |
411 | import importlib |
412 | +import time |
413 | from yaml import safe_load |
414 | from charmhelpers.core.host import ( |
415 | lsb_release |
416 | @@ -12,9 +13,9 @@ |
417 | config, |
418 | log, |
419 | ) |
420 | -import apt_pkg |
421 | import os |
422 | |
423 | + |
424 | CLOUD_ARCHIVE = """# Ubuntu Cloud Archive |
425 | deb http://ubuntu-cloud.archive.canonical.com/ubuntu {} main |
426 | """ |
427 | @@ -54,12 +55,74 @@ |
428 | 'icehouse/proposed': 'precise-proposed/icehouse', |
429 | 'precise-icehouse/proposed': 'precise-proposed/icehouse', |
430 | 'precise-proposed/icehouse': 'precise-proposed/icehouse', |
431 | + # Juno |
432 | + 'juno': 'trusty-updates/juno', |
433 | + 'trusty-juno': 'trusty-updates/juno', |
434 | + 'trusty-juno/updates': 'trusty-updates/juno', |
435 | + 'trusty-updates/juno': 'trusty-updates/juno', |
436 | + 'juno/proposed': 'trusty-proposed/juno', |
437 | + 'juno/proposed': 'trusty-proposed/juno', |
438 | + 'trusty-juno/proposed': 'trusty-proposed/juno', |
439 | + 'trusty-proposed/juno': 'trusty-proposed/juno', |
440 | } |
441 | |
442 | +# The order of this list is very important. Handlers should be listed in from |
443 | +# least- to most-specific URL matching. |
444 | +FETCH_HANDLERS = ( |
445 | + 'charmhelpers.fetch.archiveurl.ArchiveUrlFetchHandler', |
446 | + 'charmhelpers.fetch.bzrurl.BzrUrlFetchHandler', |
447 | +) |
448 | + |
449 | +APT_NO_LOCK = 100 # The return code for "couldn't acquire lock" in APT. |
450 | +APT_NO_LOCK_RETRY_DELAY = 10 # Wait 10 seconds between apt lock checks. |
451 | +APT_NO_LOCK_RETRY_COUNT = 30 # Retry to acquire the lock X times. |
452 | + |
453 | + |
454 | +class SourceConfigError(Exception): |
455 | + pass |
456 | + |
457 | + |
458 | +class UnhandledSource(Exception): |
459 | + pass |
460 | + |
461 | + |
462 | +class AptLockError(Exception): |
463 | + pass |
464 | + |
465 | + |
466 | +class BaseFetchHandler(object): |
467 | + |
468 | + """Base class for FetchHandler implementations in fetch plugins""" |
469 | + |
470 | + def can_handle(self, source): |
471 | + """Returns True if the source can be handled. Otherwise returns |
472 | + a string explaining why it cannot""" |
473 | + return "Wrong source type" |
474 | + |
475 | + def install(self, source): |
476 | + """Try to download and unpack the source. Return the path to the |
477 | + unpacked files or raise UnhandledSource.""" |
478 | + raise UnhandledSource("Wrong source type {}".format(source)) |
479 | + |
480 | + def parse_url(self, url): |
481 | + return urlparse(url) |
482 | + |
483 | + def base_url(self, url): |
484 | + """Return url without querystring or fragment""" |
485 | + parts = list(self.parse_url(url)) |
486 | + parts[4:] = ['' for i in parts[4:]] |
487 | + return urlunparse(parts) |
488 | + |
489 | |
490 | def filter_installed_packages(packages): |
491 | """Returns a list of packages that require installation""" |
492 | + import apt_pkg |
493 | apt_pkg.init() |
494 | + |
495 | + # Tell apt to build an in-memory cache to prevent race conditions (if |
496 | + # another process is already building the cache). |
497 | + apt_pkg.config.set("Dir::Cache::pkgcache", "") |
498 | + |
499 | cache = apt_pkg.Cache() |
500 | _pkgs = [] |
501 | for package in packages: |
502 | @@ -87,14 +150,7 @@ |
503 | cmd.extend(packages) |
504 | log("Installing {} with options: {}".format(packages, |
505 | options)) |
506 | - env = os.environ.copy() |
507 | - if 'DEBIAN_FRONTEND' not in env: |
508 | - env['DEBIAN_FRONTEND'] = 'noninteractive' |
509 | - |
510 | - if fatal: |
511 | - subprocess.check_call(cmd, env=env) |
512 | - else: |
513 | - subprocess.call(cmd, env=env) |
514 | + _run_apt_command(cmd, fatal) |
515 | |
516 | |
517 | def apt_upgrade(options=None, fatal=False, dist=False): |
518 | @@ -109,24 +165,13 @@ |
519 | else: |
520 | cmd.append('upgrade') |
521 | log("Upgrading with options: {}".format(options)) |
522 | - |
523 | - env = os.environ.copy() |
524 | - if 'DEBIAN_FRONTEND' not in env: |
525 | - env['DEBIAN_FRONTEND'] = 'noninteractive' |
526 | - |
527 | - if fatal: |
528 | - subprocess.check_call(cmd, env=env) |
529 | - else: |
530 | - subprocess.call(cmd, env=env) |
531 | + _run_apt_command(cmd, fatal) |
532 | |
533 | |
534 | def apt_update(fatal=False): |
535 | """Update local apt cache""" |
536 | cmd = ['apt-get', 'update'] |
537 | - if fatal: |
538 | - subprocess.check_call(cmd) |
539 | - else: |
540 | - subprocess.call(cmd) |
541 | + _run_apt_command(cmd, fatal) |
542 | |
543 | |
544 | def apt_purge(packages, fatal=False): |
545 | @@ -137,10 +182,7 @@ |
546 | else: |
547 | cmd.extend(packages) |
548 | log("Purging {}".format(packages)) |
549 | - if fatal: |
550 | - subprocess.check_call(cmd) |
551 | - else: |
552 | - subprocess.call(cmd) |
553 | + _run_apt_command(cmd, fatal) |
554 | |
555 | |
556 | def apt_hold(packages, fatal=False): |
557 | @@ -151,6 +193,7 @@ |
558 | else: |
559 | cmd.extend(packages) |
560 | log("Holding {}".format(packages)) |
561 | + |
562 | if fatal: |
563 | subprocess.check_call(cmd) |
564 | else: |
565 | @@ -184,57 +227,50 @@ |
566 | apt.write(PROPOSED_POCKET.format(release)) |
567 | if key: |
568 | subprocess.check_call(['apt-key', 'adv', '--keyserver', |
569 | - 'keyserver.ubuntu.com', '--recv', |
570 | + 'hkp://keyserver.ubuntu.com:80', '--recv', |
571 | key]) |
572 | |
573 | |
574 | -class SourceConfigError(Exception): |
575 | - pass |
576 | - |
577 | - |
578 | def configure_sources(update=False, |
579 | sources_var='install_sources', |
580 | keys_var='install_keys'): |
581 | """ |
582 | - Configure multiple sources from charm configuration |
583 | + Configure multiple sources from charm configuration. |
584 | + |
585 | + The lists are encoded as yaml fragments in the configuration. |
586 | + The frament needs to be included as a string. |
587 | |
588 | Example config: |
589 | - install_sources: |
590 | + install_sources: | |
591 | - "ppa:foo" |
592 | - "http://example.com/repo precise main" |
593 | - install_keys: |
594 | + install_keys: | |
595 | - null |
596 | - "a1b2c3d4" |
597 | |
598 | Note that 'null' (a.k.a. None) should not be quoted. |
599 | """ |
600 | - sources = safe_load(config(sources_var)) |
601 | - keys = config(keys_var) |
602 | - if keys is not None: |
603 | - keys = safe_load(keys) |
604 | - if isinstance(sources, basestring) and ( |
605 | - keys is None or isinstance(keys, basestring)): |
606 | - add_source(sources, keys) |
607 | + sources = safe_load((config(sources_var) or '').strip()) or [] |
608 | + keys = safe_load((config(keys_var) or '').strip()) or None |
609 | + |
610 | + if isinstance(sources, basestring): |
611 | + sources = [sources] |
612 | + |
613 | + if keys is None: |
614 | + for source in sources: |
615 | + add_source(source, None) |
616 | else: |
617 | - if not len(sources) == len(keys): |
618 | - msg = 'Install sources and keys lists are different lengths' |
619 | - raise SourceConfigError(msg) |
620 | - for src_num in range(len(sources)): |
621 | - add_source(sources[src_num], keys[src_num]) |
622 | + if isinstance(keys, basestring): |
623 | + keys = [keys] |
624 | + |
625 | + if len(sources) != len(keys): |
626 | + raise SourceConfigError( |
627 | + 'Install sources and keys lists are different lengths') |
628 | + for source, key in zip(sources, keys): |
629 | + add_source(source, key) |
630 | if update: |
631 | apt_update(fatal=True) |
632 | |
633 | -# The order of this list is very important. Handlers should be listed in from |
634 | -# least- to most-specific URL matching. |
635 | -FETCH_HANDLERS = ( |
636 | - 'charmhelpers.fetch.archiveurl.ArchiveUrlFetchHandler', |
637 | - 'charmhelpers.fetch.bzrurl.BzrUrlFetchHandler', |
638 | -) |
639 | - |
640 | - |
641 | -class UnhandledSource(Exception): |
642 | - pass |
643 | - |
644 | |
645 | def install_remote(source): |
646 | """ |
647 | @@ -265,30 +301,6 @@ |
648 | return install_remote(source) |
649 | |
650 | |
651 | -class BaseFetchHandler(object): |
652 | - |
653 | - """Base class for FetchHandler implementations in fetch plugins""" |
654 | - |
655 | - def can_handle(self, source): |
656 | - """Returns True if the source can be handled. Otherwise returns |
657 | - a string explaining why it cannot""" |
658 | - return "Wrong source type" |
659 | - |
660 | - def install(self, source): |
661 | - """Try to download and unpack the source. Return the path to the |
662 | - unpacked files or raise UnhandledSource.""" |
663 | - raise UnhandledSource("Wrong source type {}".format(source)) |
664 | - |
665 | - def parse_url(self, url): |
666 | - return urlparse(url) |
667 | - |
668 | - def base_url(self, url): |
669 | - """Return url without querystring or fragment""" |
670 | - parts = list(self.parse_url(url)) |
671 | - parts[4:] = ['' for i in parts[4:]] |
672 | - return urlunparse(parts) |
673 | - |
674 | - |
675 | def plugins(fetch_handlers=None): |
676 | if not fetch_handlers: |
677 | fetch_handlers = FETCH_HANDLERS |
678 | @@ -306,3 +318,40 @@ |
679 | log("FetchHandler {} not found, skipping plugin".format( |
680 | handler_name)) |
681 | return plugin_list |
682 | + |
683 | + |
684 | +def _run_apt_command(cmd, fatal=False): |
685 | + """ |
686 | + Run an APT command, checking output and retrying if the fatal flag is set |
687 | + to True. |
688 | + |
689 | + :param: cmd: str: The apt command to run. |
690 | + :param: fatal: bool: Whether the command's output should be checked and |
691 | + retried. |
692 | + """ |
693 | + env = os.environ.copy() |
694 | + |
695 | + if 'DEBIAN_FRONTEND' not in env: |
696 | + env['DEBIAN_FRONTEND'] = 'noninteractive' |
697 | + |
698 | + if fatal: |
699 | + retry_count = 0 |
700 | + result = None |
701 | + |
702 | + # If the command is considered "fatal", we need to retry if the apt |
703 | + # lock was not acquired. |
704 | + |
705 | + while result is None or result == APT_NO_LOCK: |
706 | + try: |
707 | + result = subprocess.check_call(cmd, env=env) |
708 | + except subprocess.CalledProcessError, e: |
709 | + retry_count = retry_count + 1 |
710 | + if retry_count > APT_NO_LOCK_RETRY_COUNT: |
711 | + raise |
712 | + result = e.returncode |
713 | + log("Couldn't acquire DPKG lock. Will retry in {} seconds." |
714 | + "".format(APT_NO_LOCK_RETRY_DELAY)) |
715 | + time.sleep(APT_NO_LOCK_RETRY_DELAY) |
716 | + |
717 | + else: |
718 | + subprocess.call(cmd, env=env) |
719 | |
720 | === modified file 'hooks/charmhelpers/fetch/bzrurl.py' |
721 | --- hooks/charmhelpers/fetch/bzrurl.py 2014-04-11 20:55:42 +0000 |
722 | +++ hooks/charmhelpers/fetch/bzrurl.py 2014-07-29 16:34:12 +0000 |
723 | @@ -39,7 +39,8 @@ |
724 | def install(self, source): |
725 | url_parts = self.parse_url(source) |
726 | branch_name = url_parts.path.strip("/").split("/")[-1] |
727 | - dest_dir = os.path.join(os.environ.get('CHARM_DIR'), "fetched", branch_name) |
728 | + dest_dir = os.path.join(os.environ.get('CHARM_DIR'), "fetched", |
729 | + branch_name) |
730 | if not os.path.exists(dest_dir): |
731 | mkdir(dest_dir, perms=0755) |
732 | try: |
733 | |
734 | === modified file 'hooks/hooks.py' |
735 | --- hooks/hooks.py 2014-07-29 10:22:55 +0000 |
736 | +++ hooks/hooks.py 2014-07-29 16:34:12 +0000 |
737 | @@ -6,7 +6,6 @@ |
738 | ''' |
739 | |
740 | import commands |
741 | -import json |
742 | import os |
743 | import re |
744 | import signal |
745 | @@ -15,7 +14,6 @@ |
746 | import sys |
747 | import time |
748 | import yaml |
749 | -import argparse |
750 | |
751 | from os import chmod |
752 | from os import remove |
753 | @@ -29,10 +27,26 @@ |
754 | apt_update, |
755 | apt_install |
756 | ) |
757 | + |
758 | from charmhelpers.core.hookenv import ( |
759 | - config |
760 | -) |
761 | - |
762 | + config, |
763 | + unit_get, |
764 | + relation_get, |
765 | + relation_set, |
766 | + relations_of_type, |
767 | + relation_id, |
768 | + open_port, |
769 | + close_port, |
770 | + Hooks, |
771 | +) |
772 | + |
773 | +from charmhelpers.core.hookenv import log as juju_log |
774 | + |
775 | +from charmhelpers.core.host import ( |
776 | + service, |
777 | +) |
778 | + |
779 | +hooks = Hooks() |
780 | |
781 | ############################################################################### |
782 | # Global variables |
783 | @@ -40,8 +54,8 @@ |
784 | default_mongodb_config = "/etc/mongodb.conf" |
785 | default_mongodb_init_config = "/etc/init/mongodb.conf" |
786 | default_mongos_list = "/etc/mongos.list" |
787 | -default_wait_for = 20 |
788 | -default_max_tries = 20 |
789 | +default_wait_for = 10 |
790 | +default_max_tries = 5 |
791 | |
792 | ############################################################################### |
793 | # Supporting functions |
794 | @@ -494,7 +508,7 @@ |
795 | config.append("") |
796 | |
797 | # arbiter |
798 | - if config_data['arbiter'] != "disabled" and\ |
799 | + if config_data['arbiter'] != "disabled" and \ |
800 | config_data['arbiter'] != "enabled": |
801 | config.append("arbiter = %s" % config_data['arbiter']) |
802 | config.append("") |
803 | @@ -657,7 +671,7 @@ |
804 | |
805 | |
806 | def configsvr_status(wait_for=default_wait_for, max_tries=default_max_tries): |
807 | - config_data = config_get() |
808 | + config_data = config() |
809 | current_try = 0 |
810 | while (process_check_pidfile('/var/run/mongodb/configsvr.pid') != |
811 | (None, None)) and not port_check( |
812 | @@ -685,7 +699,7 @@ |
813 | juju_log("disable_configsvr: port not defined.") |
814 | return(False) |
815 | try: |
816 | - config_server_port = config_get('config_server_port') |
817 | + config_server_port = config('config_server_port') |
818 | pid = open('/var/run/mongodb/configsvr.pid').read() |
819 | os.kill(int(pid), signal.SIGTERM) |
820 | os.unlink('/var/run/mongodb/configsvr.pid') |
821 | @@ -747,7 +761,7 @@ |
822 | |
823 | |
824 | def mongos_status(wait_for=default_wait_for, max_tries=default_max_tries): |
825 | - config_data = config_get() |
826 | + config_data = config() |
827 | current_try = 0 |
828 | while (process_check_pidfile('/var/run/mongodb/mongos.pid') != |
829 | (None, None)) and not port_check( |
830 | @@ -839,17 +853,17 @@ |
831 | |
832 | def restart_mongod(wait_for=default_wait_for, max_tries=default_max_tries): |
833 | my_hostname = unit_get('public-address') |
834 | - my_port = config_get('port') |
835 | + my_port = config('port') |
836 | current_try = 0 |
837 | |
838 | - service('mongodb', 'stop') |
839 | + service('stop', 'mongodb') |
840 | if os.path.exists('/var/lib/mongodb/mongod.lock'): |
841 | os.remove('/var/lib/mongodb/mongod.lock') |
842 | |
843 | - if not service('mongodb', 'start'): |
844 | + if not service('start', 'mongodb'): |
845 | return False |
846 | |
847 | - while (service('mongodb', 'status') and |
848 | + while (service('status', 'mongodb') and |
849 | not port_check(my_hostname, my_port) and |
850 | current_try < max_tries): |
851 | juju_log( |
852 | @@ -859,14 +873,14 @@ |
853 | current_try += 1 |
854 | |
855 | return( |
856 | - (service('mongodb', 'status') == port_check(my_hostname, my_port)) |
857 | + (service('status', 'mongodb') == port_check(my_hostname, my_port)) |
858 | is True) |
859 | |
860 | |
861 | def backup_cronjob(disable=False): |
862 | """Generate the cronjob to backup with mongodbump.""" |
863 | juju_log('Setting up cronjob') |
864 | - config_data = config_get() |
865 | + config_data = config() |
866 | backupdir = config_data['backup_directory'] |
867 | bind_ip = config_data['bind_ip'] |
868 | cron_file = '/etc/cron.d/mongodb' |
869 | @@ -915,18 +929,19 @@ |
870 | ############################################################################### |
871 | # Hook functions |
872 | ############################################################################### |
873 | +@hooks.hook('install') |
874 | def install_hook(): |
875 | juju_log("Installing mongodb") |
876 | add_source(config('source'), config('key')) |
877 | apt_update(fatal=True) |
878 | apt_install(packages=['mongodb', 'python-yaml'], fatal=True) |
879 | - return True |
880 | - |
881 | - |
882 | + |
883 | + |
884 | +@hooks.hook('config-changed') |
885 | def config_changed(): |
886 | juju_log("Entering config_changed") |
887 | print "Entering config_changed" |
888 | - config_data = config_get() |
889 | + config_data = config() |
890 | print "config_data: ", config_data |
891 | mongodb_config = open(default_mongodb_config).read() |
892 | |
893 | @@ -1048,7 +1063,7 @@ |
894 | juju_log("config_changed: Exceptions: %s" % str(e)) |
895 | |
896 | if mongos_pid is not None: |
897 | - mongos_port = re.search('--port (\w+)', mongos_cmd_line).group(2) |
898 | + mongos_port = re.search('--port (\w+)', mongos_cmd_line).group(1) |
899 | disable_mongos(mongos_port) |
900 | enable_mongos(config_data['mongos_port']) |
901 | else: |
902 | @@ -1058,6 +1073,7 @@ |
903 | return(True) |
904 | |
905 | |
906 | +@hooks.hook('start') |
907 | def start_hook(): |
908 | juju_log("start_hook") |
909 | retVal = restart_mongod() |
910 | @@ -1065,10 +1081,11 @@ |
911 | return(retVal) |
912 | |
913 | |
914 | +@hooks.hook('stop') |
915 | def stop_hook(): |
916 | juju_log("stop_hook") |
917 | try: |
918 | - retVal = service('mongodb', 'stop') |
919 | + retVal = service('stop', 'mongodb') |
920 | os.remove('/var/lib/mongodb/mongod.lock') |
921 | #FIXME Need to check if this is still needed |
922 | except Exception, e: |
923 | @@ -1079,15 +1096,16 @@ |
924 | return(retVal) |
925 | |
926 | |
927 | +@hooks.hook('database-relation-joined') |
928 | def database_relation_joined(): |
929 | juju_log("database_relation_joined") |
930 | my_hostname = unit_get('public-address') |
931 | - my_port = config_get('port') |
932 | - my_replset = config_get('replicaset') |
933 | + my_port = config('port') |
934 | + my_replset = config('replicaset') |
935 | juju_log("my_hostname: %s" % my_hostname) |
936 | juju_log("my_port: %s" % my_port) |
937 | juju_log("my_replset: %s" % my_replset) |
938 | - return(relation_set( |
939 | + return(relation_set(relation_id(), |
940 | { |
941 | 'hostname': my_hostname, |
942 | 'port': my_port, |
943 | @@ -1096,34 +1114,36 @@ |
944 | })) |
945 | |
946 | |
947 | +@hooks.hook('replicaset-relation-joined') |
948 | def replica_set_relation_joined(): |
949 | juju_log("replica_set_relation_joined") |
950 | my_hostname = unit_get('public-address') |
951 | - my_port = config_get('port') |
952 | - my_replset = config_get('replicaset') |
953 | + my_port = config('port') |
954 | + my_replset = config('replicaset') |
955 | my_install_order = os.environ['JUJU_UNIT_NAME'].split('/')[1] |
956 | juju_log("my_hostname: %s" % my_hostname) |
957 | juju_log("my_port: %s" % my_port) |
958 | juju_log("my_replset: %s" % my_replset) |
959 | juju_log("my_install_order: %s" % my_install_order) |
960 | - return(enable_replset(my_replset) == |
961 | - restart_mongod() == |
962 | - relation_set( |
963 | - { |
964 | - 'hostname': my_hostname, |
965 | - 'port': my_port, |
966 | - 'replset': my_replset, |
967 | - 'install-order': my_install_order, |
968 | - 'type': 'replset', |
969 | - })) |
970 | - |
971 | - |
972 | + enable_replset(my_replset) |
973 | + restart_mongod() |
974 | + |
975 | + relation_set(relation_id(), { |
976 | + 'hostname': my_hostname, |
977 | + 'port': my_port, |
978 | + 'replset': my_replset, |
979 | + 'install-order': my_install_order, |
980 | + 'type': 'replset', |
981 | + }) |
982 | + |
983 | + |
984 | +@hooks.hook('replicaset-relation-changed') |
985 | def replica_set_relation_changed(): |
986 | juju_log("replica_set_relation_changed") |
987 | my_hostname = unit_get('public-address') |
988 | - my_port = config_get('port') |
989 | + my_port = config('port') |
990 | my_install_order = os.environ['JUJU_UNIT_NAME'].split('/')[1] |
991 | - my_replicaset_master = config_get('replicaset_master') |
992 | + my_replicaset_master = config('replicaset_master') |
993 | |
994 | # If we are joining an existing replicaset cluster, just join and leave. |
995 | if my_replicaset_master != "auto": |
996 | @@ -1135,44 +1155,46 @@ |
997 | master_install_order = my_install_order |
998 | |
999 | # Check the nodes in the relation to find the master |
1000 | - for member in relation_list(): |
1001 | + for member in relations_of_type('replica-set'): |
1002 | + member = member['__unit__'] |
1003 | juju_log("replica_set_relation_changed: member: %s" % member) |
1004 | hostname = relation_get('hostname', member) |
1005 | port = relation_get('port', member) |
1006 | - install_order = relation_get('install-order', member) |
1007 | - juju_log("replica_set_relation_changed: install_order: %s" % install_order) |
1008 | - if install_order is None: |
1009 | - juju_log("replica_set_relation_changed: install_order is None. relation is not ready") |
1010 | + inst_ordr = relation_get('install-order', member) |
1011 | + juju_log("replica_set_relation_changed: install_order: %s" % inst_ordr) |
1012 | + if inst_ordr is None: |
1013 | + juju_log("replica_set_relation_changed: install_order is None." |
1014 | + " relation is not ready") |
1015 | break |
1016 | - if int(install_order) < int(master_install_order): |
1017 | + if int(inst_ordr) < int(master_install_order): |
1018 | master_hostname = hostname |
1019 | master_port = port |
1020 | - master_install_order = install_order |
1021 | + master_install_order = inst_ordr |
1022 | |
1023 | # Initiate the replset |
1024 | init_replset("%s:%s" % (master_hostname, master_port)) |
1025 | |
1026 | # Add the rest of the nodes to the replset |
1027 | - for member in relation_list(): |
1028 | - hostname = relation_get('hostname', member) |
1029 | - port = relation_get('port', member) |
1030 | + for member in relations_of_type('replica-set'): |
1031 | + hostname = relation_get('hostname', member['__unit__']) |
1032 | + port = relation_get('port', member['__unit__']) |
1033 | if master_hostname != hostname: |
1034 | if hostname == my_hostname: |
1035 | - subprocess.call(['mongo', |
1036 | - '--eval', |
1037 | - "rs.add(\"%s\")" % hostname]) |
1038 | + subprocess.call(['mongo', '--eval', |
1039 | + "rs.add(\"%s\")" % hostname]) |
1040 | else: |
1041 | join_replset("%s:%s" % (master_hostname, master_port), |
1042 | - "%s:%s" % (hostname, port)) |
1043 | + "%s:%s" % (hostname, port)) |
1044 | |
1045 | # Add this node to the replset ( if needed ) |
1046 | if master_hostname != my_hostname: |
1047 | join_replset("%s:%s" % (master_hostname, master_port), |
1048 | - "%s:%s" % (my_hostname, my_port)) |
1049 | - |
1050 | - return(True) |
1051 | - |
1052 | - |
1053 | + "%s:%s" % (my_hostname, my_port)) |
1054 | + |
1055 | + |
1056 | + |
1057 | + |
1058 | +@hooks.hook('data-relation-joined') |
1059 | def data_relation_joined(): |
1060 | juju_log("data_relation_joined") |
1061 | |
1062 | @@ -1182,6 +1204,7 @@ |
1063 | })) |
1064 | |
1065 | |
1066 | +@hooks.hook('data-relation-changed') |
1067 | def data_relation_changed(): |
1068 | juju_log("data_relation_changed") |
1069 | |
1070 | @@ -1192,57 +1215,60 @@ |
1071 | return(config_changed()) |
1072 | |
1073 | |
1074 | +@hooks.hook('data-relation-departed') |
1075 | def data_relation_departed(): |
1076 | juju_log("data_relation_departed") |
1077 | return(config_changed()) |
1078 | |
1079 | - |
1080 | +@hooks.hook('configsvr-relation-joined') |
1081 | def configsvr_relation_joined(): |
1082 | juju_log("configsvr_relation_joined") |
1083 | my_hostname = unit_get('public-address') |
1084 | - my_port = config_get('config_server_port') |
1085 | + my_port = config('config_server_port') |
1086 | my_install_order = os.environ['JUJU_UNIT_NAME'].split('/')[1] |
1087 | - return(relation_set( |
1088 | - { |
1089 | - 'hostname': my_hostname, |
1090 | - 'port': my_port, |
1091 | - 'install-order': my_install_order, |
1092 | - 'type': 'configsvr', |
1093 | - })) |
1094 | - |
1095 | - |
1096 | + return(relation_set(relation_id(), |
1097 | + { |
1098 | + 'hostname': my_hostname, |
1099 | + 'port': my_port, |
1100 | + 'install-order': my_install_order, |
1101 | + 'type': 'configsvr', |
1102 | + })) |
1103 | + |
1104 | + |
1105 | +@hooks.hook('configsvr-relation-changed') |
1106 | def configsvr_relation_changed(): |
1107 | juju_log("configsvr_relation_changed") |
1108 | - config_data = config_get() |
1109 | + config_data = config() |
1110 | my_port = config_data['config_server_port'] |
1111 | disable_configsvr(my_port) |
1112 | - retVal = enable_configsvr(config_data) |
1113 | - juju_log("configsvr_relation_changed returns: %s" % retVal) |
1114 | - return(retVal) |
1115 | - |
1116 | - |
1117 | + |
1118 | + |
1119 | +@hooks.hook('mongos-cfg-relation-joined') |
1120 | +@hooks.hook('mongos-relation-joined') |
1121 | def mongos_relation_joined(): |
1122 | juju_log("mongos_relation_joined") |
1123 | my_hostname = unit_get('public-address') |
1124 | - my_port = config_get('mongos_port') |
1125 | + my_port = config('mongos_port') |
1126 | my_install_order = os.environ['JUJU_UNIT_NAME'].split('/')[1] |
1127 | - return(relation_set( |
1128 | - { |
1129 | - 'hostname': my_hostname, |
1130 | - 'port': my_port, |
1131 | - 'install-order': my_install_order, |
1132 | - 'type': 'mongos' |
1133 | - })) |
1134 | - |
1135 | - |
1136 | + relation_set(relation_id(), |
1137 | + { |
1138 | + 'hostname': my_hostname, |
1139 | + 'port': my_port, |
1140 | + 'install-order': my_install_order, |
1141 | + 'type': 'mongos' |
1142 | + }) |
1143 | + |
1144 | + |
1145 | +@hooks.hook('mongos-cfg-relation-changed') |
1146 | +@hooks.hook('mongos-relation-changed') |
1147 | def mongos_relation_changed(): |
1148 | juju_log("mongos_relation_changed") |
1149 | - config_data = config_get() |
1150 | + config_data = config() |
1151 | retVal = False |
1152 | - for member in relation_list(): |
1153 | - hostname = relation_get('hostname', member) |
1154 | - port = relation_get('port', member) |
1155 | - rel_type = relation_get('type', member) |
1156 | + for member in relations_of_type('mongos-cfg'): |
1157 | + hostname = relation_get('hostname', member['__unit__']) |
1158 | + port = relation_get('port', member['__unit__']) |
1159 | + rel_type = relation_get('type', member['__unit__']) |
1160 | if hostname is None or port is None or rel_type is None: |
1161 | juju_log("mongos_relation_changed: relation data not ready.") |
1162 | break |
1163 | @@ -1264,34 +1290,33 @@ |
1164 | if mongos_ready(): |
1165 | mongos_host = "%s:%s" % ( |
1166 | unit_get('public-address'), |
1167 | - config_get('mongos_port')) |
1168 | + config('mongos_port')) |
1169 | shard_command1 = "sh.addShard(\"%s:%s\")" % (hostname, port) |
1170 | - retVal1 = mongo_client(mongos_host, shard_command1) |
1171 | + mongo_client(mongos_host, shard_command1) |
1172 | replicaset = relation_get('replset', member) |
1173 | - shard_command2 = "sh.addShard(\"%s/%s:%s\")" % \ |
1174 | + shard_command2 = "sh.addShard(\"%s/%s:%s\")" % \ |
1175 | (replicaset, hostname, port) |
1176 | - retVal2 = mongo_client(mongos_host, shard_command2) |
1177 | - retVal = retVal1 is True and retVal2 is True |
1178 | - else: |
1179 | - juju_log("Not enough config server for mongos yet.") |
1180 | - retVal = True |
1181 | + mongo_client(mongos_host, shard_command2) |
1182 | + |
1183 | + |
1184 | else: |
1185 | juju_log("mongos_relation_change: undefined rel_type: %s" % |
1186 | - rel_type) |
1187 | + rel_type) |
1188 | return(False) |
1189 | juju_log("mongos_relation_changed returns: %s" % retVal) |
1190 | - return(retVal) |
1191 | - |
1192 | - |
1193 | + |
1194 | + |
1195 | + |
1196 | +@hooks.hook('mongos-relation-broken') |
1197 | def mongos_relation_broken(): |
1198 | -# config_servers = load_config_servers(default_mongos_list) |
1199 | -# for member in relation_list(): |
1200 | -# hostname = relation_get('hostname', member) |
1201 | -# port = relation_get('port', member) |
1202 | -# if '%s:%s' % (hostname, port) in config_servers: |
1203 | -# config_servers.remove('%s:%s' % (hostname, port)) |
1204 | -# return(update_file(default_mongos_list, '\n'.join(config_servers))) |
1205 | - return(True) |
1206 | + config_servers = load_config_servers(default_mongos_list) |
1207 | + for member in relations_of_type('mongos'): |
1208 | + hostname = relation_get('hostname', member) |
1209 | + port = relation_get('port', member) |
1210 | + if '%s:%s' % (hostname, port) in config_servers: |
1211 | + config_servers.remove('%s:%s' % (hostname, port)) |
1212 | + |
1213 | + update_file(default_mongos_list, '\n'.join(config_servers)) |
1214 | |
1215 | |
1216 | def run(command, exit_on_error=True): |
1217 | @@ -1318,7 +1343,7 @@ |
1218 | # |
1219 | #------------------------------ |
1220 | def volume_get_volid_from_volume_map(): |
1221 | - config_data = config_get() |
1222 | + config_data = config() |
1223 | volume_map = {} |
1224 | try: |
1225 | volume_map = yaml.load(config_data['volume-map'].strip()) |
1226 | @@ -1379,19 +1404,21 @@ |
1227 | # None config state is invalid - we should not serve |
1228 | def volume_get_volume_id(): |
1229 | |
1230 | + config_data = config() |
1231 | + |
1232 | + |
1233 | |
1234 | volid = volume_get_id_for_storage_subordinate() |
1235 | if volid: |
1236 | return volid |
1237 | |
1238 | - config_data = config_get() |
1239 | ephemeral_storage = config_data['volume-ephemeral-storage'] |
1240 | volid = volume_get_volid_from_volume_map() |
1241 | juju_unit_name = os.environ['JUJU_UNIT_NAME'] |
1242 | if ephemeral_storage in [True, 'yes', 'Yes', 'true', 'True']: |
1243 | if volid: |
1244 | juju_log( |
1245 | - "volume-ephemeral-storage is True, but " + |
1246 | + "volume-ephemeral-storage is True, but |
1247 | "volume-map[{!r}] -> {}".format(juju_unit_name, volid)) |
1248 | return None |
1249 | else: |
1250 | @@ -1424,6 +1451,7 @@ |
1251 | return None |
1252 | return output |
1253 | |
1254 | + |
1255 | #------------------------------------------------------------------------------ |
1256 | # Core logic for permanent storage changes: |
1257 | # NOTE the only 2 "True" return points: |
1258 | @@ -1435,7 +1463,7 @@ |
1259 | # - manipulate /var/lib/mongodb/VERSION/CLUSTER symlink |
1260 | #------------------------------------------------------------------------------ |
1261 | def config_changed_volume_apply(): |
1262 | - config_data = config_get() |
1263 | + config_data = config() |
1264 | data_directory_path = config_data["dbpath"] |
1265 | assert(data_directory_path) |
1266 | volid = volume_get_volume_id() |
1267 | @@ -1548,57 +1576,6 @@ |
1268 | ############################################################################### |
1269 | # Main section |
1270 | ############################################################################### |
1271 | -if __name__ == '__main__': |
1272 | - parser = argparse.ArgumentParser() |
1273 | - parser.add_argument('-H', '--hook_name', dest='hook_name', |
1274 | - help='hook to call') |
1275 | - args = parser.parse_args() |
1276 | - if args.hook_name is not None: |
1277 | - hook_name = args.hook_name |
1278 | - else: |
1279 | - hook_name = os.path.basename(sys.argv[0]) |
1280 | - |
1281 | - if hook_name == "install": |
1282 | - retVal = install_hook() |
1283 | - elif hook_name == "config-changed": |
1284 | - retVal = config_changed() |
1285 | - elif hook_name == "start": |
1286 | - retVal = start_hook() |
1287 | - elif hook_name == "stop": |
1288 | - retVal = stop_hook() |
1289 | - elif hook_name == "database-relation-joined": |
1290 | - retVal = database_relation_joined() |
1291 | - elif hook_name == "replica-set-relation-joined": |
1292 | - retVal = replica_set_relation_joined() |
1293 | - elif hook_name == "replica-set-relation-changed": |
1294 | - retVal = replica_set_relation_changed() |
1295 | - elif hook_name == "configsvr-relation-joined": |
1296 | - retVal = configsvr_relation_joined() |
1297 | - elif hook_name == "configsvr-relation-changed": |
1298 | - retVal = configsvr_relation_changed() |
1299 | - elif hook_name == "mongos-cfg-relation-joined": |
1300 | - retVal = mongos_relation_joined() |
1301 | - elif hook_name == "mongos-cfg-relation-changed": |
1302 | - retVal = mongos_relation_changed() |
1303 | - elif hook_name == "mongos-cfg-relation-broken": |
1304 | - retVal = mongos_relation_broken() |
1305 | - elif hook_name == "mongos-relation-joined": |
1306 | - retVal = mongos_relation_joined() |
1307 | - elif hook_name == "mongos-relation-changed": |
1308 | - retVal = mongos_relation_changed() |
1309 | - elif hook_name == "mongos-relation-broken": |
1310 | - retVal = mongos_relation_broken() |
1311 | - elif hook_name == "data-relation-joined": |
1312 | - retVal = data_relation_joined() |
1313 | - elif hook_name == "data-relation-changed": |
1314 | - retVal = data_relation_changed() |
1315 | - elif hook_name == "data-relation-departed": |
1316 | - retVal = data_relation_departed() |
1317 | - else: |
1318 | - print "Unknown hook" |
1319 | - retVal = False |
1320 | - |
1321 | - if retVal is True: |
1322 | - sys.exit(0) |
1323 | - else: |
1324 | - sys.exit(1) |
1325 | +if __name__ == "__main__": |
1326 | + # execute a hook based on the name the program is called by |
1327 | + hooks.execute(sys.argv) |
1328 | \ No newline at end of file |
1329 | |
1330 | === modified file 'hooks/install' |
1331 | --- hooks/install 2013-11-25 19:48:00 +0000 |
1332 | +++ hooks/install 1970-01-01 00:00:00 +0000 |
1333 | @@ -1,5 +0,0 @@ |
1334 | -#!/bin/bash |
1335 | - |
1336 | -sudo apt-get install "python-yaml" |
1337 | - |
1338 | -hooks/hooks.py -H install |
1339 | |
1340 | === target is u'hooks.py' |
1341 | === modified file 'metadata.yaml' |
1342 | --- metadata.yaml 2014-06-18 11:13:54 +0000 |
1343 | +++ metadata.yaml 2014-07-29 16:34:12 +0000 |
1344 | @@ -1,6 +1,9 @@ |
1345 | name: mongodb |
1346 | -maintainer: Juan Negron <juan.negron@canonical.com> |
1347 | -summary: MongoDB (from humongous) is an open-source document database |
1348 | +summary: An open-source document database, and the leading NoSQL database |
1349 | +maintainers: |
1350 | + - Juan Negron <juan.negron@canonical.com> |
1351 | + - Marco Ceppi <marco@ceppi.net> |
1352 | + - Charles Butler <chuck@dasroot.net> |
1353 | description: | |
1354 | MongoDB is a high-performance, open source, schema-free document- |
1355 | oriented data store that's easy to deploy, manage and use. It's |
1356 | |
1357 | === added file 'tests/200_relate_ceilometer.test' |
1358 | --- tests/200_relate_ceilometer.test 1970-01-01 00:00:00 +0000 |
1359 | +++ tests/200_relate_ceilometer.test 2014-07-29 16:34:12 +0000 |
1360 | @@ -0,0 +1,43 @@ |
1361 | +#!/usr/bin/env python3 |
1362 | + |
1363 | +import amulet |
1364 | +import pdb |
1365 | + |
1366 | +class TestDeploy(object): |
1367 | + |
1368 | + def __init__(self, time=2500): |
1369 | + # Attempt to load the deployment topology from a bundle. |
1370 | + self.deploy = amulet.Deployment(series="trusty") |
1371 | + |
1372 | + # If something errored out, attempt to continue by |
1373 | + # manually specifying a standalone deployment |
1374 | + self.deploy.add('mongodb') |
1375 | + self.deploy.add('ceilometer', 'cs:trusty/ceilometer') |
1376 | + # send blank configs to finalize the objects in the deployment map |
1377 | + self.deploy.configure('mongodb', {}) |
1378 | + self.deploy.configure('ceilometer', {}) |
1379 | + |
1380 | + self.deploy.relate('mongodb:database', 'ceilometer:shared-db') |
1381 | + |
1382 | + try: |
1383 | + self.deploy.setup(time) |
1384 | + self.deploy.sentry.wait(time) |
1385 | + except: |
1386 | + amulet.raise_status(amulet.FAIL, msg="Environment standup timeout") |
1387 | + # sentry = self.deploy.sentry |
1388 | + |
1389 | + def run(self): |
1390 | + for test in dir(self): |
1391 | + if test.startswith('test_'): |
1392 | + getattr(self, test)() |
1393 | + |
1394 | + def test_mongo_relation(self): |
1395 | + unit = self.deploy.sentry.unit['ceilometer/0'] |
1396 | + mongo = self.deploy.sentry.unit['mongodb/0'].info['public-address'] |
1397 | + cont = unit.file_contents('/etc/ceilometer/ceilometer.conf') |
1398 | + if mongo not in cont: |
1399 | + amulet.raise_status(amulet.FAIL, "Unable to verify ceilometer cfg") |
1400 | + |
1401 | +if __name__ == '__main__': |
1402 | + runner = TestDeploy() |
1403 | + runner.run() |
Unless my read of the inline diff below is wrong you have some merge conflicts that need addressing. Happy to peek at it again after. Thanks!