Merge lp:~lazypower/charms/trusty/mongodb/fixing_st00f into lp:charms/mongodb

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
Reviewer Review Type Date Requested Status
Charles Butler (community) Needs Fixing
Benjamin Saller (community) Needs Fixing
Review via email: mp+228714@code.launchpad.net

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

Revision history for this message
Benjamin Saller (bcsaller) wrote :

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!

review: Needs Fixing
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
=== added file '.bzrignore'
--- .bzrignore 1970-01-01 00:00:00 +0000
+++ .bzrignore 2014-07-29 16:34:12 +0000
@@ -0,0 +1,3 @@
1.git
2bin/*
3scripts/charm-helpers-sync.py
04
=== modified file 'Makefile'
--- Makefile 2014-04-11 20:55:42 +0000
+++ Makefile 2014-07-29 16:34:12 +0000
@@ -13,9 +13,17 @@
13# You should have received a copy of the GNU Affero General Public License13# 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/>.14# along with this program. If not, see <http://www.gnu.org/licenses/>.
1515
16PYTHON := /usr/bin/env python
1617
17unittest:18unittest:
18 tests/10-unit.test19 tests/10-unit.test
1920
20sync:21sync:
21 @charm-helper-sync -c charm-helpers-sync.yaml22 @mkdir -p bin
23 @bzr cat lp:charm-helpers/tools/charm_helpers_sync/charm_helpers_sync.py > bin/charm_helpers_sync.py
24 @$(PYTHON) bin/charm_helpers_sync.py -c charm-helpers-sync.yaml
25
26clean:
27 @find . -name \*.pyc -delete
28 @find . -name '*.bak' -delete
29
2230
=== added file '__init__.py'
=== added directory 'bin'
=== added file 'hooks/charmhelpers/core/fstab.py'
--- hooks/charmhelpers/core/fstab.py 1970-01-01 00:00:00 +0000
+++ hooks/charmhelpers/core/fstab.py 2014-07-29 16:34:12 +0000
@@ -0,0 +1,116 @@
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4__author__ = 'Jorge Niedbalski R. <jorge.niedbalski@canonical.com>'
5
6import os
7
8
9class Fstab(file):
10 """This class extends file in order to implement a file reader/writer
11 for file `/etc/fstab`
12 """
13
14 class Entry(object):
15 """Entry class represents a non-comment line on the `/etc/fstab` file
16 """
17 def __init__(self, device, mountpoint, filesystem,
18 options, d=0, p=0):
19 self.device = device
20 self.mountpoint = mountpoint
21 self.filesystem = filesystem
22
23 if not options:
24 options = "defaults"
25
26 self.options = options
27 self.d = d
28 self.p = p
29
30 def __eq__(self, o):
31 return str(self) == str(o)
32
33 def __str__(self):
34 return "{} {} {} {} {} {}".format(self.device,
35 self.mountpoint,
36 self.filesystem,
37 self.options,
38 self.d,
39 self.p)
40
41 DEFAULT_PATH = os.path.join(os.path.sep, 'etc', 'fstab')
42
43 def __init__(self, path=None):
44 if path:
45 self._path = path
46 else:
47 self._path = self.DEFAULT_PATH
48 file.__init__(self, self._path, 'r+')
49
50 def _hydrate_entry(self, line):
51 # NOTE: use split with no arguments to split on any
52 # whitespace including tabs
53 return Fstab.Entry(*filter(
54 lambda x: x not in ('', None),
55 line.strip("\n").split()))
56
57 @property
58 def entries(self):
59 self.seek(0)
60 for line in self.readlines():
61 try:
62 if not line.startswith("#"):
63 yield self._hydrate_entry(line)
64 except ValueError:
65 pass
66
67 def get_entry_by_attr(self, attr, value):
68 for entry in self.entries:
69 e_attr = getattr(entry, attr)
70 if e_attr == value:
71 return entry
72 return None
73
74 def add_entry(self, entry):
75 if self.get_entry_by_attr('device', entry.device):
76 return False
77
78 self.write(str(entry) + '\n')
79 self.truncate()
80 return entry
81
82 def remove_entry(self, entry):
83 self.seek(0)
84
85 lines = self.readlines()
86
87 found = False
88 for index, line in enumerate(lines):
89 if not line.startswith("#"):
90 if self._hydrate_entry(line) == entry:
91 found = True
92 break
93
94 if not found:
95 return False
96
97 lines.remove(line)
98
99 self.seek(0)
100 self.write(''.join(lines))
101 self.truncate()
102 return True
103
104 @classmethod
105 def remove_by_mountpoint(cls, mountpoint, path=None):
106 fstab = cls(path=path)
107 entry = fstab.get_entry_by_attr('mountpoint', mountpoint)
108 if entry:
109 return fstab.remove_entry(entry)
110 return False
111
112 @classmethod
113 def add(cls, device, mountpoint, filesystem, options=None, path=None):
114 return cls(path=path).add_entry(Fstab.Entry(device,
115 mountpoint, filesystem,
116 options=options))
0117
=== modified file 'hooks/charmhelpers/core/hookenv.py'
--- hooks/charmhelpers/core/hookenv.py 2014-04-11 20:55:42 +0000
+++ hooks/charmhelpers/core/hookenv.py 2014-07-29 16:34:12 +0000
@@ -25,7 +25,7 @@
25def cached(func):25def cached(func):
26 """Cache return values for multiple executions of func + args26 """Cache return values for multiple executions of func + args
2727
28 For example:28 For example::
2929
30 @cached30 @cached
31 def unit_get(attribute):31 def unit_get(attribute):
@@ -155,6 +155,100 @@
155 return os.path.basename(sys.argv[0])155 return os.path.basename(sys.argv[0])
156156
157157
158class Config(dict):
159 """A Juju charm config dictionary that can write itself to
160 disk (as json) and track which values have changed since
161 the previous hook invocation.
162
163 Do not instantiate this object directly - instead call
164 ``hookenv.config()``
165
166 Example usage::
167
168 >>> # inside a hook
169 >>> from charmhelpers.core import hookenv
170 >>> config = hookenv.config()
171 >>> config['foo']
172 'bar'
173 >>> config['mykey'] = 'myval'
174 >>> config.save()
175
176
177 >>> # user runs `juju set mycharm foo=baz`
178 >>> # now we're inside subsequent config-changed hook
179 >>> config = hookenv.config()
180 >>> config['foo']
181 'baz'
182 >>> # test to see if this val has changed since last hook
183 >>> config.changed('foo')
184 True
185 >>> # what was the previous value?
186 >>> config.previous('foo')
187 'bar'
188 >>> # keys/values that we add are preserved across hooks
189 >>> config['mykey']
190 'myval'
191 >>> # don't forget to save at the end of hook!
192 >>> config.save()
193
194 """
195 CONFIG_FILE_NAME = '.juju-persistent-config'
196
197 def __init__(self, *args, **kw):
198 super(Config, self).__init__(*args, **kw)
199 self._prev_dict = None
200 self.path = os.path.join(charm_dir(), Config.CONFIG_FILE_NAME)
201 if os.path.exists(self.path):
202 self.load_previous()
203
204 def load_previous(self, path=None):
205 """Load previous copy of config from disk so that current values
206 can be compared to previous values.
207
208 :param path:
209
210 File path from which to load the previous config. If `None`,
211 config is loaded from the default location. If `path` is
212 specified, subsequent `save()` calls will write to the same
213 path.
214
215 """
216 self.path = path or self.path
217 with open(self.path) as f:
218 self._prev_dict = json.load(f)
219
220 def changed(self, key):
221 """Return true if the value for this key has changed since
222 the last save.
223
224 """
225 if self._prev_dict is None:
226 return True
227 return self.previous(key) != self.get(key)
228
229 def previous(self, key):
230 """Return previous value for this key, or None if there
231 is no "previous" value.
232
233 """
234 if self._prev_dict:
235 return self._prev_dict.get(key)
236 return None
237
238 def save(self):
239 """Save this config to disk.
240
241 Preserves items in _prev_dict that do not exist in self.
242
243 """
244 if self._prev_dict:
245 for k, v in self._prev_dict.iteritems():
246 if k not in self:
247 self[k] = v
248 with open(self.path, 'w') as f:
249 json.dump(self, f)
250
251
158@cached252@cached
159def config(scope=None):253def config(scope=None):
160 """Juju charm configuration"""254 """Juju charm configuration"""
@@ -163,7 +257,10 @@
163 config_cmd_line.append(scope)257 config_cmd_line.append(scope)
164 config_cmd_line.append('--format=json')258 config_cmd_line.append('--format=json')
165 try:259 try:
166 return json.loads(subprocess.check_output(config_cmd_line))260 config_data = json.loads(subprocess.check_output(config_cmd_line))
261 if scope is not None:
262 return config_data
263 return Config(config_data)
167 except ValueError:264 except ValueError:
168 return None265 return None
169266
@@ -348,18 +445,19 @@
348class Hooks(object):445class Hooks(object):
349 """A convenient handler for hook functions.446 """A convenient handler for hook functions.
350447
351 Example:448 Example::
449
352 hooks = Hooks()450 hooks = Hooks()
353451
354 # register a hook, taking its name from the function name452 # register a hook, taking its name from the function name
355 @hooks.hook()453 @hooks.hook()
356 def install():454 def install():
357 ...455 pass # your code here
358456
359 # register a hook, providing a custom hook name457 # register a hook, providing a custom hook name
360 @hooks.hook("config-changed")458 @hooks.hook("config-changed")
361 def config_changed():459 def config_changed():
362 ...460 pass # your code here
363461
364 if __name__ == "__main__":462 if __name__ == "__main__":
365 # execute a hook based on the name the program is called by463 # execute a hook based on the name the program is called by
366464
=== modified file 'hooks/charmhelpers/core/host.py'
--- hooks/charmhelpers/core/host.py 2014-04-11 20:55:42 +0000
+++ hooks/charmhelpers/core/host.py 2014-07-29 16:34:12 +0000
@@ -16,6 +16,7 @@
16from collections import OrderedDict16from collections import OrderedDict
1717
18from hookenv import log18from hookenv import log
19from fstab import Fstab
1920
2021
21def service_start(service_name):22def service_start(service_name):
@@ -34,7 +35,8 @@
3435
3536
36def service_reload(service_name, restart_on_failure=False):37def service_reload(service_name, restart_on_failure=False):
37 """Reload a system service, optionally falling back to restart if reload fails"""38 """Reload a system service, optionally falling back to restart if
39 reload fails"""
38 service_result = service('reload', service_name)40 service_result = service('reload', service_name)
39 if not service_result and restart_on_failure:41 if not service_result and restart_on_failure:
40 service_result = service('restart', service_name)42 service_result = service('restart', service_name)
@@ -143,7 +145,19 @@
143 target.write(content)145 target.write(content)
144146
145147
146def mount(device, mountpoint, options=None, persist=False):148def fstab_remove(mp):
149 """Remove the given mountpoint entry from /etc/fstab
150 """
151 return Fstab.remove_by_mountpoint(mp)
152
153
154def fstab_add(dev, mp, fs, options=None):
155 """Adds the given device entry to the /etc/fstab file
156 """
157 return Fstab.add(dev, mp, fs, options=options)
158
159
160def mount(device, mountpoint, options=None, persist=False, filesystem="ext3"):
147 """Mount a filesystem at a particular mountpoint"""161 """Mount a filesystem at a particular mountpoint"""
148 cmd_args = ['mount']162 cmd_args = ['mount']
149 if options is not None:163 if options is not None:
@@ -154,9 +168,9 @@
154 except subprocess.CalledProcessError, e:168 except subprocess.CalledProcessError, e:
155 log('Error mounting {} at {}\n{}'.format(device, mountpoint, e.output))169 log('Error mounting {} at {}\n{}'.format(device, mountpoint, e.output))
156 return False170 return False
171
157 if persist:172 if persist:
158 # TODO: update fstab173 return fstab_add(device, mountpoint, filesystem, options=options)
159 pass
160 return True174 return True
161175
162176
@@ -168,9 +182,9 @@
168 except subprocess.CalledProcessError, e:182 except subprocess.CalledProcessError, e:
169 log('Error unmounting {}\n{}'.format(mountpoint, e.output))183 log('Error unmounting {}\n{}'.format(mountpoint, e.output))
170 return False184 return False
185
171 if persist:186 if persist:
172 # TODO: update fstab187 return fstab_remove(mountpoint)
173 pass
174 return True188 return True
175189
176190
@@ -197,13 +211,13 @@
197def restart_on_change(restart_map, stopstart=False):211def restart_on_change(restart_map, stopstart=False):
198 """Restart services based on configuration files changing212 """Restart services based on configuration files changing
199213
200 This function is used a decorator, for example214 This function is used a decorator, for example::
201215
202 @restart_on_change({216 @restart_on_change({
203 '/etc/ceph/ceph.conf': [ 'cinder-api', 'cinder-volume' ]217 '/etc/ceph/ceph.conf': [ 'cinder-api', 'cinder-volume' ]
204 })218 })
205 def ceph_client_changed():219 def ceph_client_changed():
206 ...220 pass # your code here
207221
208 In this example, the cinder-api and cinder-volume services222 In this example, the cinder-api and cinder-volume services
209 would be restarted if /etc/ceph/ceph.conf is changed by the223 would be restarted if /etc/ceph/ceph.conf is changed by the
@@ -295,3 +309,19 @@
295 if 'link/ether' in words:309 if 'link/ether' in words:
296 hwaddr = words[words.index('link/ether') + 1]310 hwaddr = words[words.index('link/ether') + 1]
297 return hwaddr311 return hwaddr
312
313
314def cmp_pkgrevno(package, revno, pkgcache=None):
315 '''Compare supplied revno with the revno of the installed package
316
317 * 1 => Installed revno is greater than supplied arg
318 * 0 => Installed revno is the same as supplied arg
319 * -1 => Installed revno is less than supplied arg
320
321 '''
322 import apt_pkg
323 if not pkgcache:
324 apt_pkg.init()
325 pkgcache = apt_pkg.Cache()
326 pkg = pkgcache[package]
327 return apt_pkg.version_compare(pkg.current_ver.ver_str, revno)
298328
=== modified file 'hooks/charmhelpers/fetch/__init__.py'
--- hooks/charmhelpers/fetch/__init__.py 2014-04-11 20:55:42 +0000
+++ hooks/charmhelpers/fetch/__init__.py 2014-07-29 16:34:12 +0000
@@ -1,4 +1,5 @@
1import importlib1import importlib
2import time
2from yaml import safe_load3from yaml import safe_load
3from charmhelpers.core.host import (4from charmhelpers.core.host import (
4 lsb_release5 lsb_release
@@ -12,9 +13,9 @@
12 config,13 config,
13 log,14 log,
14)15)
15import apt_pkg
16import os16import os
1717
18
18CLOUD_ARCHIVE = """# Ubuntu Cloud Archive19CLOUD_ARCHIVE = """# Ubuntu Cloud Archive
19deb http://ubuntu-cloud.archive.canonical.com/ubuntu {} main20deb http://ubuntu-cloud.archive.canonical.com/ubuntu {} main
20"""21"""
@@ -54,12 +55,74 @@
54 'icehouse/proposed': 'precise-proposed/icehouse',55 'icehouse/proposed': 'precise-proposed/icehouse',
55 'precise-icehouse/proposed': 'precise-proposed/icehouse',56 'precise-icehouse/proposed': 'precise-proposed/icehouse',
56 'precise-proposed/icehouse': 'precise-proposed/icehouse',57 'precise-proposed/icehouse': 'precise-proposed/icehouse',
58 # Juno
59 'juno': 'trusty-updates/juno',
60 'trusty-juno': 'trusty-updates/juno',
61 'trusty-juno/updates': 'trusty-updates/juno',
62 'trusty-updates/juno': 'trusty-updates/juno',
63 'juno/proposed': 'trusty-proposed/juno',
64 'juno/proposed': 'trusty-proposed/juno',
65 'trusty-juno/proposed': 'trusty-proposed/juno',
66 'trusty-proposed/juno': 'trusty-proposed/juno',
57}67}
5868
69# The order of this list is very important. Handlers should be listed in from
70# least- to most-specific URL matching.
71FETCH_HANDLERS = (
72 'charmhelpers.fetch.archiveurl.ArchiveUrlFetchHandler',
73 'charmhelpers.fetch.bzrurl.BzrUrlFetchHandler',
74)
75
76APT_NO_LOCK = 100 # The return code for "couldn't acquire lock" in APT.
77APT_NO_LOCK_RETRY_DELAY = 10 # Wait 10 seconds between apt lock checks.
78APT_NO_LOCK_RETRY_COUNT = 30 # Retry to acquire the lock X times.
79
80
81class SourceConfigError(Exception):
82 pass
83
84
85class UnhandledSource(Exception):
86 pass
87
88
89class AptLockError(Exception):
90 pass
91
92
93class BaseFetchHandler(object):
94
95 """Base class for FetchHandler implementations in fetch plugins"""
96
97 def can_handle(self, source):
98 """Returns True if the source can be handled. Otherwise returns
99 a string explaining why it cannot"""
100 return "Wrong source type"
101
102 def install(self, source):
103 """Try to download and unpack the source. Return the path to the
104 unpacked files or raise UnhandledSource."""
105 raise UnhandledSource("Wrong source type {}".format(source))
106
107 def parse_url(self, url):
108 return urlparse(url)
109
110 def base_url(self, url):
111 """Return url without querystring or fragment"""
112 parts = list(self.parse_url(url))
113 parts[4:] = ['' for i in parts[4:]]
114 return urlunparse(parts)
115
59116
60def filter_installed_packages(packages):117def filter_installed_packages(packages):
61 """Returns a list of packages that require installation"""118 """Returns a list of packages that require installation"""
119 import apt_pkg
62 apt_pkg.init()120 apt_pkg.init()
121
122 # Tell apt to build an in-memory cache to prevent race conditions (if
123 # another process is already building the cache).
124 apt_pkg.config.set("Dir::Cache::pkgcache", "")
125
63 cache = apt_pkg.Cache()126 cache = apt_pkg.Cache()
64 _pkgs = []127 _pkgs = []
65 for package in packages:128 for package in packages:
@@ -87,14 +150,7 @@
87 cmd.extend(packages)150 cmd.extend(packages)
88 log("Installing {} with options: {}".format(packages,151 log("Installing {} with options: {}".format(packages,
89 options))152 options))
90 env = os.environ.copy()153 _run_apt_command(cmd, fatal)
91 if 'DEBIAN_FRONTEND' not in env:
92 env['DEBIAN_FRONTEND'] = 'noninteractive'
93
94 if fatal:
95 subprocess.check_call(cmd, env=env)
96 else:
97 subprocess.call(cmd, env=env)
98154
99155
100def apt_upgrade(options=None, fatal=False, dist=False):156def apt_upgrade(options=None, fatal=False, dist=False):
@@ -109,24 +165,13 @@
109 else:165 else:
110 cmd.append('upgrade')166 cmd.append('upgrade')
111 log("Upgrading with options: {}".format(options))167 log("Upgrading with options: {}".format(options))
112168 _run_apt_command(cmd, fatal)
113 env = os.environ.copy()
114 if 'DEBIAN_FRONTEND' not in env:
115 env['DEBIAN_FRONTEND'] = 'noninteractive'
116
117 if fatal:
118 subprocess.check_call(cmd, env=env)
119 else:
120 subprocess.call(cmd, env=env)
121169
122170
123def apt_update(fatal=False):171def apt_update(fatal=False):
124 """Update local apt cache"""172 """Update local apt cache"""
125 cmd = ['apt-get', 'update']173 cmd = ['apt-get', 'update']
126 if fatal:174 _run_apt_command(cmd, fatal)
127 subprocess.check_call(cmd)
128 else:
129 subprocess.call(cmd)
130175
131176
132def apt_purge(packages, fatal=False):177def apt_purge(packages, fatal=False):
@@ -137,10 +182,7 @@
137 else:182 else:
138 cmd.extend(packages)183 cmd.extend(packages)
139 log("Purging {}".format(packages))184 log("Purging {}".format(packages))
140 if fatal:185 _run_apt_command(cmd, fatal)
141 subprocess.check_call(cmd)
142 else:
143 subprocess.call(cmd)
144186
145187
146def apt_hold(packages, fatal=False):188def apt_hold(packages, fatal=False):
@@ -151,6 +193,7 @@
151 else:193 else:
152 cmd.extend(packages)194 cmd.extend(packages)
153 log("Holding {}".format(packages))195 log("Holding {}".format(packages))
196
154 if fatal:197 if fatal:
155 subprocess.check_call(cmd)198 subprocess.check_call(cmd)
156 else:199 else:
@@ -184,57 +227,50 @@
184 apt.write(PROPOSED_POCKET.format(release))227 apt.write(PROPOSED_POCKET.format(release))
185 if key:228 if key:
186 subprocess.check_call(['apt-key', 'adv', '--keyserver',229 subprocess.check_call(['apt-key', 'adv', '--keyserver',
187 'keyserver.ubuntu.com', '--recv',230 'hkp://keyserver.ubuntu.com:80', '--recv',
188 key])231 key])
189232
190233
191class SourceConfigError(Exception):
192 pass
193
194
195def configure_sources(update=False,234def configure_sources(update=False,
196 sources_var='install_sources',235 sources_var='install_sources',
197 keys_var='install_keys'):236 keys_var='install_keys'):
198 """237 """
199 Configure multiple sources from charm configuration238 Configure multiple sources from charm configuration.
239
240 The lists are encoded as yaml fragments in the configuration.
241 The frament needs to be included as a string.
200242
201 Example config:243 Example config:
202 install_sources:244 install_sources: |
203 - "ppa:foo"245 - "ppa:foo"
204 - "http://example.com/repo precise main"246 - "http://example.com/repo precise main"
205 install_keys:247 install_keys: |
206 - null248 - null
207 - "a1b2c3d4"249 - "a1b2c3d4"
208250
209 Note that 'null' (a.k.a. None) should not be quoted.251 Note that 'null' (a.k.a. None) should not be quoted.
210 """252 """
211 sources = safe_load(config(sources_var))253 sources = safe_load((config(sources_var) or '').strip()) or []
212 keys = config(keys_var)254 keys = safe_load((config(keys_var) or '').strip()) or None
213 if keys is not None:255
214 keys = safe_load(keys)256 if isinstance(sources, basestring):
215 if isinstance(sources, basestring) and (257 sources = [sources]
216 keys is None or isinstance(keys, basestring)):258
217 add_source(sources, keys)259 if keys is None:
260 for source in sources:
261 add_source(source, None)
218 else:262 else:
219 if not len(sources) == len(keys):263 if isinstance(keys, basestring):
220 msg = 'Install sources and keys lists are different lengths'264 keys = [keys]
221 raise SourceConfigError(msg)265
222 for src_num in range(len(sources)):266 if len(sources) != len(keys):
223 add_source(sources[src_num], keys[src_num])267 raise SourceConfigError(
268 'Install sources and keys lists are different lengths')
269 for source, key in zip(sources, keys):
270 add_source(source, key)
224 if update:271 if update:
225 apt_update(fatal=True)272 apt_update(fatal=True)
226273
227# The order of this list is very important. Handlers should be listed in from
228# least- to most-specific URL matching.
229FETCH_HANDLERS = (
230 'charmhelpers.fetch.archiveurl.ArchiveUrlFetchHandler',
231 'charmhelpers.fetch.bzrurl.BzrUrlFetchHandler',
232)
233
234
235class UnhandledSource(Exception):
236 pass
237
238274
239def install_remote(source):275def install_remote(source):
240 """276 """
@@ -265,30 +301,6 @@
265 return install_remote(source)301 return install_remote(source)
266302
267303
268class BaseFetchHandler(object):
269
270 """Base class for FetchHandler implementations in fetch plugins"""
271
272 def can_handle(self, source):
273 """Returns True if the source can be handled. Otherwise returns
274 a string explaining why it cannot"""
275 return "Wrong source type"
276
277 def install(self, source):
278 """Try to download and unpack the source. Return the path to the
279 unpacked files or raise UnhandledSource."""
280 raise UnhandledSource("Wrong source type {}".format(source))
281
282 def parse_url(self, url):
283 return urlparse(url)
284
285 def base_url(self, url):
286 """Return url without querystring or fragment"""
287 parts = list(self.parse_url(url))
288 parts[4:] = ['' for i in parts[4:]]
289 return urlunparse(parts)
290
291
292def plugins(fetch_handlers=None):304def plugins(fetch_handlers=None):
293 if not fetch_handlers:305 if not fetch_handlers:
294 fetch_handlers = FETCH_HANDLERS306 fetch_handlers = FETCH_HANDLERS
@@ -306,3 +318,40 @@
306 log("FetchHandler {} not found, skipping plugin".format(318 log("FetchHandler {} not found, skipping plugin".format(
307 handler_name))319 handler_name))
308 return plugin_list320 return plugin_list
321
322
323def _run_apt_command(cmd, fatal=False):
324 """
325 Run an APT command, checking output and retrying if the fatal flag is set
326 to True.
327
328 :param: cmd: str: The apt command to run.
329 :param: fatal: bool: Whether the command's output should be checked and
330 retried.
331 """
332 env = os.environ.copy()
333
334 if 'DEBIAN_FRONTEND' not in env:
335 env['DEBIAN_FRONTEND'] = 'noninteractive'
336
337 if fatal:
338 retry_count = 0
339 result = None
340
341 # If the command is considered "fatal", we need to retry if the apt
342 # lock was not acquired.
343
344 while result is None or result == APT_NO_LOCK:
345 try:
346 result = subprocess.check_call(cmd, env=env)
347 except subprocess.CalledProcessError, e:
348 retry_count = retry_count + 1
349 if retry_count > APT_NO_LOCK_RETRY_COUNT:
350 raise
351 result = e.returncode
352 log("Couldn't acquire DPKG lock. Will retry in {} seconds."
353 "".format(APT_NO_LOCK_RETRY_DELAY))
354 time.sleep(APT_NO_LOCK_RETRY_DELAY)
355
356 else:
357 subprocess.call(cmd, env=env)
309358
=== modified file 'hooks/charmhelpers/fetch/bzrurl.py'
--- hooks/charmhelpers/fetch/bzrurl.py 2014-04-11 20:55:42 +0000
+++ hooks/charmhelpers/fetch/bzrurl.py 2014-07-29 16:34:12 +0000
@@ -39,7 +39,8 @@
39 def install(self, source):39 def install(self, source):
40 url_parts = self.parse_url(source)40 url_parts = self.parse_url(source)
41 branch_name = url_parts.path.strip("/").split("/")[-1]41 branch_name = url_parts.path.strip("/").split("/")[-1]
42 dest_dir = os.path.join(os.environ.get('CHARM_DIR'), "fetched", branch_name)42 dest_dir = os.path.join(os.environ.get('CHARM_DIR'), "fetched",
43 branch_name)
43 if not os.path.exists(dest_dir):44 if not os.path.exists(dest_dir):
44 mkdir(dest_dir, perms=0755)45 mkdir(dest_dir, perms=0755)
45 try:46 try:
4647
=== modified file 'hooks/hooks.py'
--- hooks/hooks.py 2014-07-29 10:22:55 +0000
+++ hooks/hooks.py 2014-07-29 16:34:12 +0000
@@ -6,7 +6,6 @@
6'''6'''
77
8import commands8import commands
9import json
10import os9import os
11import re10import re
12import signal11import signal
@@ -15,7 +14,6 @@
15import sys14import sys
16import time15import time
17import yaml16import yaml
18import argparse
1917
20from os import chmod18from os import chmod
21from os import remove19from os import remove
@@ -29,10 +27,26 @@
29 apt_update,27 apt_update,
30 apt_install28 apt_install
31)29)
30
32from charmhelpers.core.hookenv import (31from charmhelpers.core.hookenv import (
33 config32 config,
34)33 unit_get,
3534 relation_get,
35 relation_set,
36 relations_of_type,
37 relation_id,
38 open_port,
39 close_port,
40 Hooks,
41)
42
43from charmhelpers.core.hookenv import log as juju_log
44
45from charmhelpers.core.host import (
46 service,
47)
48
49hooks = Hooks()
3650
37###############################################################################51###############################################################################
38# Global variables52# Global variables
@@ -40,8 +54,8 @@
40default_mongodb_config = "/etc/mongodb.conf"54default_mongodb_config = "/etc/mongodb.conf"
41default_mongodb_init_config = "/etc/init/mongodb.conf"55default_mongodb_init_config = "/etc/init/mongodb.conf"
42default_mongos_list = "/etc/mongos.list"56default_mongos_list = "/etc/mongos.list"
43default_wait_for = 2057default_wait_for = 10
44default_max_tries = 2058default_max_tries = 5
4559
46###############################################################################60###############################################################################
47# Supporting functions61# Supporting functions
@@ -494,7 +508,7 @@
494 config.append("")508 config.append("")
495509
496 # arbiter510 # arbiter
497 if config_data['arbiter'] != "disabled" and\511 if config_data['arbiter'] != "disabled" and \
498 config_data['arbiter'] != "enabled":512 config_data['arbiter'] != "enabled":
499 config.append("arbiter = %s" % config_data['arbiter'])513 config.append("arbiter = %s" % config_data['arbiter'])
500 config.append("")514 config.append("")
@@ -657,7 +671,7 @@
657671
658672
659def configsvr_status(wait_for=default_wait_for, max_tries=default_max_tries):673def configsvr_status(wait_for=default_wait_for, max_tries=default_max_tries):
660 config_data = config_get()674 config_data = config()
661 current_try = 0675 current_try = 0
662 while (process_check_pidfile('/var/run/mongodb/configsvr.pid') !=676 while (process_check_pidfile('/var/run/mongodb/configsvr.pid') !=
663 (None, None)) and not port_check(677 (None, None)) and not port_check(
@@ -685,7 +699,7 @@
685 juju_log("disable_configsvr: port not defined.")699 juju_log("disable_configsvr: port not defined.")
686 return(False)700 return(False)
687 try:701 try:
688 config_server_port = config_get('config_server_port')702 config_server_port = config('config_server_port')
689 pid = open('/var/run/mongodb/configsvr.pid').read()703 pid = open('/var/run/mongodb/configsvr.pid').read()
690 os.kill(int(pid), signal.SIGTERM)704 os.kill(int(pid), signal.SIGTERM)
691 os.unlink('/var/run/mongodb/configsvr.pid')705 os.unlink('/var/run/mongodb/configsvr.pid')
@@ -747,7 +761,7 @@
747761
748762
749def mongos_status(wait_for=default_wait_for, max_tries=default_max_tries):763def mongos_status(wait_for=default_wait_for, max_tries=default_max_tries):
750 config_data = config_get()764 config_data = config()
751 current_try = 0765 current_try = 0
752 while (process_check_pidfile('/var/run/mongodb/mongos.pid') !=766 while (process_check_pidfile('/var/run/mongodb/mongos.pid') !=
753 (None, None)) and not port_check(767 (None, None)) and not port_check(
@@ -839,17 +853,17 @@
839853
840def restart_mongod(wait_for=default_wait_for, max_tries=default_max_tries):854def restart_mongod(wait_for=default_wait_for, max_tries=default_max_tries):
841 my_hostname = unit_get('public-address')855 my_hostname = unit_get('public-address')
842 my_port = config_get('port')856 my_port = config('port')
843 current_try = 0857 current_try = 0
844858
845 service('mongodb', 'stop')859 service('stop', 'mongodb')
846 if os.path.exists('/var/lib/mongodb/mongod.lock'):860 if os.path.exists('/var/lib/mongodb/mongod.lock'):
847 os.remove('/var/lib/mongodb/mongod.lock')861 os.remove('/var/lib/mongodb/mongod.lock')
848862
849 if not service('mongodb', 'start'):863 if not service('start', 'mongodb'):
850 return False864 return False
851865
852 while (service('mongodb', 'status') and866 while (service('status', 'mongodb') and
853 not port_check(my_hostname, my_port) and867 not port_check(my_hostname, my_port) and
854 current_try < max_tries):868 current_try < max_tries):
855 juju_log(869 juju_log(
@@ -859,14 +873,14 @@
859 current_try += 1873 current_try += 1
860874
861 return(875 return(
862 (service('mongodb', 'status') == port_check(my_hostname, my_port))876 (service('status', 'mongodb') == port_check(my_hostname, my_port))
863 is True)877 is True)
864878
865879
866def backup_cronjob(disable=False):880def backup_cronjob(disable=False):
867 """Generate the cronjob to backup with mongodbump."""881 """Generate the cronjob to backup with mongodbump."""
868 juju_log('Setting up cronjob')882 juju_log('Setting up cronjob')
869 config_data = config_get()883 config_data = config()
870 backupdir = config_data['backup_directory']884 backupdir = config_data['backup_directory']
871 bind_ip = config_data['bind_ip']885 bind_ip = config_data['bind_ip']
872 cron_file = '/etc/cron.d/mongodb'886 cron_file = '/etc/cron.d/mongodb'
@@ -915,18 +929,19 @@
915###############################################################################929###############################################################################
916# Hook functions930# Hook functions
917###############################################################################931###############################################################################
932@hooks.hook('install')
918def install_hook():933def install_hook():
919 juju_log("Installing mongodb")934 juju_log("Installing mongodb")
920 add_source(config('source'), config('key'))935 add_source(config('source'), config('key'))
921 apt_update(fatal=True)936 apt_update(fatal=True)
922 apt_install(packages=['mongodb', 'python-yaml'], fatal=True)937 apt_install(packages=['mongodb', 'python-yaml'], fatal=True)
923 return True938
924939
925940@hooks.hook('config-changed')
926def config_changed():941def config_changed():
927 juju_log("Entering config_changed")942 juju_log("Entering config_changed")
928 print "Entering config_changed"943 print "Entering config_changed"
929 config_data = config_get()944 config_data = config()
930 print "config_data: ", config_data945 print "config_data: ", config_data
931 mongodb_config = open(default_mongodb_config).read()946 mongodb_config = open(default_mongodb_config).read()
932947
@@ -1048,7 +1063,7 @@
1048 juju_log("config_changed: Exceptions: %s" % str(e))1063 juju_log("config_changed: Exceptions: %s" % str(e))
10491064
1050 if mongos_pid is not None:1065 if mongos_pid is not None:
1051 mongos_port = re.search('--port (\w+)', mongos_cmd_line).group(2)1066 mongos_port = re.search('--port (\w+)', mongos_cmd_line).group(1)
1052 disable_mongos(mongos_port)1067 disable_mongos(mongos_port)
1053 enable_mongos(config_data['mongos_port'])1068 enable_mongos(config_data['mongos_port'])
1054 else:1069 else:
@@ -1058,6 +1073,7 @@
1058 return(True)1073 return(True)
10591074
10601075
1076@hooks.hook('start')
1061def start_hook():1077def start_hook():
1062 juju_log("start_hook")1078 juju_log("start_hook")
1063 retVal = restart_mongod()1079 retVal = restart_mongod()
@@ -1065,10 +1081,11 @@
1065 return(retVal)1081 return(retVal)
10661082
10671083
1084@hooks.hook('stop')
1068def stop_hook():1085def stop_hook():
1069 juju_log("stop_hook")1086 juju_log("stop_hook")
1070 try:1087 try:
1071 retVal = service('mongodb', 'stop')1088 retVal = service('stop', 'mongodb')
1072 os.remove('/var/lib/mongodb/mongod.lock')1089 os.remove('/var/lib/mongodb/mongod.lock')
1073 #FIXME Need to check if this is still needed1090 #FIXME Need to check if this is still needed
1074 except Exception, e:1091 except Exception, e:
@@ -1079,15 +1096,16 @@
1079 return(retVal)1096 return(retVal)
10801097
10811098
1099@hooks.hook('database-relation-joined')
1082def database_relation_joined():1100def database_relation_joined():
1083 juju_log("database_relation_joined")1101 juju_log("database_relation_joined")
1084 my_hostname = unit_get('public-address')1102 my_hostname = unit_get('public-address')
1085 my_port = config_get('port')1103 my_port = config('port')
1086 my_replset = config_get('replicaset')1104 my_replset = config('replicaset')
1087 juju_log("my_hostname: %s" % my_hostname)1105 juju_log("my_hostname: %s" % my_hostname)
1088 juju_log("my_port: %s" % my_port)1106 juju_log("my_port: %s" % my_port)
1089 juju_log("my_replset: %s" % my_replset)1107 juju_log("my_replset: %s" % my_replset)
1090 return(relation_set(1108 return(relation_set(relation_id(),
1091 {1109 {
1092 'hostname': my_hostname,1110 'hostname': my_hostname,
1093 'port': my_port,1111 'port': my_port,
@@ -1096,34 +1114,36 @@
1096 }))1114 }))
10971115
10981116
1117@hooks.hook('replicaset-relation-joined')
1099def replica_set_relation_joined():1118def replica_set_relation_joined():
1100 juju_log("replica_set_relation_joined")1119 juju_log("replica_set_relation_joined")
1101 my_hostname = unit_get('public-address')1120 my_hostname = unit_get('public-address')
1102 my_port = config_get('port')1121 my_port = config('port')
1103 my_replset = config_get('replicaset')1122 my_replset = config('replicaset')
1104 my_install_order = os.environ['JUJU_UNIT_NAME'].split('/')[1]1123 my_install_order = os.environ['JUJU_UNIT_NAME'].split('/')[1]
1105 juju_log("my_hostname: %s" % my_hostname)1124 juju_log("my_hostname: %s" % my_hostname)
1106 juju_log("my_port: %s" % my_port)1125 juju_log("my_port: %s" % my_port)
1107 juju_log("my_replset: %s" % my_replset)1126 juju_log("my_replset: %s" % my_replset)
1108 juju_log("my_install_order: %s" % my_install_order)1127 juju_log("my_install_order: %s" % my_install_order)
1109 return(enable_replset(my_replset) ==1128 enable_replset(my_replset)
1110 restart_mongod() ==1129 restart_mongod()
1111 relation_set(1130
1112 {1131 relation_set(relation_id(), {
1113 'hostname': my_hostname,1132 'hostname': my_hostname,
1114 'port': my_port,1133 'port': my_port,
1115 'replset': my_replset,1134 'replset': my_replset,
1116 'install-order': my_install_order,1135 'install-order': my_install_order,
1117 'type': 'replset',1136 'type': 'replset',
1118 }))1137 })
11191138
11201139
1140@hooks.hook('replicaset-relation-changed')
1121def replica_set_relation_changed():1141def replica_set_relation_changed():
1122 juju_log("replica_set_relation_changed")1142 juju_log("replica_set_relation_changed")
1123 my_hostname = unit_get('public-address')1143 my_hostname = unit_get('public-address')
1124 my_port = config_get('port')1144 my_port = config('port')
1125 my_install_order = os.environ['JUJU_UNIT_NAME'].split('/')[1]1145 my_install_order = os.environ['JUJU_UNIT_NAME'].split('/')[1]
1126 my_replicaset_master = config_get('replicaset_master')1146 my_replicaset_master = config('replicaset_master')
11271147
1128 # If we are joining an existing replicaset cluster, just join and leave.1148 # If we are joining an existing replicaset cluster, just join and leave.
1129 if my_replicaset_master != "auto":1149 if my_replicaset_master != "auto":
@@ -1135,44 +1155,46 @@
1135 master_install_order = my_install_order1155 master_install_order = my_install_order
11361156
1137 # Check the nodes in the relation to find the master1157 # Check the nodes in the relation to find the master
1138 for member in relation_list():1158 for member in relations_of_type('replica-set'):
1159 member = member['__unit__']
1139 juju_log("replica_set_relation_changed: member: %s" % member)1160 juju_log("replica_set_relation_changed: member: %s" % member)
1140 hostname = relation_get('hostname', member)1161 hostname = relation_get('hostname', member)
1141 port = relation_get('port', member)1162 port = relation_get('port', member)
1142 install_order = relation_get('install-order', member)1163 inst_ordr = relation_get('install-order', member)
1143 juju_log("replica_set_relation_changed: install_order: %s" % install_order)1164 juju_log("replica_set_relation_changed: install_order: %s" % inst_ordr)
1144 if install_order is None:1165 if inst_ordr is None:
1145 juju_log("replica_set_relation_changed: install_order is None. relation is not ready")1166 juju_log("replica_set_relation_changed: install_order is None."
1167 " relation is not ready")
1146 break1168 break
1147 if int(install_order) < int(master_install_order):1169 if int(inst_ordr) < int(master_install_order):
1148 master_hostname = hostname1170 master_hostname = hostname
1149 master_port = port1171 master_port = port
1150 master_install_order = install_order1172 master_install_order = inst_ordr
11511173
1152 # Initiate the replset1174 # Initiate the replset
1153 init_replset("%s:%s" % (master_hostname, master_port))1175 init_replset("%s:%s" % (master_hostname, master_port))
11541176
1155 # Add the rest of the nodes to the replset1177 # Add the rest of the nodes to the replset
1156 for member in relation_list():1178 for member in relations_of_type('replica-set'):
1157 hostname = relation_get('hostname', member)1179 hostname = relation_get('hostname', member['__unit__'])
1158 port = relation_get('port', member)1180 port = relation_get('port', member['__unit__'])
1159 if master_hostname != hostname:1181 if master_hostname != hostname:
1160 if hostname == my_hostname:1182 if hostname == my_hostname:
1161 subprocess.call(['mongo',1183 subprocess.call(['mongo', '--eval',
1162 '--eval',1184 "rs.add(\"%s\")" % hostname])
1163 "rs.add(\"%s\")" % hostname])
1164 else:1185 else:
1165 join_replset("%s:%s" % (master_hostname, master_port),1186 join_replset("%s:%s" % (master_hostname, master_port),
1166 "%s:%s" % (hostname, port))1187 "%s:%s" % (hostname, port))
11671188
1168 # Add this node to the replset ( if needed )1189 # Add this node to the replset ( if needed )
1169 if master_hostname != my_hostname:1190 if master_hostname != my_hostname:
1170 join_replset("%s:%s" % (master_hostname, master_port),1191 join_replset("%s:%s" % (master_hostname, master_port),
1171 "%s:%s" % (my_hostname, my_port))1192 "%s:%s" % (my_hostname, my_port))
11721193
1173 return(True)1194
11741195
11751196
1197@hooks.hook('data-relation-joined')
1176def data_relation_joined():1198def data_relation_joined():
1177 juju_log("data_relation_joined")1199 juju_log("data_relation_joined")
11781200
@@ -1182,6 +1204,7 @@
1182 }))1204 }))
11831205
11841206
1207@hooks.hook('data-relation-changed')
1185def data_relation_changed():1208def data_relation_changed():
1186 juju_log("data_relation_changed")1209 juju_log("data_relation_changed")
11871210
@@ -1192,57 +1215,60 @@
1192 return(config_changed())1215 return(config_changed())
11931216
11941217
1218@hooks.hook('data-relation-departed')
1195def data_relation_departed():1219def data_relation_departed():
1196 juju_log("data_relation_departed")1220 juju_log("data_relation_departed")
1197 return(config_changed())1221 return(config_changed())
11981222
11991223@hooks.hook('configsvr-relation-joined')
1200def configsvr_relation_joined():1224def configsvr_relation_joined():
1201 juju_log("configsvr_relation_joined")1225 juju_log("configsvr_relation_joined")
1202 my_hostname = unit_get('public-address')1226 my_hostname = unit_get('public-address')
1203 my_port = config_get('config_server_port')1227 my_port = config('config_server_port')
1204 my_install_order = os.environ['JUJU_UNIT_NAME'].split('/')[1]1228 my_install_order = os.environ['JUJU_UNIT_NAME'].split('/')[1]
1205 return(relation_set(1229 return(relation_set(relation_id(),
1206 {1230 {
1207 'hostname': my_hostname,1231 'hostname': my_hostname,
1208 'port': my_port,1232 'port': my_port,
1209 'install-order': my_install_order,1233 'install-order': my_install_order,
1210 'type': 'configsvr',1234 'type': 'configsvr',
1211 }))1235 }))
12121236
12131237
1238@hooks.hook('configsvr-relation-changed')
1214def configsvr_relation_changed():1239def configsvr_relation_changed():
1215 juju_log("configsvr_relation_changed")1240 juju_log("configsvr_relation_changed")
1216 config_data = config_get()1241 config_data = config()
1217 my_port = config_data['config_server_port']1242 my_port = config_data['config_server_port']
1218 disable_configsvr(my_port)1243 disable_configsvr(my_port)
1219 retVal = enable_configsvr(config_data)1244
1220 juju_log("configsvr_relation_changed returns: %s" % retVal)1245
1221 return(retVal)1246@hooks.hook('mongos-cfg-relation-joined')
12221247@hooks.hook('mongos-relation-joined')
1223
1224def mongos_relation_joined():1248def mongos_relation_joined():
1225 juju_log("mongos_relation_joined")1249 juju_log("mongos_relation_joined")
1226 my_hostname = unit_get('public-address')1250 my_hostname = unit_get('public-address')
1227 my_port = config_get('mongos_port')1251 my_port = config('mongos_port')
1228 my_install_order = os.environ['JUJU_UNIT_NAME'].split('/')[1]1252 my_install_order = os.environ['JUJU_UNIT_NAME'].split('/')[1]
1229 return(relation_set(1253 relation_set(relation_id(),
1230 {1254 {
1231 'hostname': my_hostname,1255 'hostname': my_hostname,
1232 'port': my_port,1256 'port': my_port,
1233 'install-order': my_install_order,1257 'install-order': my_install_order,
1234 'type': 'mongos'1258 'type': 'mongos'
1235 }))1259 })
12361260
12371261
1262@hooks.hook('mongos-cfg-relation-changed')
1263@hooks.hook('mongos-relation-changed')
1238def mongos_relation_changed():1264def mongos_relation_changed():
1239 juju_log("mongos_relation_changed")1265 juju_log("mongos_relation_changed")
1240 config_data = config_get()1266 config_data = config()
1241 retVal = False1267 retVal = False
1242 for member in relation_list():1268 for member in relations_of_type('mongos-cfg'):
1243 hostname = relation_get('hostname', member)1269 hostname = relation_get('hostname', member['__unit__'])
1244 port = relation_get('port', member)1270 port = relation_get('port', member['__unit__'])
1245 rel_type = relation_get('type', member)1271 rel_type = relation_get('type', member['__unit__'])
1246 if hostname is None or port is None or rel_type is None:1272 if hostname is None or port is None or rel_type is None:
1247 juju_log("mongos_relation_changed: relation data not ready.")1273 juju_log("mongos_relation_changed: relation data not ready.")
1248 break1274 break
@@ -1264,34 +1290,33 @@
1264 if mongos_ready():1290 if mongos_ready():
1265 mongos_host = "%s:%s" % (1291 mongos_host = "%s:%s" % (
1266 unit_get('public-address'),1292 unit_get('public-address'),
1267 config_get('mongos_port'))1293 config('mongos_port'))
1268 shard_command1 = "sh.addShard(\"%s:%s\")" % (hostname, port)1294 shard_command1 = "sh.addShard(\"%s:%s\")" % (hostname, port)
1269 retVal1 = mongo_client(mongos_host, shard_command1)1295 mongo_client(mongos_host, shard_command1)
1270 replicaset = relation_get('replset', member)1296 replicaset = relation_get('replset', member)
1271 shard_command2 = "sh.addShard(\"%s/%s:%s\")" % \1297 shard_command2 = "sh.addShard(\"%s/%s:%s\")" % \
1272 (replicaset, hostname, port)1298 (replicaset, hostname, port)
1273 retVal2 = mongo_client(mongos_host, shard_command2)1299 mongo_client(mongos_host, shard_command2)
1274 retVal = retVal1 is True and retVal2 is True1300
1275 else:1301
1276 juju_log("Not enough config server for mongos yet.")
1277 retVal = True
1278 else:1302 else:
1279 juju_log("mongos_relation_change: undefined rel_type: %s" %1303 juju_log("mongos_relation_change: undefined rel_type: %s" %
1280 rel_type)1304 rel_type)
1281 return(False)1305 return(False)
1282 juju_log("mongos_relation_changed returns: %s" % retVal)1306 juju_log("mongos_relation_changed returns: %s" % retVal)
1283 return(retVal)1307
12841308
12851309
1310@hooks.hook('mongos-relation-broken')
1286def mongos_relation_broken():1311def mongos_relation_broken():
1287# config_servers = load_config_servers(default_mongos_list)1312 config_servers = load_config_servers(default_mongos_list)
1288# for member in relation_list():1313 for member in relations_of_type('mongos'):
1289# hostname = relation_get('hostname', member)1314 hostname = relation_get('hostname', member)
1290# port = relation_get('port', member)1315 port = relation_get('port', member)
1291# if '%s:%s' % (hostname, port) in config_servers:1316 if '%s:%s' % (hostname, port) in config_servers:
1292# config_servers.remove('%s:%s' % (hostname, port))1317 config_servers.remove('%s:%s' % (hostname, port))
1293# return(update_file(default_mongos_list, '\n'.join(config_servers)))1318
1294 return(True)1319 update_file(default_mongos_list, '\n'.join(config_servers))
12951320
12961321
1297def run(command, exit_on_error=True):1322def run(command, exit_on_error=True):
@@ -1318,7 +1343,7 @@
1318#1343#
1319#------------------------------1344#------------------------------
1320def volume_get_volid_from_volume_map():1345def volume_get_volid_from_volume_map():
1321 config_data = config_get()1346 config_data = config()
1322 volume_map = {}1347 volume_map = {}
1323 try:1348 try:
1324 volume_map = yaml.load(config_data['volume-map'].strip())1349 volume_map = yaml.load(config_data['volume-map'].strip())
@@ -1379,19 +1404,21 @@
1379# None config state is invalid - we should not serve1404# None config state is invalid - we should not serve
1380def volume_get_volume_id():1405def volume_get_volume_id():
13811406
1407 config_data = config()
1408
1409
13821410
1383 volid = volume_get_id_for_storage_subordinate()1411 volid = volume_get_id_for_storage_subordinate()
1384 if volid:1412 if volid:
1385 return volid1413 return volid
13861414
1387 config_data = config_get()
1388 ephemeral_storage = config_data['volume-ephemeral-storage']1415 ephemeral_storage = config_data['volume-ephemeral-storage']
1389 volid = volume_get_volid_from_volume_map()1416 volid = volume_get_volid_from_volume_map()
1390 juju_unit_name = os.environ['JUJU_UNIT_NAME']1417 juju_unit_name = os.environ['JUJU_UNIT_NAME']
1391 if ephemeral_storage in [True, 'yes', 'Yes', 'true', 'True']:1418 if ephemeral_storage in [True, 'yes', 'Yes', 'true', 'True']:
1392 if volid:1419 if volid:
1393 juju_log(1420 juju_log(
1394 "volume-ephemeral-storage is True, but " +1421 "volume-ephemeral-storage is True, but
1395 "volume-map[{!r}] -> {}".format(juju_unit_name, volid))1422 "volume-map[{!r}] -> {}".format(juju_unit_name, volid))
1396 return None1423 return None
1397 else:1424 else:
@@ -1424,6 +1451,7 @@
1424 return None1451 return None
1425 return output1452 return output
14261453
1454
1427#------------------------------------------------------------------------------1455#------------------------------------------------------------------------------
1428# Core logic for permanent storage changes:1456# Core logic for permanent storage changes:
1429# NOTE the only 2 "True" return points:1457# NOTE the only 2 "True" return points:
@@ -1435,7 +1463,7 @@
1435# - manipulate /var/lib/mongodb/VERSION/CLUSTER symlink1463# - manipulate /var/lib/mongodb/VERSION/CLUSTER symlink
1436#------------------------------------------------------------------------------1464#------------------------------------------------------------------------------
1437def config_changed_volume_apply():1465def config_changed_volume_apply():
1438 config_data = config_get()1466 config_data = config()
1439 data_directory_path = config_data["dbpath"]1467 data_directory_path = config_data["dbpath"]
1440 assert(data_directory_path)1468 assert(data_directory_path)
1441 volid = volume_get_volume_id()1469 volid = volume_get_volume_id()
@@ -1548,57 +1576,6 @@
1548###############################################################################1576###############################################################################
1549# Main section1577# Main section
1550###############################################################################1578###############################################################################
1551if __name__ == '__main__':1579if __name__ == "__main__":
1552 parser = argparse.ArgumentParser()1580 # execute a hook based on the name the program is called by
1553 parser.add_argument('-H', '--hook_name', dest='hook_name',1581 hooks.execute(sys.argv)
1554 help='hook to call')
1555 args = parser.parse_args()
1556 if args.hook_name is not None:
1557 hook_name = args.hook_name
1558 else:
1559 hook_name = os.path.basename(sys.argv[0])
1560
1561 if hook_name == "install":
1562 retVal = install_hook()
1563 elif hook_name == "config-changed":
1564 retVal = config_changed()
1565 elif hook_name == "start":
1566 retVal = start_hook()
1567 elif hook_name == "stop":
1568 retVal = stop_hook()
1569 elif hook_name == "database-relation-joined":
1570 retVal = database_relation_joined()
1571 elif hook_name == "replica-set-relation-joined":
1572 retVal = replica_set_relation_joined()
1573 elif hook_name == "replica-set-relation-changed":
1574 retVal = replica_set_relation_changed()
1575 elif hook_name == "configsvr-relation-joined":
1576 retVal = configsvr_relation_joined()
1577 elif hook_name == "configsvr-relation-changed":
1578 retVal = configsvr_relation_changed()
1579 elif hook_name == "mongos-cfg-relation-joined":
1580 retVal = mongos_relation_joined()
1581 elif hook_name == "mongos-cfg-relation-changed":
1582 retVal = mongos_relation_changed()
1583 elif hook_name == "mongos-cfg-relation-broken":
1584 retVal = mongos_relation_broken()
1585 elif hook_name == "mongos-relation-joined":
1586 retVal = mongos_relation_joined()
1587 elif hook_name == "mongos-relation-changed":
1588 retVal = mongos_relation_changed()
1589 elif hook_name == "mongos-relation-broken":
1590 retVal = mongos_relation_broken()
1591 elif hook_name == "data-relation-joined":
1592 retVal = data_relation_joined()
1593 elif hook_name == "data-relation-changed":
1594 retVal = data_relation_changed()
1595 elif hook_name == "data-relation-departed":
1596 retVal = data_relation_departed()
1597 else:
1598 print "Unknown hook"
1599 retVal = False
1600
1601 if retVal is True:
1602 sys.exit(0)
1603 else:
1604 sys.exit(1)
1605\ No newline at end of file1582\ No newline at end of file
16061583
=== modified file 'hooks/install'
--- hooks/install 2013-11-25 19:48:00 +0000
+++ hooks/install 1970-01-01 00:00:00 +0000
@@ -1,5 +0,0 @@
1#!/bin/bash
2
3sudo apt-get install "python-yaml"
4
5hooks/hooks.py -H install
60
=== target is u'hooks.py'
=== modified file 'metadata.yaml'
--- metadata.yaml 2014-06-18 11:13:54 +0000
+++ metadata.yaml 2014-07-29 16:34:12 +0000
@@ -1,6 +1,9 @@
1name: mongodb1name: mongodb
2maintainer: Juan Negron <juan.negron@canonical.com>2summary: An open-source document database, and the leading NoSQL database
3summary: MongoDB (from humongous) is an open-source document database3maintainers:
4 - Juan Negron <juan.negron@canonical.com>
5 - Marco Ceppi <marco@ceppi.net>
6 - Charles Butler <chuck@dasroot.net>
4description: |7description: |
5 MongoDB is a high-performance, open source, schema-free document-8 MongoDB is a high-performance, open source, schema-free document-
6 oriented data store that's easy to deploy, manage and use. It's9 oriented data store that's easy to deploy, manage and use. It's
710
=== added file 'tests/200_relate_ceilometer.test'
--- tests/200_relate_ceilometer.test 1970-01-01 00:00:00 +0000
+++ tests/200_relate_ceilometer.test 2014-07-29 16:34:12 +0000
@@ -0,0 +1,43 @@
1#!/usr/bin/env python3
2
3import amulet
4import pdb
5
6class TestDeploy(object):
7
8 def __init__(self, time=2500):
9 # Attempt to load the deployment topology from a bundle.
10 self.deploy = amulet.Deployment(series="trusty")
11
12 # If something errored out, attempt to continue by
13 # manually specifying a standalone deployment
14 self.deploy.add('mongodb')
15 self.deploy.add('ceilometer', 'cs:trusty/ceilometer')
16 # send blank configs to finalize the objects in the deployment map
17 self.deploy.configure('mongodb', {})
18 self.deploy.configure('ceilometer', {})
19
20 self.deploy.relate('mongodb:database', 'ceilometer:shared-db')
21
22 try:
23 self.deploy.setup(time)
24 self.deploy.sentry.wait(time)
25 except:
26 amulet.raise_status(amulet.FAIL, msg="Environment standup timeout")
27 # sentry = self.deploy.sentry
28
29 def run(self):
30 for test in dir(self):
31 if test.startswith('test_'):
32 getattr(self, test)()
33
34 def test_mongo_relation(self):
35 unit = self.deploy.sentry.unit['ceilometer/0']
36 mongo = self.deploy.sentry.unit['mongodb/0'].info['public-address']
37 cont = unit.file_contents('/etc/ceilometer/ceilometer.conf')
38 if mongo not in cont:
39 amulet.raise_status(amulet.FAIL, "Unable to verify ceilometer cfg")
40
41if __name__ == '__main__':
42 runner = TestDeploy()
43 runner.run()

Subscribers

People subscribed via source and target branches