Merge lp:~jacekn/charms/precise/swift-storage/n-e-m-with-concat into lp:~openstack-charmers-archive/charms/trusty/swift-storage/next
- Precise Pangolin (12.04)
- n-e-m-with-concat
- Merge into next
Status: | Superseded |
---|---|
Proposed branch: | lp:~jacekn/charms/precise/swift-storage/n-e-m-with-concat |
Merge into: | lp:~openstack-charmers-archive/charms/trusty/swift-storage/next |
Diff against target: |
848 lines (+634/-33) 13 files modified
charm-helpers.yaml (+1/-0) config.yaml (+14/-1) hooks/charmhelpers/contrib/charmsupport/nrpe.py (+219/-0) hooks/charmhelpers/contrib/charmsupport/volumes.py (+156/-0) hooks/swift_storage_hooks.py (+44/-1) hooks/swift_storage_utils.py (+18/-2) metadata.yaml (+3/-0) revision (+1/-1) scripts/check_swift_storage.py (+136/-0) templates/050-swift-storage (+24/-0) templates/rsyncd.conf (+5/-23) unit_tests/test_swift_storage_relations.py (+10/-3) unit_tests/test_swift_storage_utils.py (+3/-2) |
To merge this branch: | bzr merge lp:~jacekn/charms/precise/swift-storage/n-e-m-with-concat |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
James Page | Needs Information | ||
Review via email: mp+221692@code.launchpad.net |
This proposal supersedes a proposal from 2014-05-16.
This proposal has been superseded by a proposal from 2014-07-31.
Commit message
Description of the change
This change adds nrpe-external-
Jacek Nykis (jacekn) wrote : | # |
> This merge proposal appears to have more than just the nrpe support - lots of
> changes around how rsync is managed as well?
>
> Was this intentional? if so I would prefer that they where split out into two
> MP's to make it easier to test/review.
Hi James,
Yes it was intentional. The swift-storage charm assumed full control over rsync config which could lead to broken configuration when used with subordinate charms.
So the rsync management changes are prerequisite for n-e-m support because n-e-m needs to be able to add rsync stanzas to the config without destroying swift config (and the swift charm needs to be able to update its config without breaking n-e-m config)
Unmerged revisions
- 31. By Jacek Nykis
-
Fixed tests
- 30. By Jacek Nykis
-
Added rsync fragment concatenation to the config-changed hook
- 29. By Ryan Finnie
-
Enable /etc/rsyncd.d functionality for compatibility with basenode
- 28. By Jacek Nykis
-
Fixed bug in check_swift_
storage. py - 27. By Jacek Nykis
-
Added nrpe-external-
master hook support
Preview Diff
1 | === modified file 'charm-helpers.yaml' | |||
2 | --- charm-helpers.yaml 2014-03-25 17:05:07 +0000 | |||
3 | +++ charm-helpers.yaml 2014-06-02 09:35:40 +0000 | |||
4 | @@ -9,3 +9,4 @@ | |||
5 | 9 | - apache | 9 | - apache |
6 | 10 | - cluster | 10 | - cluster |
7 | 11 | - payload.execd | 11 | - payload.execd |
8 | 12 | - contrib.charmsupport | ||
9 | 12 | 13 | ||
10 | === modified file 'config.yaml' | |||
11 | --- config.yaml 2012-12-19 23:09:13 +0000 | |||
12 | +++ config.yaml 2014-06-02 09:35:40 +0000 | |||
13 | @@ -49,4 +49,17 @@ | |||
14 | 49 | default: 6002 | 49 | default: 6002 |
15 | 50 | type: int | 50 | type: int |
16 | 51 | description: Listening port of the swift-account-server. | 51 | description: Listening port of the swift-account-server. |
18 | 52 | 52 | nagios-check-params: | |
19 | 53 | default: "-m -r 60 180 10 20" | ||
20 | 54 | type: string | ||
21 | 55 | description: String appended to nagios check | ||
22 | 56 | nagios_context: | ||
23 | 57 | default: "juju" | ||
24 | 58 | type: string | ||
25 | 59 | description: | | ||
26 | 60 | Used by the nrpe-external-master subordinate charm. | ||
27 | 61 | A string that will be prepended to instance name to set the host name | ||
28 | 62 | in nagios. So for instance the hostname would be something like: | ||
29 | 63 | juju-myservice-0 | ||
30 | 64 | If you're running multiple environments with the same services in them | ||
31 | 65 | this allows you to differentiate between them. | ||
32 | 53 | 66 | ||
33 | === added directory 'hooks/charmhelpers/contrib/charmsupport' | |||
34 | === added file 'hooks/charmhelpers/contrib/charmsupport/__init__.py' | |||
35 | === added file 'hooks/charmhelpers/contrib/charmsupport/nrpe.py' | |||
36 | --- hooks/charmhelpers/contrib/charmsupport/nrpe.py 1970-01-01 00:00:00 +0000 | |||
37 | +++ hooks/charmhelpers/contrib/charmsupport/nrpe.py 2014-06-02 09:35:40 +0000 | |||
38 | @@ -0,0 +1,219 @@ | |||
39 | 1 | """Compatibility with the nrpe-external-master charm""" | ||
40 | 2 | # Copyright 2012 Canonical Ltd. | ||
41 | 3 | # | ||
42 | 4 | # Authors: | ||
43 | 5 | # Matthew Wedgwood <matthew.wedgwood@canonical.com> | ||
44 | 6 | |||
45 | 7 | import subprocess | ||
46 | 8 | import pwd | ||
47 | 9 | import grp | ||
48 | 10 | import os | ||
49 | 11 | import re | ||
50 | 12 | import shlex | ||
51 | 13 | import yaml | ||
52 | 14 | |||
53 | 15 | from charmhelpers.core.hookenv import ( | ||
54 | 16 | config, | ||
55 | 17 | local_unit, | ||
56 | 18 | log, | ||
57 | 19 | relation_ids, | ||
58 | 20 | relation_set, | ||
59 | 21 | ) | ||
60 | 22 | |||
61 | 23 | from charmhelpers.core.host import service | ||
62 | 24 | |||
63 | 25 | # This module adds compatibility with the nrpe-external-master and plain nrpe | ||
64 | 26 | # subordinate charms. To use it in your charm: | ||
65 | 27 | # | ||
66 | 28 | # 1. Update metadata.yaml | ||
67 | 29 | # | ||
68 | 30 | # provides: | ||
69 | 31 | # (...) | ||
70 | 32 | # nrpe-external-master: | ||
71 | 33 | # interface: nrpe-external-master | ||
72 | 34 | # scope: container | ||
73 | 35 | # | ||
74 | 36 | # and/or | ||
75 | 37 | # | ||
76 | 38 | # provides: | ||
77 | 39 | # (...) | ||
78 | 40 | # local-monitors: | ||
79 | 41 | # interface: local-monitors | ||
80 | 42 | # scope: container | ||
81 | 43 | |||
82 | 44 | # | ||
83 | 45 | # 2. Add the following to config.yaml | ||
84 | 46 | # | ||
85 | 47 | # nagios_context: | ||
86 | 48 | # default: "juju" | ||
87 | 49 | # type: string | ||
88 | 50 | # description: | | ||
89 | 51 | # Used by the nrpe subordinate charms. | ||
90 | 52 | # A string that will be prepended to instance name to set the host name | ||
91 | 53 | # in nagios. So for instance the hostname would be something like: | ||
92 | 54 | # juju-myservice-0 | ||
93 | 55 | # If you're running multiple environments with the same services in them | ||
94 | 56 | # this allows you to differentiate between them. | ||
95 | 57 | # | ||
96 | 58 | # 3. Add custom checks (Nagios plugins) to files/nrpe-external-master | ||
97 | 59 | # | ||
98 | 60 | # 4. Update your hooks.py with something like this: | ||
99 | 61 | # | ||
100 | 62 | # from charmsupport.nrpe import NRPE | ||
101 | 63 | # (...) | ||
102 | 64 | # def update_nrpe_config(): | ||
103 | 65 | # nrpe_compat = NRPE() | ||
104 | 66 | # nrpe_compat.add_check( | ||
105 | 67 | # shortname = "myservice", | ||
106 | 68 | # description = "Check MyService", | ||
107 | 69 | # check_cmd = "check_http -w 2 -c 10 http://localhost" | ||
108 | 70 | # ) | ||
109 | 71 | # nrpe_compat.add_check( | ||
110 | 72 | # "myservice_other", | ||
111 | 73 | # "Check for widget failures", | ||
112 | 74 | # check_cmd = "/srv/myapp/scripts/widget_check" | ||
113 | 75 | # ) | ||
114 | 76 | # nrpe_compat.write() | ||
115 | 77 | # | ||
116 | 78 | # def config_changed(): | ||
117 | 79 | # (...) | ||
118 | 80 | # update_nrpe_config() | ||
119 | 81 | # | ||
120 | 82 | # def nrpe_external_master_relation_changed(): | ||
121 | 83 | # update_nrpe_config() | ||
122 | 84 | # | ||
123 | 85 | # def local_monitors_relation_changed(): | ||
124 | 86 | # update_nrpe_config() | ||
125 | 87 | # | ||
126 | 88 | # 5. ln -s hooks.py nrpe-external-master-relation-changed | ||
127 | 89 | # ln -s hooks.py local-monitors-relation-changed | ||
128 | 90 | |||
129 | 91 | |||
130 | 92 | class CheckException(Exception): | ||
131 | 93 | pass | ||
132 | 94 | |||
133 | 95 | |||
134 | 96 | class Check(object): | ||
135 | 97 | shortname_re = '[A-Za-z0-9-_]+$' | ||
136 | 98 | service_template = (""" | ||
137 | 99 | #--------------------------------------------------- | ||
138 | 100 | # This file is Juju managed | ||
139 | 101 | #--------------------------------------------------- | ||
140 | 102 | define service {{ | ||
141 | 103 | use active-service | ||
142 | 104 | host_name {nagios_hostname} | ||
143 | 105 | service_description {nagios_hostname}[{shortname}] """ | ||
144 | 106 | """{description} | ||
145 | 107 | check_command check_nrpe!{command} | ||
146 | 108 | servicegroups {nagios_servicegroup} | ||
147 | 109 | }} | ||
148 | 110 | """) | ||
149 | 111 | |||
150 | 112 | def __init__(self, shortname, description, check_cmd): | ||
151 | 113 | super(Check, self).__init__() | ||
152 | 114 | # XXX: could be better to calculate this from the service name | ||
153 | 115 | if not re.match(self.shortname_re, shortname): | ||
154 | 116 | raise CheckException("shortname must match {}".format( | ||
155 | 117 | Check.shortname_re)) | ||
156 | 118 | self.shortname = shortname | ||
157 | 119 | self.command = "check_{}".format(shortname) | ||
158 | 120 | # Note: a set of invalid characters is defined by the | ||
159 | 121 | # Nagios server config | ||
160 | 122 | # The default is: illegal_object_name_chars=`~!$%^&*"|'<>?,()= | ||
161 | 123 | self.description = description | ||
162 | 124 | self.check_cmd = self._locate_cmd(check_cmd) | ||
163 | 125 | |||
164 | 126 | def _locate_cmd(self, check_cmd): | ||
165 | 127 | search_path = ( | ||
166 | 128 | '/usr/lib/nagios/plugins', | ||
167 | 129 | '/usr/local/lib/nagios/plugins', | ||
168 | 130 | ) | ||
169 | 131 | parts = shlex.split(check_cmd) | ||
170 | 132 | for path in search_path: | ||
171 | 133 | if os.path.exists(os.path.join(path, parts[0])): | ||
172 | 134 | command = os.path.join(path, parts[0]) | ||
173 | 135 | if len(parts) > 1: | ||
174 | 136 | command += " " + " ".join(parts[1:]) | ||
175 | 137 | return command | ||
176 | 138 | log('Check command not found: {}'.format(parts[0])) | ||
177 | 139 | return '' | ||
178 | 140 | |||
179 | 141 | def write(self, nagios_context, hostname): | ||
180 | 142 | nrpe_check_file = '/etc/nagios/nrpe.d/{}.cfg'.format( | ||
181 | 143 | self.command) | ||
182 | 144 | with open(nrpe_check_file, 'w') as nrpe_check_config: | ||
183 | 145 | nrpe_check_config.write("# check {}\n".format(self.shortname)) | ||
184 | 146 | nrpe_check_config.write("command[{}]={}\n".format( | ||
185 | 147 | self.command, self.check_cmd)) | ||
186 | 148 | |||
187 | 149 | if not os.path.exists(NRPE.nagios_exportdir): | ||
188 | 150 | log('Not writing service config as {} is not accessible'.format( | ||
189 | 151 | NRPE.nagios_exportdir)) | ||
190 | 152 | else: | ||
191 | 153 | self.write_service_config(nagios_context, hostname) | ||
192 | 154 | |||
193 | 155 | def write_service_config(self, nagios_context, hostname): | ||
194 | 156 | for f in os.listdir(NRPE.nagios_exportdir): | ||
195 | 157 | if re.search('.*{}.cfg'.format(self.command), f): | ||
196 | 158 | os.remove(os.path.join(NRPE.nagios_exportdir, f)) | ||
197 | 159 | |||
198 | 160 | templ_vars = { | ||
199 | 161 | 'nagios_hostname': hostname, | ||
200 | 162 | 'nagios_servicegroup': nagios_context, | ||
201 | 163 | 'description': self.description, | ||
202 | 164 | 'shortname': self.shortname, | ||
203 | 165 | 'command': self.command, | ||
204 | 166 | } | ||
205 | 167 | nrpe_service_text = Check.service_template.format(**templ_vars) | ||
206 | 168 | nrpe_service_file = '{}/service__{}_{}.cfg'.format( | ||
207 | 169 | NRPE.nagios_exportdir, hostname, self.command) | ||
208 | 170 | with open(nrpe_service_file, 'w') as nrpe_service_config: | ||
209 | 171 | nrpe_service_config.write(str(nrpe_service_text)) | ||
210 | 172 | |||
211 | 173 | def run(self): | ||
212 | 174 | subprocess.call(self.check_cmd) | ||
213 | 175 | |||
214 | 176 | |||
215 | 177 | class NRPE(object): | ||
216 | 178 | nagios_logdir = '/var/log/nagios' | ||
217 | 179 | nagios_exportdir = '/var/lib/nagios/export' | ||
218 | 180 | nrpe_confdir = '/etc/nagios/nrpe.d' | ||
219 | 181 | |||
220 | 182 | def __init__(self, hostname=None): | ||
221 | 183 | super(NRPE, self).__init__() | ||
222 | 184 | self.config = config() | ||
223 | 185 | self.nagios_context = self.config['nagios_context'] | ||
224 | 186 | self.unit_name = local_unit().replace('/', '-') | ||
225 | 187 | if hostname: | ||
226 | 188 | self.hostname = hostname | ||
227 | 189 | else: | ||
228 | 190 | self.hostname = "{}-{}".format(self.nagios_context, self.unit_name) | ||
229 | 191 | self.checks = [] | ||
230 | 192 | |||
231 | 193 | def add_check(self, *args, **kwargs): | ||
232 | 194 | self.checks.append(Check(*args, **kwargs)) | ||
233 | 195 | |||
234 | 196 | def write(self): | ||
235 | 197 | try: | ||
236 | 198 | nagios_uid = pwd.getpwnam('nagios').pw_uid | ||
237 | 199 | nagios_gid = grp.getgrnam('nagios').gr_gid | ||
238 | 200 | except: | ||
239 | 201 | log("Nagios user not set up, nrpe checks not updated") | ||
240 | 202 | return | ||
241 | 203 | |||
242 | 204 | if not os.path.exists(NRPE.nagios_logdir): | ||
243 | 205 | os.mkdir(NRPE.nagios_logdir) | ||
244 | 206 | os.chown(NRPE.nagios_logdir, nagios_uid, nagios_gid) | ||
245 | 207 | |||
246 | 208 | nrpe_monitors = {} | ||
247 | 209 | monitors = {"monitors": {"remote": {"nrpe": nrpe_monitors}}} | ||
248 | 210 | for nrpecheck in self.checks: | ||
249 | 211 | nrpecheck.write(self.nagios_context, self.hostname) | ||
250 | 212 | nrpe_monitors[nrpecheck.shortname] = { | ||
251 | 213 | "command": nrpecheck.command, | ||
252 | 214 | } | ||
253 | 215 | |||
254 | 216 | service('restart', 'nagios-nrpe-server') | ||
255 | 217 | |||
256 | 218 | for rid in relation_ids("local-monitors"): | ||
257 | 219 | relation_set(relation_id=rid, monitors=yaml.dump(monitors)) | ||
258 | 0 | 220 | ||
259 | === added file 'hooks/charmhelpers/contrib/charmsupport/volumes.py' | |||
260 | --- hooks/charmhelpers/contrib/charmsupport/volumes.py 1970-01-01 00:00:00 +0000 | |||
261 | +++ hooks/charmhelpers/contrib/charmsupport/volumes.py 2014-06-02 09:35:40 +0000 | |||
262 | @@ -0,0 +1,156 @@ | |||
263 | 1 | ''' | ||
264 | 2 | Functions for managing volumes in juju units. One volume is supported per unit. | ||
265 | 3 | Subordinates may have their own storage, provided it is on its own partition. | ||
266 | 4 | |||
267 | 5 | Configuration stanzas: | ||
268 | 6 | volume-ephemeral: | ||
269 | 7 | type: boolean | ||
270 | 8 | default: true | ||
271 | 9 | description: > | ||
272 | 10 | If false, a volume is mounted as sepecified in "volume-map" | ||
273 | 11 | If true, ephemeral storage will be used, meaning that log data | ||
274 | 12 | will only exist as long as the machine. YOU HAVE BEEN WARNED. | ||
275 | 13 | volume-map: | ||
276 | 14 | type: string | ||
277 | 15 | default: {} | ||
278 | 16 | description: > | ||
279 | 17 | YAML map of units to device names, e.g: | ||
280 | 18 | "{ rsyslog/0: /dev/vdb, rsyslog/1: /dev/vdb }" | ||
281 | 19 | Service units will raise a configure-error if volume-ephemeral | ||
282 | 20 | is 'true' and no volume-map value is set. Use 'juju set' to set a | ||
283 | 21 | value and 'juju resolved' to complete configuration. | ||
284 | 22 | |||
285 | 23 | Usage: | ||
286 | 24 | from charmsupport.volumes import configure_volume, VolumeConfigurationError | ||
287 | 25 | from charmsupport.hookenv import log, ERROR | ||
288 | 26 | def post_mount_hook(): | ||
289 | 27 | stop_service('myservice') | ||
290 | 28 | def post_mount_hook(): | ||
291 | 29 | start_service('myservice') | ||
292 | 30 | |||
293 | 31 | if __name__ == '__main__': | ||
294 | 32 | try: | ||
295 | 33 | configure_volume(before_change=pre_mount_hook, | ||
296 | 34 | after_change=post_mount_hook) | ||
297 | 35 | except VolumeConfigurationError: | ||
298 | 36 | log('Storage could not be configured', ERROR) | ||
299 | 37 | ''' | ||
300 | 38 | |||
301 | 39 | # XXX: Known limitations | ||
302 | 40 | # - fstab is neither consulted nor updated | ||
303 | 41 | |||
304 | 42 | import os | ||
305 | 43 | from charmhelpers.core import hookenv | ||
306 | 44 | from charmhelpers.core import host | ||
307 | 45 | import yaml | ||
308 | 46 | |||
309 | 47 | |||
310 | 48 | MOUNT_BASE = '/srv/juju/volumes' | ||
311 | 49 | |||
312 | 50 | |||
313 | 51 | class VolumeConfigurationError(Exception): | ||
314 | 52 | '''Volume configuration data is missing or invalid''' | ||
315 | 53 | pass | ||
316 | 54 | |||
317 | 55 | |||
318 | 56 | def get_config(): | ||
319 | 57 | '''Gather and sanity-check volume configuration data''' | ||
320 | 58 | volume_config = {} | ||
321 | 59 | config = hookenv.config() | ||
322 | 60 | |||
323 | 61 | errors = False | ||
324 | 62 | |||
325 | 63 | if config.get('volume-ephemeral') in (True, 'True', 'true', 'Yes', 'yes'): | ||
326 | 64 | volume_config['ephemeral'] = True | ||
327 | 65 | else: | ||
328 | 66 | volume_config['ephemeral'] = False | ||
329 | 67 | |||
330 | 68 | try: | ||
331 | 69 | volume_map = yaml.safe_load(config.get('volume-map', '{}')) | ||
332 | 70 | except yaml.YAMLError as e: | ||
333 | 71 | hookenv.log("Error parsing YAML volume-map: {}".format(e), | ||
334 | 72 | hookenv.ERROR) | ||
335 | 73 | errors = True | ||
336 | 74 | if volume_map is None: | ||
337 | 75 | # probably an empty string | ||
338 | 76 | volume_map = {} | ||
339 | 77 | elif not isinstance(volume_map, dict): | ||
340 | 78 | hookenv.log("Volume-map should be a dictionary, not {}".format( | ||
341 | 79 | type(volume_map))) | ||
342 | 80 | errors = True | ||
343 | 81 | |||
344 | 82 | volume_config['device'] = volume_map.get(os.environ['JUJU_UNIT_NAME']) | ||
345 | 83 | if volume_config['device'] and volume_config['ephemeral']: | ||
346 | 84 | # asked for ephemeral storage but also defined a volume ID | ||
347 | 85 | hookenv.log('A volume is defined for this unit, but ephemeral ' | ||
348 | 86 | 'storage was requested', hookenv.ERROR) | ||
349 | 87 | errors = True | ||
350 | 88 | elif not volume_config['device'] and not volume_config['ephemeral']: | ||
351 | 89 | # asked for permanent storage but did not define volume ID | ||
352 | 90 | hookenv.log('Ephemeral storage was requested, but there is no volume ' | ||
353 | 91 | 'defined for this unit.', hookenv.ERROR) | ||
354 | 92 | errors = True | ||
355 | 93 | |||
356 | 94 | unit_mount_name = hookenv.local_unit().replace('/', '-') | ||
357 | 95 | volume_config['mountpoint'] = os.path.join(MOUNT_BASE, unit_mount_name) | ||
358 | 96 | |||
359 | 97 | if errors: | ||
360 | 98 | return None | ||
361 | 99 | return volume_config | ||
362 | 100 | |||
363 | 101 | |||
364 | 102 | def mount_volume(config): | ||
365 | 103 | if os.path.exists(config['mountpoint']): | ||
366 | 104 | if not os.path.isdir(config['mountpoint']): | ||
367 | 105 | hookenv.log('Not a directory: {}'.format(config['mountpoint'])) | ||
368 | 106 | raise VolumeConfigurationError() | ||
369 | 107 | else: | ||
370 | 108 | host.mkdir(config['mountpoint']) | ||
371 | 109 | if os.path.ismount(config['mountpoint']): | ||
372 | 110 | unmount_volume(config) | ||
373 | 111 | if not host.mount(config['device'], config['mountpoint'], persist=True): | ||
374 | 112 | raise VolumeConfigurationError() | ||
375 | 113 | |||
376 | 114 | |||
377 | 115 | def unmount_volume(config): | ||
378 | 116 | if os.path.ismount(config['mountpoint']): | ||
379 | 117 | if not host.umount(config['mountpoint'], persist=True): | ||
380 | 118 | raise VolumeConfigurationError() | ||
381 | 119 | |||
382 | 120 | |||
383 | 121 | def managed_mounts(): | ||
384 | 122 | '''List of all mounted managed volumes''' | ||
385 | 123 | return filter(lambda mount: mount[0].startswith(MOUNT_BASE), host.mounts()) | ||
386 | 124 | |||
387 | 125 | |||
388 | 126 | def configure_volume(before_change=lambda: None, after_change=lambda: None): | ||
389 | 127 | '''Set up storage (or don't) according to the charm's volume configuration. | ||
390 | 128 | Returns the mount point or "ephemeral". before_change and after_change | ||
391 | 129 | are optional functions to be called if the volume configuration changes. | ||
392 | 130 | ''' | ||
393 | 131 | |||
394 | 132 | config = get_config() | ||
395 | 133 | if not config: | ||
396 | 134 | hookenv.log('Failed to read volume configuration', hookenv.CRITICAL) | ||
397 | 135 | raise VolumeConfigurationError() | ||
398 | 136 | |||
399 | 137 | if config['ephemeral']: | ||
400 | 138 | if os.path.ismount(config['mountpoint']): | ||
401 | 139 | before_change() | ||
402 | 140 | unmount_volume(config) | ||
403 | 141 | after_change() | ||
404 | 142 | return 'ephemeral' | ||
405 | 143 | else: | ||
406 | 144 | # persistent storage | ||
407 | 145 | if os.path.ismount(config['mountpoint']): | ||
408 | 146 | mounts = dict(managed_mounts()) | ||
409 | 147 | if mounts.get(config['mountpoint']) != config['device']: | ||
410 | 148 | before_change() | ||
411 | 149 | unmount_volume(config) | ||
412 | 150 | mount_volume(config) | ||
413 | 151 | after_change() | ||
414 | 152 | else: | ||
415 | 153 | before_change() | ||
416 | 154 | mount_volume(config) | ||
417 | 155 | after_change() | ||
418 | 156 | return config['mountpoint'] | ||
419 | 0 | 157 | ||
420 | === added symlink 'hooks/nrpe-external-master-relation-changed' | |||
421 | === target is u'swift_storage_hooks.py' | |||
422 | === added symlink 'hooks/nrpe-external-master-relation-joined' | |||
423 | === target is u'swift_storage_hooks.py' | |||
424 | === modified file 'hooks/swift_storage_hooks.py' | |||
425 | --- hooks/swift_storage_hooks.py 2013-09-27 16:33:06 +0000 | |||
426 | +++ hooks/swift_storage_hooks.py 2014-06-02 09:35:40 +0000 | |||
427 | @@ -13,6 +13,7 @@ | |||
428 | 13 | register_configs, | 13 | register_configs, |
429 | 14 | save_script_rc, | 14 | save_script_rc, |
430 | 15 | setup_storage, | 15 | setup_storage, |
431 | 16 | concat_rsync_fragments, | ||
432 | 16 | ) | 17 | ) |
433 | 17 | 18 | ||
434 | 18 | from charmhelpers.core.hookenv import ( | 19 | from charmhelpers.core.hookenv import ( |
435 | @@ -21,10 +22,11 @@ | |||
436 | 21 | log, | 22 | log, |
437 | 22 | relation_get, | 23 | relation_get, |
438 | 23 | relation_set, | 24 | relation_set, |
439 | 25 | relations_of_type, | ||
440 | 24 | ) | 26 | ) |
441 | 25 | 27 | ||
442 | 26 | from charmhelpers.fetch import apt_install, apt_update | 28 | from charmhelpers.fetch import apt_install, apt_update |
444 | 27 | from charmhelpers.core.host import restart_on_change | 29 | from charmhelpers.core.host import restart_on_change, rsync |
445 | 28 | from charmhelpers.payload.execd import execd_preinstall | 30 | from charmhelpers.payload.execd import execd_preinstall |
446 | 29 | 31 | ||
447 | 30 | from charmhelpers.contrib.openstack.utils import ( | 32 | from charmhelpers.contrib.openstack.utils import ( |
448 | @@ -32,8 +34,11 @@ | |||
449 | 32 | openstack_upgrade_available, | 34 | openstack_upgrade_available, |
450 | 33 | ) | 35 | ) |
451 | 34 | 36 | ||
452 | 37 | from charmhelpers.contrib.charmsupport.nrpe import NRPE | ||
453 | 38 | |||
454 | 35 | hooks = Hooks() | 39 | hooks = Hooks() |
455 | 36 | CONFIGS = register_configs() | 40 | CONFIGS = register_configs() |
456 | 41 | NAGIOS_PLUGINS = '/usr/local/lib/nagios/plugins' | ||
457 | 37 | 42 | ||
458 | 38 | 43 | ||
459 | 39 | @hooks.hook() | 44 | @hooks.hook() |
460 | @@ -52,7 +57,22 @@ | |||
461 | 52 | if openstack_upgrade_available('swift'): | 57 | if openstack_upgrade_available('swift'): |
462 | 53 | do_openstack_upgrade(configs=CONFIGS) | 58 | do_openstack_upgrade(configs=CONFIGS) |
463 | 54 | CONFIGS.write_all() | 59 | CONFIGS.write_all() |
464 | 60 | |||
465 | 61 | # If basenode is not installed and managing rsyncd.conf, replicate | ||
466 | 62 | # its core functionality. Otherwise concat files | ||
467 | 63 | if not os.path.exists('/etc/rsyncd.d/001-basenode'): | ||
468 | 64 | with open('templates/rsyncd.conf') as _in: | ||
469 | 65 | rsync_header = _in.read() | ||
470 | 66 | with open('/etc/rsyncd.d/050-swift-storage') as _in: | ||
471 | 67 | rsync_fragment = _in.read() | ||
472 | 68 | with open('/etc/rsyncd.conf', 'w') as out: | ||
473 | 69 | out.write(rsync_header + rsync_fragment) | ||
474 | 70 | else: | ||
475 | 71 | concat_rsync_fragments() | ||
476 | 72 | |||
477 | 55 | save_script_rc() | 73 | save_script_rc() |
478 | 74 | if relations_of_type('nrpe-external-master'): | ||
479 | 75 | nrpe_relation() | ||
480 | 56 | 76 | ||
481 | 57 | 77 | ||
482 | 58 | @hooks.hook() | 78 | @hooks.hook() |
483 | @@ -80,6 +100,29 @@ | |||
484 | 80 | fetch_swift_rings(rings_url) | 100 | fetch_swift_rings(rings_url) |
485 | 81 | 101 | ||
486 | 82 | 102 | ||
487 | 103 | @hooks.hook('nrpe-external-master-relation-joined') | ||
488 | 104 | @hooks.hook('nrpe-external-master-relation-changed') | ||
489 | 105 | def nrpe_relation(): | ||
490 | 106 | log('Refreshing nrpe checks') | ||
491 | 107 | rsync(os.path.join(os.getenv('CHARM_DIR'), 'scripts', | ||
492 | 108 | 'check_swift_storage.py'), | ||
493 | 109 | os.path.join(NAGIOS_PLUGINS, 'check_swift_storage.py')) | ||
494 | 110 | # Find out if nrpe set nagios_hostname | ||
495 | 111 | hostname = None | ||
496 | 112 | for rel in relations_of_type('nrpe-external-master'): | ||
497 | 113 | if 'nagios_hostname' in rel: | ||
498 | 114 | hostname = rel['nagios_hostname'] | ||
499 | 115 | break | ||
500 | 116 | nrpe = NRPE(hostname=hostname) | ||
501 | 117 | nrpe.add_check( | ||
502 | 118 | shortname='swift_storage', | ||
503 | 119 | description='Check swift storage', | ||
504 | 120 | check_cmd='check_swift_storage.py {}'.format( | ||
505 | 121 | config('nagios-check-params')) | ||
506 | 122 | ) | ||
507 | 123 | nrpe.write() | ||
508 | 124 | |||
509 | 125 | |||
510 | 83 | def main(): | 126 | def main(): |
511 | 84 | try: | 127 | try: |
512 | 85 | hooks.execute(sys.argv) | 128 | hooks.execute(sys.argv) |
513 | 86 | 129 | ||
514 | === modified file 'hooks/swift_storage_utils.py' | |||
515 | --- hooks/swift_storage_utils.py 2014-04-07 14:50:34 +0000 | |||
516 | +++ hooks/swift_storage_utils.py 2014-06-02 09:35:40 +0000 | |||
517 | @@ -70,7 +70,7 @@ | |||
518 | 70 | ] | 70 | ] |
519 | 71 | 71 | ||
520 | 72 | RESTART_MAP = { | 72 | RESTART_MAP = { |
522 | 73 | '/etc/rsyncd.conf': ['rsync'], | 73 | '/etc/rsyncd.d/050-swift-storage': ['rsync'], |
523 | 74 | '/etc/swift/account-server.conf': ACCOUNT_SVCS, | 74 | '/etc/swift/account-server.conf': ACCOUNT_SVCS, |
524 | 75 | '/etc/swift/container-server.conf': CONTAINER_SVCS, | 75 | '/etc/swift/container-server.conf': CONTAINER_SVCS, |
525 | 76 | '/etc/swift/object-server.conf': OBJECT_SVCS, | 76 | '/etc/swift/object-server.conf': OBJECT_SVCS, |
526 | @@ -90,6 +90,11 @@ | |||
527 | 90 | ] | 90 | ] |
528 | 91 | [mkdir(d, owner='swift', group='swift') for d in dirs | 91 | [mkdir(d, owner='swift', group='swift') for d in dirs |
529 | 92 | if not os.path.isdir(d)] | 92 | if not os.path.isdir(d)] |
530 | 93 | root_dirs = [ | ||
531 | 94 | '/etc/rsyncd.d', | ||
532 | 95 | ] | ||
533 | 96 | [mkdir(d, owner='root', group='root') for d in root_dirs | ||
534 | 97 | if not os.path.isdir(d)] | ||
535 | 93 | 98 | ||
536 | 94 | 99 | ||
537 | 95 | def register_configs(): | 100 | def register_configs(): |
538 | @@ -98,7 +103,7 @@ | |||
539 | 98 | openstack_release=release) | 103 | openstack_release=release) |
540 | 99 | configs.register('/etc/swift/swift.conf', | 104 | configs.register('/etc/swift/swift.conf', |
541 | 100 | [SwiftStorageContext()]) | 105 | [SwiftStorageContext()]) |
543 | 101 | configs.register('/etc/rsyncd.conf', | 106 | configs.register('/etc/rsyncd.d/050-swift-storage', |
544 | 102 | [RsyncContext()]) | 107 | [RsyncContext()]) |
545 | 103 | for server in ['account', 'object', 'container']: | 108 | for server in ['account', 'object', 'container']: |
546 | 104 | configs.register('/etc/swift/%s-server.conf' % server, | 109 | configs.register('/etc/swift/%s-server.conf' % server, |
547 | @@ -209,3 +214,14 @@ | |||
548 | 209 | 'OPENSTACK_URL_%s' % svc: url, | 214 | 'OPENSTACK_URL_%s' % svc: url, |
549 | 210 | }) | 215 | }) |
550 | 211 | _save_script_rc(**env_vars) | 216 | _save_script_rc(**env_vars) |
551 | 217 | |||
552 | 218 | |||
553 | 219 | def concat_rsync_fragments(): | ||
554 | 220 | log('Concatenating rsyncd.d fragments') | ||
555 | 221 | rsyncd_dir = '/etc/rsyncd.d' | ||
556 | 222 | rsyncd_conf = "" | ||
557 | 223 | for filename in sorted(os.listdir(rsyncd_dir)): | ||
558 | 224 | with open(os.path.join(rsyncd_dir, filename), 'r') as fragment: | ||
559 | 225 | rsyncd_conf += fragment.read() | ||
560 | 226 | with open('/etc/rsyncd.conf', 'w') as f: | ||
561 | 227 | f.write(rsyncd_conf) | ||
562 | 212 | 228 | ||
563 | === modified file 'metadata.yaml' | |||
564 | --- metadata.yaml 2013-07-11 20:45:19 +0000 | |||
565 | +++ metadata.yaml 2014-06-02 09:35:40 +0000 | |||
566 | @@ -8,3 +8,6 @@ | |||
567 | 8 | provides: | 8 | provides: |
568 | 9 | swift-storage: | 9 | swift-storage: |
569 | 10 | interface: swift | 10 | interface: swift |
570 | 11 | nrpe-external-master: | ||
571 | 12 | interface: nrpe-external-master | ||
572 | 13 | scope: container | ||
573 | 11 | 14 | ||
574 | === modified file 'revision' | |||
575 | --- revision 2013-07-19 21:13:59 +0000 | |||
576 | +++ revision 2014-06-02 09:35:40 +0000 | |||
577 | @@ -1,1 +1,1 @@ | |||
579 | 1 | 90 | 1 | 100 |
580 | 2 | \ No newline at end of file | 2 | \ No newline at end of file |
581 | 3 | 3 | ||
582 | === added file 'scripts/check_swift_storage.py' | |||
583 | --- scripts/check_swift_storage.py 1970-01-01 00:00:00 +0000 | |||
584 | +++ scripts/check_swift_storage.py 2014-06-02 09:35:40 +0000 | |||
585 | @@ -0,0 +1,136 @@ | |||
586 | 1 | #!/usr/bin/env python | ||
587 | 2 | |||
588 | 3 | # Copyright (C) 2014 Canonical | ||
589 | 4 | # All Rights Reserved | ||
590 | 5 | # Author: Jacek Nykis | ||
591 | 6 | |||
592 | 7 | import sys | ||
593 | 8 | import json | ||
594 | 9 | import urllib2 | ||
595 | 10 | import argparse | ||
596 | 11 | import hashlib | ||
597 | 12 | import datetime | ||
598 | 13 | |||
599 | 14 | STATUS_OK = 0 | ||
600 | 15 | STATUS_WARN = 1 | ||
601 | 16 | STATUS_CRIT = 2 | ||
602 | 17 | STATUS_UNKNOWN = 3 | ||
603 | 18 | |||
604 | 19 | |||
605 | 20 | def generate_md5(filename): | ||
606 | 21 | with open(filename, 'rb') as f: | ||
607 | 22 | md5 = hashlib.md5() | ||
608 | 23 | buffer = f.read(2 ** 20) | ||
609 | 24 | while buffer: | ||
610 | 25 | md5.update(buffer) | ||
611 | 26 | buffer = f.read(2 ** 20) | ||
612 | 27 | return md5.hexdigest() | ||
613 | 28 | |||
614 | 29 | |||
615 | 30 | def check_md5(base_url): | ||
616 | 31 | url = base_url + "ringmd5" | ||
617 | 32 | ringfiles = ["/etc/swift/object.ring.gz", | ||
618 | 33 | "/etc/swift/account.ring.gz", | ||
619 | 34 | "/etc/swift/container.ring.gz"] | ||
620 | 35 | results = [] | ||
621 | 36 | try: | ||
622 | 37 | data = urllib2.urlopen(url).read() | ||
623 | 38 | j = json.loads(data) | ||
624 | 39 | except urllib2.URLError: | ||
625 | 40 | return [(STATUS_UNKNOWN, "Can't open url: {}".format(url))] | ||
626 | 41 | except ValueError: | ||
627 | 42 | return [(STATUS_UNKNOWN, "Can't parse status data")] | ||
628 | 43 | |||
629 | 44 | for ringfile in ringfiles: | ||
630 | 45 | try: | ||
631 | 46 | if generate_md5(ringfile) != j[ringfile]: | ||
632 | 47 | results.append((STATUS_CRIT, | ||
633 | 48 | "Ringfile {} MD5 sum mismatch".format(ringfile))) | ||
634 | 49 | except IOError: | ||
635 | 50 | results.append( | ||
636 | 51 | (STATUS_UNKNOWN, "Can't open ringfile {}".format(ringfile))) | ||
637 | 52 | if results: | ||
638 | 53 | return results | ||
639 | 54 | else: | ||
640 | 55 | return [(STATUS_OK, "OK")] | ||
641 | 56 | |||
642 | 57 | |||
643 | 58 | def check_replication(base_url, limits): | ||
644 | 59 | types = ["account", "object", "container"] | ||
645 | 60 | results = [] | ||
646 | 61 | for repl in types: | ||
647 | 62 | url = base_url + "replication/" + repl | ||
648 | 63 | try: | ||
649 | 64 | data = urllib2.urlopen(url).read() | ||
650 | 65 | j = json.loads(data) | ||
651 | 66 | except urllib2.URLError: | ||
652 | 67 | results.append((STATUS_UNKNOWN, "Can't open url: {}".format(url))) | ||
653 | 68 | continue | ||
654 | 69 | except ValueError: | ||
655 | 70 | results.append((STATUS_UNKNOWN, "Can't parse status data")) | ||
656 | 71 | continue | ||
657 | 72 | |||
658 | 73 | if "object_replication_last" in j: | ||
659 | 74 | repl_last = datetime.datetime.fromtimestamp(j["object_replication_last"]) | ||
660 | 75 | else: | ||
661 | 76 | repl_last = datetime.datetime.fromtimestamp(j["replication_last"]) | ||
662 | 77 | delta = datetime.datetime.now() - repl_last | ||
663 | 78 | if delta.seconds >= limits[1]: | ||
664 | 79 | results.append((STATUS_CRIT, | ||
665 | 80 | "'{}' replication lag is {} seconds".format(repl, delta.seconds))) | ||
666 | 81 | elif delta.seconds >= limits[0]: | ||
667 | 82 | results.append((STATUS_WARN, | ||
668 | 83 | "'{}' replication lag is {} seconds".format(repl, delta.seconds))) | ||
669 | 84 | if "replication_stats" in j: | ||
670 | 85 | errors = j["replication_stats"]["failure"] | ||
671 | 86 | if errors >= limits[3]: | ||
672 | 87 | results.append( | ||
673 | 88 | (STATUS_CRIT, "{} replication failures".format(errors))) | ||
674 | 89 | elif errors >= limits[2]: | ||
675 | 90 | results.append( | ||
676 | 91 | (STATUS_WARN, "{} replication failures".format(errors))) | ||
677 | 92 | if results: | ||
678 | 93 | return results | ||
679 | 94 | else: | ||
680 | 95 | return [(STATUS_OK, "OK")] | ||
681 | 96 | |||
682 | 97 | |||
683 | 98 | if __name__ == '__main__': | ||
684 | 99 | parser = argparse.ArgumentParser(description='Check swift-storage health') | ||
685 | 100 | parser.add_argument('-H', '--host', dest='host', default='localhost', | ||
686 | 101 | help='Hostname to query') | ||
687 | 102 | parser.add_argument('-p', '--port', dest='port', default='6000', | ||
688 | 103 | type=int, help='Port number') | ||
689 | 104 | parser.add_argument('-r', '--replication', dest='check_replication', | ||
690 | 105 | type=int, nargs=4, help='Check replication status', | ||
691 | 106 | metavar=('lag_warn', 'lag_crit', 'failures_warn', 'failures_crit')) | ||
692 | 107 | parser.add_argument('-m', '--md5', dest='check_md5', action='store_true', | ||
693 | 108 | help='Compare server rings md5sum with local copy') | ||
694 | 109 | args = parser.parse_args() | ||
695 | 110 | |||
696 | 111 | if not args.check_replication and not args.check_md5: | ||
697 | 112 | print "You must use -r or -m switch" | ||
698 | 113 | sys.exit(STATUS_UNKNOWN) | ||
699 | 114 | |||
700 | 115 | base_url = "http://{}:{}/recon/".format(args.host, args.port) | ||
701 | 116 | results = [] | ||
702 | 117 | if args.check_replication: | ||
703 | 118 | results.extend(check_replication(base_url, args.check_replication)) | ||
704 | 119 | if args.check_md5: | ||
705 | 120 | results.extend(check_md5(base_url)) | ||
706 | 121 | |||
707 | 122 | crits = ';'.join([i[1] for i in results if i[0] == STATUS_CRIT]) | ||
708 | 123 | warns = ';'.join([i[1] for i in results if i[0] == STATUS_WARN]) | ||
709 | 124 | unknowns = ';'.join([i[1] for i in results if i[0] == STATUS_UNKNOWN]) | ||
710 | 125 | if crits: | ||
711 | 126 | print "CRITICAL: " + crits | ||
712 | 127 | sys.exit(STATUS_CRIT) | ||
713 | 128 | elif warns: | ||
714 | 129 | print "WARNING: " + warns | ||
715 | 130 | sys.exit(STATUS_WARN) | ||
716 | 131 | elif unknowns: | ||
717 | 132 | print "UNKNOWN: " + unknowns | ||
718 | 133 | sys.exit(STATUS_UNKNOWN) | ||
719 | 134 | else: | ||
720 | 135 | print "OK" | ||
721 | 136 | sys.exit(0) | ||
722 | 0 | 137 | ||
723 | === added file 'templates/050-swift-storage' | |||
724 | --- templates/050-swift-storage 1970-01-01 00:00:00 +0000 | |||
725 | +++ templates/050-swift-storage 2014-06-02 09:35:40 +0000 | |||
726 | @@ -0,0 +1,24 @@ | |||
727 | 1 | [account] | ||
728 | 2 | uid = swift | ||
729 | 3 | gid = swift | ||
730 | 4 | max connections = 2 | ||
731 | 5 | path = /srv/node/ | ||
732 | 6 | read only = false | ||
733 | 7 | lock file = /var/lock/account.lock | ||
734 | 8 | |||
735 | 9 | [container] | ||
736 | 10 | uid = swift | ||
737 | 11 | gid = swift | ||
738 | 12 | max connections = 2 | ||
739 | 13 | path = /srv/node/ | ||
740 | 14 | read only = false | ||
741 | 15 | lock file = /var/lock/container.lock | ||
742 | 16 | |||
743 | 17 | [object] | ||
744 | 18 | uid = swift | ||
745 | 19 | gid = swift | ||
746 | 20 | max connections = 2 | ||
747 | 21 | path = /srv/node/ | ||
748 | 22 | read only = false | ||
749 | 23 | lock file = /var/lock/object.lock | ||
750 | 24 | |||
751 | 0 | 25 | ||
752 | === modified file 'templates/rsyncd.conf' | |||
753 | --- templates/rsyncd.conf 2013-07-19 19:52:45 +0000 | |||
754 | +++ templates/rsyncd.conf 2014-06-02 09:35:40 +0000 | |||
755 | @@ -1,23 +1,5 @@ | |||
779 | 1 | uid = swift | 1 | uid = nobody |
780 | 2 | gid = swift | 2 | gid = nogroup |
781 | 3 | log file = /var/log/rsyncd.log | 3 | syslog facility = daemon |
782 | 4 | pid file = /var/run/rsyncd.pid | 4 | socket options = SO_KEEPALIVE |
783 | 5 | address = {{ local_ip }} | 5 | |
761 | 6 | |||
762 | 7 | [account] | ||
763 | 8 | max connections = 2 | ||
764 | 9 | path = /srv/node/ | ||
765 | 10 | read only = false | ||
766 | 11 | lock file = /var/lock/account.lock | ||
767 | 12 | |||
768 | 13 | [container] | ||
769 | 14 | max connections = 2 | ||
770 | 15 | path = /srv/node/ | ||
771 | 16 | read only = false | ||
772 | 17 | lock file = /var/lock/container.lock | ||
773 | 18 | |||
774 | 19 | [object] | ||
775 | 20 | max connections = 2 | ||
776 | 21 | path = /srv/node/ | ||
777 | 22 | read only = false | ||
778 | 23 | lock file = /var/lock/object.lock | ||
784 | 24 | 6 | ||
785 | === modified file 'unit_tests/test_swift_storage_relations.py' | |||
786 | --- unit_tests/test_swift_storage_relations.py 2013-09-27 16:33:06 +0000 | |||
787 | +++ unit_tests/test_swift_storage_relations.py 2014-06-02 09:35:40 +0000 | |||
788 | @@ -1,6 +1,6 @@ | |||
789 | 1 | from mock import patch, MagicMock | 1 | from mock import patch, MagicMock |
790 | 2 | 2 | ||
792 | 3 | from test_utils import CharmTestCase | 3 | from test_utils import CharmTestCase, patch_open |
793 | 4 | 4 | ||
794 | 5 | import swift_storage_utils as utils | 5 | import swift_storage_utils as utils |
795 | 6 | 6 | ||
796 | @@ -21,6 +21,7 @@ | |||
797 | 21 | 'log', | 21 | 'log', |
798 | 22 | 'relation_set', | 22 | 'relation_set', |
799 | 23 | 'relation_get', | 23 | 'relation_get', |
800 | 24 | 'relations_of_type', | ||
801 | 24 | # charmhelpers.core.host | 25 | # charmhelpers.core.host |
802 | 25 | 'apt_update', | 26 | 'apt_update', |
803 | 26 | 'apt_install', | 27 | 'apt_install', |
804 | @@ -60,13 +61,19 @@ | |||
805 | 60 | 61 | ||
806 | 61 | def test_config_changed_no_upgrade_available(self): | 62 | def test_config_changed_no_upgrade_available(self): |
807 | 62 | self.openstack_upgrade_available.return_value = False | 63 | self.openstack_upgrade_available.return_value = False |
809 | 63 | hooks.config_changed() | 64 | self.relations_of_type.return_value = False |
810 | 65 | with patch_open() as (_open, _file): | ||
811 | 66 | _file.read.return_value = "foo" | ||
812 | 67 | hooks.config_changed() | ||
813 | 64 | self.assertFalse(self.do_openstack_upgrade.called) | 68 | self.assertFalse(self.do_openstack_upgrade.called) |
814 | 65 | self.assertTrue(self.CONFIGS.write_all.called) | 69 | self.assertTrue(self.CONFIGS.write_all.called) |
815 | 66 | 70 | ||
816 | 67 | def test_config_changed_upgrade_available(self): | 71 | def test_config_changed_upgrade_available(self): |
817 | 68 | self.openstack_upgrade_available.return_value = True | 72 | self.openstack_upgrade_available.return_value = True |
819 | 69 | hooks.config_changed() | 73 | self.relations_of_type.return_value = False |
820 | 74 | with patch_open() as (_open, _file): | ||
821 | 75 | _file.read.return_value = "foo" | ||
822 | 76 | hooks.config_changed() | ||
823 | 70 | self.assertTrue(self.do_openstack_upgrade.called) | 77 | self.assertTrue(self.do_openstack_upgrade.called) |
824 | 71 | self.assertTrue(self.CONFIGS.write_all.called) | 78 | self.assertTrue(self.CONFIGS.write_all.called) |
825 | 72 | 79 | ||
826 | 73 | 80 | ||
827 | === modified file 'unit_tests/test_swift_storage_utils.py' | |||
828 | --- unit_tests/test_swift_storage_utils.py 2014-03-20 13:50:49 +0000 | |||
829 | +++ unit_tests/test_swift_storage_utils.py 2014-06-02 09:35:40 +0000 | |||
830 | @@ -74,7 +74,8 @@ | |||
831 | 74 | ex_dirs = [ | 74 | ex_dirs = [ |
832 | 75 | call('/etc/swift', owner='swift', group='swift'), | 75 | call('/etc/swift', owner='swift', group='swift'), |
833 | 76 | call('/var/cache/swift', owner='swift', group='swift'), | 76 | call('/var/cache/swift', owner='swift', group='swift'), |
835 | 77 | call('/srv/node', owner='swift', group='swift') | 77 | call('/srv/node', owner='swift', group='swift'), |
836 | 78 | call('/etc/rsyncd.d', owner='root', group='root') | ||
837 | 78 | ] | 79 | ] |
838 | 79 | self.assertEquals(ex_dirs, self.mkdir.call_args_list) | 80 | self.assertEquals(ex_dirs, self.mkdir.call_args_list) |
839 | 80 | 81 | ||
840 | @@ -196,7 +197,7 @@ | |||
841 | 196 | openstack_release='grizzly') | 197 | openstack_release='grizzly') |
842 | 197 | ex = [ | 198 | ex = [ |
843 | 198 | call('/etc/swift/swift.conf', ['swift_server_context']), | 199 | call('/etc/swift/swift.conf', ['swift_server_context']), |
845 | 199 | call('/etc/rsyncd.conf', ['rsync_context']), | 200 | call('/etc/rsyncd.d/050-swift-storage', ['rsync_context']), |
846 | 200 | call('/etc/swift/account-server.conf', ['swift_context']), | 201 | call('/etc/swift/account-server.conf', ['swift_context']), |
847 | 201 | call('/etc/swift/object-server.conf', ['swift_context']), | 202 | call('/etc/swift/object-server.conf', ['swift_context']), |
848 | 202 | call('/etc/swift/container-server.conf', ['swift_context']) | 203 | call('/etc/swift/container-server.conf', ['swift_context']) |
This merge proposal appears to have more than just the nrpe support - lots of changes around how rsync is managed as well?
Was this intentional? if so I would prefer that they where split out into two MP's to make it easier to test/review.