Merge lp:~james-page/charms/trusty/mongodb/ch-resync-newton into lp:charms/trusty/mongodb
- Trusty Tahr (14.04)
- ch-resync-newton
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 88 |
Proposed branch: | lp:~james-page/charms/trusty/mongodb/ch-resync-newton |
Merge into: | lp:charms/trusty/mongodb |
Diff against target: |
536 lines (+223/-61) 5 files modified
charmhelpers/contrib/python/packages.py (+22/-7) charmhelpers/core/hookenv.py (+31/-0) charmhelpers/core/host.py (+159/-53) charmhelpers/fetch/__init__.py (+8/-0) charmhelpers/fetch/giturl.py (+3/-1) |
To merge this branch: | bzr merge lp:~james-page/charms/trusty/mongodb/ch-resync-newton |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Review Queue (community) | automated testing | Needs Fixing | |
Ryan Beisner (community) | Approve | ||
Review via email: mp+297046@code.launchpad.net |
Commit message
Description of the change
Resync charm-helpers to ensure that charm understands the Newton UCA.
uosci-testing-bot (uosci-testing-bot) wrote : | # |
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_unit_test #2174 mongodb for james-page mp297046
UNIT OK: passed
uosci-testing-bot (uosci-testing-bot) wrote : | # |
charm_amulet_test #779 mongodb for james-page mp297046
AMULET FAIL: amulet-test failed
AMULET Results (max last 2 lines):
make: *** [functional_test] Error 1
ERROR:root:Make target returned non-zero.
Full amulet test output: http://
Build: http://
Ryan Beisner (1chb1n) wrote : | # |
I believe the amulet test failure is an existing problem with the 03_deploy_
00:30:46.446 juju-test.conductor DEBUG : State for 1.25.5: started
00:30:46.447 juju-test.
00:30:47.717 2016-06-10 11:34:08 Starting deployment of osci-sv08
00:30:48.010 2016-06-10 11:34:08 Deploying services...
00:30:48.081 2016-06-10 11:34:08 Deploying service mongodb using /tmp/charmn47ka
00:34:24.871 2016-06-10 11:37:45 Adding relations...
00:34:24.950 2016-06-10 11:37:45 Exposing service 'mongodb'
00:34:25.167 2016-06-10 11:37:45 Deployment complete in 217.69 seconds
00:35:05.382 juju-test.
00:35:05.382
00:35:05.382 juju-test.
00:35:05.382 juju-test.
00:35:05.382 juju-test.conductor INFO : Breaking here as requested by --set-e
00:35:05.382 juju-test INFO : Results: 3 passed, 1 failed, 0 errored
00:35:05.397 make: *** [functional_test] Error 1
Review Queue (review-queue) wrote : | # |
This item has failed automated testing! Results available here http://
Preview Diff
1 | === modified file 'charmhelpers/contrib/python/packages.py' | |||
2 | --- charmhelpers/contrib/python/packages.py 2016-01-11 18:16:28 +0000 | |||
3 | +++ charmhelpers/contrib/python/packages.py 2016-06-10 10:55:43 +0000 | |||
4 | @@ -19,20 +19,35 @@ | |||
5 | 19 | 19 | ||
6 | 20 | import os | 20 | import os |
7 | 21 | import subprocess | 21 | import subprocess |
8 | 22 | import sys | ||
9 | 22 | 23 | ||
10 | 23 | from charmhelpers.fetch import apt_install, apt_update | 24 | from charmhelpers.fetch import apt_install, apt_update |
11 | 24 | from charmhelpers.core.hookenv import charm_dir, log | 25 | from charmhelpers.core.hookenv import charm_dir, log |
12 | 25 | 26 | ||
13 | 26 | try: | ||
14 | 27 | from pip import main as pip_execute | ||
15 | 28 | except ImportError: | ||
16 | 29 | apt_update() | ||
17 | 30 | apt_install('python-pip') | ||
18 | 31 | from pip import main as pip_execute | ||
19 | 32 | |||
20 | 33 | __author__ = "Jorge Niedbalski <jorge.niedbalski@canonical.com>" | 27 | __author__ = "Jorge Niedbalski <jorge.niedbalski@canonical.com>" |
21 | 34 | 28 | ||
22 | 35 | 29 | ||
23 | 30 | def pip_execute(*args, **kwargs): | ||
24 | 31 | """Overriden pip_execute() to stop sys.path being changed. | ||
25 | 32 | |||
26 | 33 | The act of importing main from the pip module seems to cause add wheels | ||
27 | 34 | from the /usr/share/python-wheels which are installed by various tools. | ||
28 | 35 | This function ensures that sys.path remains the same after the call is | ||
29 | 36 | executed. | ||
30 | 37 | """ | ||
31 | 38 | try: | ||
32 | 39 | _path = sys.path | ||
33 | 40 | try: | ||
34 | 41 | from pip import main as _pip_execute | ||
35 | 42 | except ImportError: | ||
36 | 43 | apt_update() | ||
37 | 44 | apt_install('python-pip') | ||
38 | 45 | from pip import main as _pip_execute | ||
39 | 46 | _pip_execute(*args, **kwargs) | ||
40 | 47 | finally: | ||
41 | 48 | sys.path = _path | ||
42 | 49 | |||
43 | 50 | |||
44 | 36 | def parse_options(given, available): | 51 | def parse_options(given, available): |
45 | 37 | """Given a set of options, check if available""" | 52 | """Given a set of options, check if available""" |
46 | 38 | for key, value in sorted(given.items()): | 53 | for key, value in sorted(given.items()): |
47 | 39 | 54 | ||
48 | === modified file 'charmhelpers/core/hookenv.py' | |||
49 | --- charmhelpers/core/hookenv.py 2016-01-11 18:16:28 +0000 | |||
50 | +++ charmhelpers/core/hookenv.py 2016-06-10 10:55:43 +0000 | |||
51 | @@ -912,6 +912,24 @@ | |||
52 | 912 | subprocess.check_call(cmd) | 912 | subprocess.check_call(cmd) |
53 | 913 | 913 | ||
54 | 914 | 914 | ||
55 | 915 | @translate_exc(from_exc=OSError, to_exc=NotImplementedError) | ||
56 | 916 | def resource_get(name): | ||
57 | 917 | """used to fetch the resource path of the given name. | ||
58 | 918 | |||
59 | 919 | <name> must match a name of defined resource in metadata.yaml | ||
60 | 920 | |||
61 | 921 | returns either a path or False if resource not available | ||
62 | 922 | """ | ||
63 | 923 | if not name: | ||
64 | 924 | return False | ||
65 | 925 | |||
66 | 926 | cmd = ['resource-get', name] | ||
67 | 927 | try: | ||
68 | 928 | return subprocess.check_output(cmd).decode('UTF-8') | ||
69 | 929 | except subprocess.CalledProcessError: | ||
70 | 930 | return False | ||
71 | 931 | |||
72 | 932 | |||
73 | 915 | @cached | 933 | @cached |
74 | 916 | def juju_version(): | 934 | def juju_version(): |
75 | 917 | """Full version string (eg. '1.23.3.1-trusty-amd64')""" | 935 | """Full version string (eg. '1.23.3.1-trusty-amd64')""" |
76 | @@ -976,3 +994,16 @@ | |||
77 | 976 | for callback, args, kwargs in reversed(_atexit): | 994 | for callback, args, kwargs in reversed(_atexit): |
78 | 977 | callback(*args, **kwargs) | 995 | callback(*args, **kwargs) |
79 | 978 | del _atexit[:] | 996 | del _atexit[:] |
80 | 997 | |||
81 | 998 | |||
82 | 999 | @translate_exc(from_exc=OSError, to_exc=NotImplementedError) | ||
83 | 1000 | def network_get_primary_address(binding): | ||
84 | 1001 | ''' | ||
85 | 1002 | Retrieve the primary network address for a named binding | ||
86 | 1003 | |||
87 | 1004 | :param binding: string. The name of a relation of extra-binding | ||
88 | 1005 | :return: string. The primary IP address for the named binding | ||
89 | 1006 | :raise: NotImplementedError if run on Juju < 2.0 | ||
90 | 1007 | ''' | ||
91 | 1008 | cmd = ['network-get', '--primary-address', binding] | ||
92 | 1009 | return subprocess.check_output(cmd).strip() | ||
93 | 979 | 1010 | ||
94 | === modified file 'charmhelpers/core/host.py' | |||
95 | --- charmhelpers/core/host.py 2016-01-11 18:16:28 +0000 | |||
96 | +++ charmhelpers/core/host.py 2016-06-10 10:55:43 +0000 | |||
97 | @@ -30,6 +30,8 @@ | |||
98 | 30 | import string | 30 | import string |
99 | 31 | import subprocess | 31 | import subprocess |
100 | 32 | import hashlib | 32 | import hashlib |
101 | 33 | import functools | ||
102 | 34 | import itertools | ||
103 | 33 | from contextlib import contextmanager | 35 | from contextlib import contextmanager |
104 | 34 | from collections import OrderedDict | 36 | from collections import OrderedDict |
105 | 35 | 37 | ||
106 | @@ -126,22 +128,31 @@ | |||
107 | 126 | return subprocess.call(cmd) == 0 | 128 | return subprocess.call(cmd) == 0 |
108 | 127 | 129 | ||
109 | 128 | 130 | ||
110 | 131 | _UPSTART_CONF = "/etc/init/{}.conf" | ||
111 | 132 | _INIT_D_CONF = "/etc/init.d/{}" | ||
112 | 133 | |||
113 | 134 | |||
114 | 129 | def service_running(service_name): | 135 | def service_running(service_name): |
115 | 130 | """Determine whether a system service is running""" | 136 | """Determine whether a system service is running""" |
116 | 131 | if init_is_systemd(): | 137 | if init_is_systemd(): |
117 | 132 | return service('is-active', service_name) | 138 | return service('is-active', service_name) |
118 | 133 | else: | 139 | else: |
129 | 134 | try: | 140 | if os.path.exists(_UPSTART_CONF.format(service_name)): |
130 | 135 | output = subprocess.check_output( | 141 | try: |
131 | 136 | ['service', service_name, 'status'], | 142 | output = subprocess.check_output( |
132 | 137 | stderr=subprocess.STDOUT).decode('UTF-8') | 143 | ['status', service_name], |
133 | 138 | except subprocess.CalledProcessError: | 144 | stderr=subprocess.STDOUT).decode('UTF-8') |
134 | 139 | return False | 145 | except subprocess.CalledProcessError: |
125 | 140 | else: | ||
126 | 141 | if ("start/running" in output or "is running" in output): | ||
127 | 142 | return True | ||
128 | 143 | else: | ||
135 | 144 | return False | 146 | return False |
136 | 147 | else: | ||
137 | 148 | # This works for upstart scripts where the 'service' command | ||
138 | 149 | # returns a consistent string to represent running 'start/running' | ||
139 | 150 | if "start/running" in output: | ||
140 | 151 | return True | ||
141 | 152 | elif os.path.exists(_INIT_D_CONF.format(service_name)): | ||
142 | 153 | # Check System V scripts init script return codes | ||
143 | 154 | return service('status', service_name) | ||
144 | 155 | return False | ||
145 | 145 | 156 | ||
146 | 146 | 157 | ||
147 | 147 | def service_available(service_name): | 158 | def service_available(service_name): |
148 | @@ -160,13 +171,13 @@ | |||
149 | 160 | 171 | ||
150 | 161 | 172 | ||
151 | 162 | def init_is_systemd(): | 173 | def init_is_systemd(): |
152 | 174 | """Return True if the host system uses systemd, False otherwise.""" | ||
153 | 163 | return os.path.isdir(SYSTEMD_SYSTEM) | 175 | return os.path.isdir(SYSTEMD_SYSTEM) |
154 | 164 | 176 | ||
155 | 165 | 177 | ||
156 | 166 | def adduser(username, password=None, shell='/bin/bash', system_user=False, | 178 | def adduser(username, password=None, shell='/bin/bash', system_user=False, |
160 | 167 | primary_group=None, secondary_groups=None): | 179 | primary_group=None, secondary_groups=None, uid=None): |
161 | 168 | """ | 180 | """Add a user to the system. |
159 | 169 | Add a user to the system. | ||
162 | 170 | 181 | ||
163 | 171 | Will log but otherwise succeed if the user already exists. | 182 | Will log but otherwise succeed if the user already exists. |
164 | 172 | 183 | ||
165 | @@ -174,17 +185,23 @@ | |||
166 | 174 | :param str password: Password for user; if ``None``, create a system user | 185 | :param str password: Password for user; if ``None``, create a system user |
167 | 175 | :param str shell: The default shell for the user | 186 | :param str shell: The default shell for the user |
168 | 176 | :param bool system_user: Whether to create a login or system user | 187 | :param bool system_user: Whether to create a login or system user |
170 | 177 | :param str primary_group: Primary group for user; defaults to their username | 188 | :param str primary_group: Primary group for user; defaults to username |
171 | 178 | :param list secondary_groups: Optional list of additional groups | 189 | :param list secondary_groups: Optional list of additional groups |
172 | 190 | :param int uid: UID for user being created | ||
173 | 179 | 191 | ||
174 | 180 | :returns: The password database entry struct, as returned by `pwd.getpwnam` | 192 | :returns: The password database entry struct, as returned by `pwd.getpwnam` |
175 | 181 | """ | 193 | """ |
176 | 182 | try: | 194 | try: |
177 | 183 | user_info = pwd.getpwnam(username) | 195 | user_info = pwd.getpwnam(username) |
178 | 184 | log('user {0} already exists!'.format(username)) | 196 | log('user {0} already exists!'.format(username)) |
179 | 197 | if uid: | ||
180 | 198 | user_info = pwd.getpwuid(int(uid)) | ||
181 | 199 | log('user with uid {0} already exists!'.format(uid)) | ||
182 | 185 | except KeyError: | 200 | except KeyError: |
183 | 186 | log('creating user {0}'.format(username)) | 201 | log('creating user {0}'.format(username)) |
184 | 187 | cmd = ['useradd'] | 202 | cmd = ['useradd'] |
185 | 203 | if uid: | ||
186 | 204 | cmd.extend(['--uid', str(uid)]) | ||
187 | 188 | if system_user or password is None: | 205 | if system_user or password is None: |
188 | 189 | cmd.append('--system') | 206 | cmd.append('--system') |
189 | 190 | else: | 207 | else: |
190 | @@ -219,14 +236,58 @@ | |||
191 | 219 | return user_exists | 236 | return user_exists |
192 | 220 | 237 | ||
193 | 221 | 238 | ||
196 | 222 | def add_group(group_name, system_group=False): | 239 | def uid_exists(uid): |
197 | 223 | """Add a group to the system""" | 240 | """Check if a uid exists""" |
198 | 241 | try: | ||
199 | 242 | pwd.getpwuid(uid) | ||
200 | 243 | uid_exists = True | ||
201 | 244 | except KeyError: | ||
202 | 245 | uid_exists = False | ||
203 | 246 | return uid_exists | ||
204 | 247 | |||
205 | 248 | |||
206 | 249 | def group_exists(groupname): | ||
207 | 250 | """Check if a group exists""" | ||
208 | 251 | try: | ||
209 | 252 | grp.getgrnam(groupname) | ||
210 | 253 | group_exists = True | ||
211 | 254 | except KeyError: | ||
212 | 255 | group_exists = False | ||
213 | 256 | return group_exists | ||
214 | 257 | |||
215 | 258 | |||
216 | 259 | def gid_exists(gid): | ||
217 | 260 | """Check if a gid exists""" | ||
218 | 261 | try: | ||
219 | 262 | grp.getgrgid(gid) | ||
220 | 263 | gid_exists = True | ||
221 | 264 | except KeyError: | ||
222 | 265 | gid_exists = False | ||
223 | 266 | return gid_exists | ||
224 | 267 | |||
225 | 268 | |||
226 | 269 | def add_group(group_name, system_group=False, gid=None): | ||
227 | 270 | """Add a group to the system | ||
228 | 271 | |||
229 | 272 | Will log but otherwise succeed if the group already exists. | ||
230 | 273 | |||
231 | 274 | :param str group_name: group to create | ||
232 | 275 | :param bool system_group: Create system group | ||
233 | 276 | :param int gid: GID for user being created | ||
234 | 277 | |||
235 | 278 | :returns: The password database entry struct, as returned by `grp.getgrnam` | ||
236 | 279 | """ | ||
237 | 224 | try: | 280 | try: |
238 | 225 | group_info = grp.getgrnam(group_name) | 281 | group_info = grp.getgrnam(group_name) |
239 | 226 | log('group {0} already exists!'.format(group_name)) | 282 | log('group {0} already exists!'.format(group_name)) |
240 | 283 | if gid: | ||
241 | 284 | group_info = grp.getgrgid(gid) | ||
242 | 285 | log('group with gid {0} already exists!'.format(gid)) | ||
243 | 227 | except KeyError: | 286 | except KeyError: |
244 | 228 | log('creating group {0}'.format(group_name)) | 287 | log('creating group {0}'.format(group_name)) |
245 | 229 | cmd = ['addgroup'] | 288 | cmd = ['addgroup'] |
246 | 289 | if gid: | ||
247 | 290 | cmd.extend(['--gid', str(gid)]) | ||
248 | 230 | if system_group: | 291 | if system_group: |
249 | 231 | cmd.append('--system') | 292 | cmd.append('--system') |
250 | 232 | else: | 293 | else: |
251 | @@ -300,14 +361,12 @@ | |||
252 | 300 | 361 | ||
253 | 301 | 362 | ||
254 | 302 | def fstab_remove(mp): | 363 | def fstab_remove(mp): |
257 | 303 | """Remove the given mountpoint entry from /etc/fstab | 364 | """Remove the given mountpoint entry from /etc/fstab""" |
256 | 304 | """ | ||
258 | 305 | return Fstab.remove_by_mountpoint(mp) | 365 | return Fstab.remove_by_mountpoint(mp) |
259 | 306 | 366 | ||
260 | 307 | 367 | ||
261 | 308 | def fstab_add(dev, mp, fs, options=None): | 368 | def fstab_add(dev, mp, fs, options=None): |
264 | 309 | """Adds the given device entry to the /etc/fstab file | 369 | """Adds the given device entry to the /etc/fstab file""" |
263 | 310 | """ | ||
265 | 311 | return Fstab.add(dev, mp, fs, options=options) | 370 | return Fstab.add(dev, mp, fs, options=options) |
266 | 312 | 371 | ||
267 | 313 | 372 | ||
268 | @@ -363,8 +422,7 @@ | |||
269 | 363 | 422 | ||
270 | 364 | 423 | ||
271 | 365 | def file_hash(path, hash_type='md5'): | 424 | def file_hash(path, hash_type='md5'): |
274 | 366 | """ | 425 | """Generate a hash checksum of the contents of 'path' or None if not found. |
273 | 367 | Generate a hash checksum of the contents of 'path' or None if not found. | ||
275 | 368 | 426 | ||
276 | 369 | :param str hash_type: Any hash alrgorithm supported by :mod:`hashlib`, | 427 | :param str hash_type: Any hash alrgorithm supported by :mod:`hashlib`, |
277 | 370 | such as md5, sha1, sha256, sha512, etc. | 428 | such as md5, sha1, sha256, sha512, etc. |
278 | @@ -379,10 +437,9 @@ | |||
279 | 379 | 437 | ||
280 | 380 | 438 | ||
281 | 381 | def path_hash(path): | 439 | def path_hash(path): |
286 | 382 | """ | 440 | """Generate a hash checksum of all files matching 'path'. Standard |
287 | 383 | Generate a hash checksum of all files matching 'path'. Standard wildcards | 441 | wildcards like '*' and '?' are supported, see documentation for the 'glob' |
288 | 384 | like '*' and '?' are supported, see documentation for the 'glob' module for | 442 | module for more information. |
285 | 385 | more information. | ||
289 | 386 | 443 | ||
290 | 387 | :return: dict: A { filename: hash } dictionary for all matched files. | 444 | :return: dict: A { filename: hash } dictionary for all matched files. |
291 | 388 | Empty if none found. | 445 | Empty if none found. |
292 | @@ -394,8 +451,7 @@ | |||
293 | 394 | 451 | ||
294 | 395 | 452 | ||
295 | 396 | def check_hash(path, checksum, hash_type='md5'): | 453 | def check_hash(path, checksum, hash_type='md5'): |
298 | 397 | """ | 454 | """Validate a file using a cryptographic checksum. |
297 | 398 | Validate a file using a cryptographic checksum. | ||
299 | 399 | 455 | ||
300 | 400 | :param str checksum: Value of the checksum used to validate the file. | 456 | :param str checksum: Value of the checksum used to validate the file. |
301 | 401 | :param str hash_type: Hash algorithm used to generate `checksum`. | 457 | :param str hash_type: Hash algorithm used to generate `checksum`. |
302 | @@ -410,10 +466,11 @@ | |||
303 | 410 | 466 | ||
304 | 411 | 467 | ||
305 | 412 | class ChecksumError(ValueError): | 468 | class ChecksumError(ValueError): |
306 | 469 | """A class derived from Value error to indicate the checksum failed.""" | ||
307 | 413 | pass | 470 | pass |
308 | 414 | 471 | ||
309 | 415 | 472 | ||
311 | 416 | def restart_on_change(restart_map, stopstart=False): | 473 | def restart_on_change(restart_map, stopstart=False, restart_functions=None): |
312 | 417 | """Restart services based on configuration files changing | 474 | """Restart services based on configuration files changing |
313 | 418 | 475 | ||
314 | 419 | This function is used a decorator, for example:: | 476 | This function is used a decorator, for example:: |
315 | @@ -431,27 +488,58 @@ | |||
316 | 431 | restarted if any file matching the pattern got changed, created | 488 | restarted if any file matching the pattern got changed, created |
317 | 432 | or removed. Standard wildcards are supported, see documentation | 489 | or removed. Standard wildcards are supported, see documentation |
318 | 433 | for the 'glob' module for more information. | 490 | for the 'glob' module for more information. |
319 | 491 | |||
320 | 492 | @param restart_map: {path_file_name: [service_name, ...] | ||
321 | 493 | @param stopstart: DEFAULT false; whether to stop, start OR restart | ||
322 | 494 | @param restart_functions: nonstandard functions to use to restart services | ||
323 | 495 | {svc: func, ...} | ||
324 | 496 | @returns result from decorated function | ||
325 | 434 | """ | 497 | """ |
326 | 435 | def wrap(f): | 498 | def wrap(f): |
327 | 499 | @functools.wraps(f) | ||
328 | 436 | def wrapped_f(*args, **kwargs): | 500 | def wrapped_f(*args, **kwargs): |
343 | 437 | checksums = {path: path_hash(path) for path in restart_map} | 501 | return restart_on_change_helper( |
344 | 438 | f(*args, **kwargs) | 502 | (lambda: f(*args, **kwargs)), restart_map, stopstart, |
345 | 439 | restarts = [] | 503 | restart_functions) |
332 | 440 | for path in restart_map: | ||
333 | 441 | if path_hash(path) != checksums[path]: | ||
334 | 442 | restarts += restart_map[path] | ||
335 | 443 | services_list = list(OrderedDict.fromkeys(restarts)) | ||
336 | 444 | if not stopstart: | ||
337 | 445 | for service_name in services_list: | ||
338 | 446 | service('restart', service_name) | ||
339 | 447 | else: | ||
340 | 448 | for action in ['stop', 'start']: | ||
341 | 449 | for service_name in services_list: | ||
342 | 450 | service(action, service_name) | ||
346 | 451 | return wrapped_f | 504 | return wrapped_f |
347 | 452 | return wrap | 505 | return wrap |
348 | 453 | 506 | ||
349 | 454 | 507 | ||
350 | 508 | def restart_on_change_helper(lambda_f, restart_map, stopstart=False, | ||
351 | 509 | restart_functions=None): | ||
352 | 510 | """Helper function to perform the restart_on_change function. | ||
353 | 511 | |||
354 | 512 | This is provided for decorators to restart services if files described | ||
355 | 513 | in the restart_map have changed after an invocation of lambda_f(). | ||
356 | 514 | |||
357 | 515 | @param lambda_f: function to call. | ||
358 | 516 | @param restart_map: {file: [service, ...]} | ||
359 | 517 | @param stopstart: whether to stop, start or restart a service | ||
360 | 518 | @param restart_functions: nonstandard functions to use to restart services | ||
361 | 519 | {svc: func, ...} | ||
362 | 520 | @returns result of lambda_f() | ||
363 | 521 | """ | ||
364 | 522 | if restart_functions is None: | ||
365 | 523 | restart_functions = {} | ||
366 | 524 | checksums = {path: path_hash(path) for path in restart_map} | ||
367 | 525 | r = lambda_f() | ||
368 | 526 | # create a list of lists of the services to restart | ||
369 | 527 | restarts = [restart_map[path] | ||
370 | 528 | for path in restart_map | ||
371 | 529 | if path_hash(path) != checksums[path]] | ||
372 | 530 | # create a flat list of ordered services without duplicates from lists | ||
373 | 531 | services_list = list(OrderedDict.fromkeys(itertools.chain(*restarts))) | ||
374 | 532 | if services_list: | ||
375 | 533 | actions = ('stop', 'start') if stopstart else ('restart',) | ||
376 | 534 | for service_name in services_list: | ||
377 | 535 | if service_name in restart_functions: | ||
378 | 536 | restart_functions[service_name](service_name) | ||
379 | 537 | else: | ||
380 | 538 | for action in actions: | ||
381 | 539 | service(action, service_name) | ||
382 | 540 | return r | ||
383 | 541 | |||
384 | 542 | |||
385 | 455 | def lsb_release(): | 543 | def lsb_release(): |
386 | 456 | """Return /etc/lsb-release in a dict""" | 544 | """Return /etc/lsb-release in a dict""" |
387 | 457 | d = {} | 545 | d = {} |
388 | @@ -515,7 +603,7 @@ | |||
389 | 515 | 603 | ||
390 | 516 | 604 | ||
391 | 517 | def list_nics(nic_type=None): | 605 | def list_nics(nic_type=None): |
393 | 518 | '''Return a list of nics of given type(s)''' | 606 | """Return a list of nics of given type(s)""" |
394 | 519 | if isinstance(nic_type, six.string_types): | 607 | if isinstance(nic_type, six.string_types): |
395 | 520 | int_types = [nic_type] | 608 | int_types = [nic_type] |
396 | 521 | else: | 609 | else: |
397 | @@ -557,12 +645,13 @@ | |||
398 | 557 | 645 | ||
399 | 558 | 646 | ||
400 | 559 | def set_nic_mtu(nic, mtu): | 647 | def set_nic_mtu(nic, mtu): |
402 | 560 | '''Set MTU on a network interface''' | 648 | """Set the Maximum Transmission Unit (MTU) on a network interface.""" |
403 | 561 | cmd = ['ip', 'link', 'set', nic, 'mtu', mtu] | 649 | cmd = ['ip', 'link', 'set', nic, 'mtu', mtu] |
404 | 562 | subprocess.check_call(cmd) | 650 | subprocess.check_call(cmd) |
405 | 563 | 651 | ||
406 | 564 | 652 | ||
407 | 565 | def get_nic_mtu(nic): | 653 | def get_nic_mtu(nic): |
408 | 654 | """Return the Maximum Transmission Unit (MTU) for a network interface.""" | ||
409 | 566 | cmd = ['ip', 'addr', 'show', nic] | 655 | cmd = ['ip', 'addr', 'show', nic] |
410 | 567 | ip_output = subprocess.check_output(cmd).decode('UTF-8').split('\n') | 656 | ip_output = subprocess.check_output(cmd).decode('UTF-8').split('\n') |
411 | 568 | mtu = "" | 657 | mtu = "" |
412 | @@ -574,6 +663,7 @@ | |||
413 | 574 | 663 | ||
414 | 575 | 664 | ||
415 | 576 | def get_nic_hwaddr(nic): | 665 | def get_nic_hwaddr(nic): |
416 | 666 | """Return the Media Access Control (MAC) for a network interface.""" | ||
417 | 577 | cmd = ['ip', '-o', '-0', 'addr', 'show', nic] | 667 | cmd = ['ip', '-o', '-0', 'addr', 'show', nic] |
418 | 578 | ip_output = subprocess.check_output(cmd).decode('UTF-8') | 668 | ip_output = subprocess.check_output(cmd).decode('UTF-8') |
419 | 579 | hwaddr = "" | 669 | hwaddr = "" |
420 | @@ -584,7 +674,7 @@ | |||
421 | 584 | 674 | ||
422 | 585 | 675 | ||
423 | 586 | def cmp_pkgrevno(package, revno, pkgcache=None): | 676 | def cmp_pkgrevno(package, revno, pkgcache=None): |
425 | 587 | '''Compare supplied revno with the revno of the installed package | 677 | """Compare supplied revno with the revno of the installed package |
426 | 588 | 678 | ||
427 | 589 | * 1 => Installed revno is greater than supplied arg | 679 | * 1 => Installed revno is greater than supplied arg |
428 | 590 | * 0 => Installed revno is the same as supplied arg | 680 | * 0 => Installed revno is the same as supplied arg |
429 | @@ -593,7 +683,7 @@ | |||
430 | 593 | This function imports apt_cache function from charmhelpers.fetch if | 683 | This function imports apt_cache function from charmhelpers.fetch if |
431 | 594 | the pkgcache argument is None. Be sure to add charmhelpers.fetch if | 684 | the pkgcache argument is None. Be sure to add charmhelpers.fetch if |
432 | 595 | you call this function, or pass an apt_pkg.Cache() instance. | 685 | you call this function, or pass an apt_pkg.Cache() instance. |
434 | 596 | ''' | 686 | """ |
435 | 597 | import apt_pkg | 687 | import apt_pkg |
436 | 598 | if not pkgcache: | 688 | if not pkgcache: |
437 | 599 | from charmhelpers.fetch import apt_cache | 689 | from charmhelpers.fetch import apt_cache |
438 | @@ -603,19 +693,27 @@ | |||
439 | 603 | 693 | ||
440 | 604 | 694 | ||
441 | 605 | @contextmanager | 695 | @contextmanager |
443 | 606 | def chdir(d): | 696 | def chdir(directory): |
444 | 697 | """Change the current working directory to a different directory for a code | ||
445 | 698 | block and return the previous directory after the block exits. Useful to | ||
446 | 699 | run commands from a specificed directory. | ||
447 | 700 | |||
448 | 701 | :param str directory: The directory path to change to for this context. | ||
449 | 702 | """ | ||
450 | 607 | cur = os.getcwd() | 703 | cur = os.getcwd() |
451 | 608 | try: | 704 | try: |
453 | 609 | yield os.chdir(d) | 705 | yield os.chdir(directory) |
454 | 610 | finally: | 706 | finally: |
455 | 611 | os.chdir(cur) | 707 | os.chdir(cur) |
456 | 612 | 708 | ||
457 | 613 | 709 | ||
458 | 614 | def chownr(path, owner, group, follow_links=True, chowntopdir=False): | 710 | def chownr(path, owner, group, follow_links=True, chowntopdir=False): |
461 | 615 | """ | 711 | """Recursively change user and group ownership of files and directories |
460 | 616 | Recursively change user and group ownership of files and directories | ||
462 | 617 | in given path. Doesn't chown path itself by default, only its children. | 712 | in given path. Doesn't chown path itself by default, only its children. |
463 | 618 | 713 | ||
464 | 714 | :param str path: The string path to start changing ownership. | ||
465 | 715 | :param str owner: The owner string to use when looking up the uid. | ||
466 | 716 | :param str group: The group string to use when looking up the gid. | ||
467 | 619 | :param bool follow_links: Also Chown links if True | 717 | :param bool follow_links: Also Chown links if True |
468 | 620 | :param bool chowntopdir: Also chown path itself if True | 718 | :param bool chowntopdir: Also chown path itself if True |
469 | 621 | """ | 719 | """ |
470 | @@ -639,15 +737,23 @@ | |||
471 | 639 | 737 | ||
472 | 640 | 738 | ||
473 | 641 | def lchownr(path, owner, group): | 739 | def lchownr(path, owner, group): |
474 | 740 | """Recursively change user and group ownership of files and directories | ||
475 | 741 | in a given path, not following symbolic links. See the documentation for | ||
476 | 742 | 'os.lchown' for more information. | ||
477 | 743 | |||
478 | 744 | :param str path: The string path to start changing ownership. | ||
479 | 745 | :param str owner: The owner string to use when looking up the uid. | ||
480 | 746 | :param str group: The group string to use when looking up the gid. | ||
481 | 747 | """ | ||
482 | 642 | chownr(path, owner, group, follow_links=False) | 748 | chownr(path, owner, group, follow_links=False) |
483 | 643 | 749 | ||
484 | 644 | 750 | ||
485 | 645 | def get_total_ram(): | 751 | def get_total_ram(): |
487 | 646 | '''The total amount of system RAM in bytes. | 752 | """The total amount of system RAM in bytes. |
488 | 647 | 753 | ||
489 | 648 | This is what is reported by the OS, and may be overcommitted when | 754 | This is what is reported by the OS, and may be overcommitted when |
490 | 649 | there are multiple containers hosted on the same machine. | 755 | there are multiple containers hosted on the same machine. |
492 | 650 | ''' | 756 | """ |
493 | 651 | with open('/proc/meminfo', 'r') as f: | 757 | with open('/proc/meminfo', 'r') as f: |
494 | 652 | for line in f.readlines(): | 758 | for line in f.readlines(): |
495 | 653 | if line: | 759 | if line: |
496 | 654 | 760 | ||
497 | === modified file 'charmhelpers/fetch/__init__.py' | |||
498 | --- charmhelpers/fetch/__init__.py 2016-01-11 18:16:28 +0000 | |||
499 | +++ charmhelpers/fetch/__init__.py 2016-06-10 10:55:43 +0000 | |||
500 | @@ -106,6 +106,14 @@ | |||
501 | 106 | 'mitaka/proposed': 'trusty-proposed/mitaka', | 106 | 'mitaka/proposed': 'trusty-proposed/mitaka', |
502 | 107 | 'trusty-mitaka/proposed': 'trusty-proposed/mitaka', | 107 | 'trusty-mitaka/proposed': 'trusty-proposed/mitaka', |
503 | 108 | 'trusty-proposed/mitaka': 'trusty-proposed/mitaka', | 108 | 'trusty-proposed/mitaka': 'trusty-proposed/mitaka', |
504 | 109 | # Newton | ||
505 | 110 | 'newton': 'xenial-updates/newton', | ||
506 | 111 | 'xenial-newton': 'xenial-updates/newton', | ||
507 | 112 | 'xenial-newton/updates': 'xenial-updates/newton', | ||
508 | 113 | 'xenial-updates/newton': 'xenial-updates/newton', | ||
509 | 114 | 'newton/proposed': 'xenial-proposed/newton', | ||
510 | 115 | 'xenial-newton/proposed': 'xenial-proposed/newton', | ||
511 | 116 | 'xenial-proposed/newton': 'xenial-proposed/newton', | ||
512 | 109 | } | 117 | } |
513 | 110 | 118 | ||
514 | 111 | # The order of this list is very important. Handlers should be listed in from | 119 | # The order of this list is very important. Handlers should be listed in from |
515 | 112 | 120 | ||
516 | === modified file 'charmhelpers/fetch/giturl.py' | |||
517 | --- charmhelpers/fetch/giturl.py 2016-01-11 18:16:28 +0000 | |||
518 | +++ charmhelpers/fetch/giturl.py 2016-06-10 10:55:43 +0000 | |||
519 | @@ -15,7 +15,7 @@ | |||
520 | 15 | # along with charm-helpers. If not, see <http://www.gnu.org/licenses/>. | 15 | # along with charm-helpers. If not, see <http://www.gnu.org/licenses/>. |
521 | 16 | 16 | ||
522 | 17 | import os | 17 | import os |
524 | 18 | from subprocess import check_call | 18 | from subprocess import check_call, CalledProcessError |
525 | 19 | from charmhelpers.fetch import ( | 19 | from charmhelpers.fetch import ( |
526 | 20 | BaseFetchHandler, | 20 | BaseFetchHandler, |
527 | 21 | UnhandledSource, | 21 | UnhandledSource, |
528 | @@ -63,6 +63,8 @@ | |||
529 | 63 | branch_name) | 63 | branch_name) |
530 | 64 | try: | 64 | try: |
531 | 65 | self.clone(source, dest_dir, branch, depth) | 65 | self.clone(source, dest_dir, branch, depth) |
532 | 66 | except CalledProcessError as e: | ||
533 | 67 | raise UnhandledSource(e) | ||
534 | 66 | except OSError as e: | 68 | except OSError as e: |
535 | 67 | raise UnhandledSource(e.strerror) | 69 | raise UnhandledSource(e.strerror) |
536 | 68 | return dest_dir | 70 | return dest_dir |
charm_lint_check #2850 mongodb for james-page mp297046
LINT OK: passed
Build: http:// 10.245. 162.36: 8080/job/ charm_lint_ check/2850/