Merge lp:~james-page/charms/trusty/mongodb/ch-resync-newton into lp:charms/trusty/mongodb

Proposed by James Page
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
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

Description of the change

Resync charm-helpers to ensure that charm understands the Newton UCA.

To post a comment you must log in.
Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_lint_check #2850 mongodb for james-page mp297046
    LINT OK: passed

Build: http://10.245.162.36:8080/job/charm_lint_check/2850/

Revision history for this message
uosci-testing-bot (uosci-testing-bot) wrote :

charm_unit_test #2174 mongodb for james-page mp297046
    UNIT OK: passed

Build: http://10.245.162.36:8080/job/charm_unit_test/2174/

Revision history for this message
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://paste.ubuntu.com/17168378/
Build: http://10.245.162.36:8080/job/charm_amulet_test/779/

Revision history for this message
Ryan Beisner (1chb1n) wrote :

I believe the amulet test failure is an existing problem with the 03_deploy_replicaset.py test logic, https://bugs.launchpad.net/charms/+source/mongodb/+bug/1518468.

00:30:46.446 juju-test.conductor DEBUG : State for 1.25.5: started
00:30:46.447 juju-test.conductor.03_deploy_replicaset.py DEBUG : Running 03_deploy_replicaset.py (tests/03_deploy_replicaset.py)
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/charmn47kajm4/trusty/mongodb
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.conductor.03_deploy_replicaset.py DEBUG : Expected 2 secondary units! (Found 0) [5, 5, 1]
00:35:05.382
00:35:05.382 juju-test.conductor.03_deploy_replicaset.py DEBUG : Got exit code: 1
00:35:05.382 juju-test.conductor.03_deploy_replicaset.py RESULT : FAIL
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: Approve
Revision history for this message
Review Queue (review-queue) wrote :

This item has failed automated testing! Results available here http://juju-ci.vapour.ws:8080/job/charm-bundle-test-aws/4675/

review: Needs Fixing (automated testing)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'charmhelpers/contrib/python/packages.py'
--- charmhelpers/contrib/python/packages.py 2016-01-11 18:16:28 +0000
+++ charmhelpers/contrib/python/packages.py 2016-06-10 10:55:43 +0000
@@ -19,20 +19,35 @@
1919
20import os20import os
21import subprocess21import subprocess
22import sys
2223
23from charmhelpers.fetch import apt_install, apt_update24from charmhelpers.fetch import apt_install, apt_update
24from charmhelpers.core.hookenv import charm_dir, log25from charmhelpers.core.hookenv import charm_dir, log
2526
26try:
27 from pip import main as pip_execute
28except ImportError:
29 apt_update()
30 apt_install('python-pip')
31 from pip import main as pip_execute
32
33__author__ = "Jorge Niedbalski <jorge.niedbalski@canonical.com>"27__author__ = "Jorge Niedbalski <jorge.niedbalski@canonical.com>"
3428
3529
30def pip_execute(*args, **kwargs):
31 """Overriden pip_execute() to stop sys.path being changed.
32
33 The act of importing main from the pip module seems to cause add wheels
34 from the /usr/share/python-wheels which are installed by various tools.
35 This function ensures that sys.path remains the same after the call is
36 executed.
37 """
38 try:
39 _path = sys.path
40 try:
41 from pip import main as _pip_execute
42 except ImportError:
43 apt_update()
44 apt_install('python-pip')
45 from pip import main as _pip_execute
46 _pip_execute(*args, **kwargs)
47 finally:
48 sys.path = _path
49
50
36def parse_options(given, available):51def parse_options(given, available):
37 """Given a set of options, check if available"""52 """Given a set of options, check if available"""
38 for key, value in sorted(given.items()):53 for key, value in sorted(given.items()):
3954
=== modified file 'charmhelpers/core/hookenv.py'
--- charmhelpers/core/hookenv.py 2016-01-11 18:16:28 +0000
+++ charmhelpers/core/hookenv.py 2016-06-10 10:55:43 +0000
@@ -912,6 +912,24 @@
912 subprocess.check_call(cmd)912 subprocess.check_call(cmd)
913913
914914
915@translate_exc(from_exc=OSError, to_exc=NotImplementedError)
916def resource_get(name):
917 """used to fetch the resource path of the given name.
918
919 <name> must match a name of defined resource in metadata.yaml
920
921 returns either a path or False if resource not available
922 """
923 if not name:
924 return False
925
926 cmd = ['resource-get', name]
927 try:
928 return subprocess.check_output(cmd).decode('UTF-8')
929 except subprocess.CalledProcessError:
930 return False
931
932
915@cached933@cached
916def juju_version():934def juju_version():
917 """Full version string (eg. '1.23.3.1-trusty-amd64')"""935 """Full version string (eg. '1.23.3.1-trusty-amd64')"""
@@ -976,3 +994,16 @@
976 for callback, args, kwargs in reversed(_atexit):994 for callback, args, kwargs in reversed(_atexit):
977 callback(*args, **kwargs)995 callback(*args, **kwargs)
978 del _atexit[:]996 del _atexit[:]
997
998
999@translate_exc(from_exc=OSError, to_exc=NotImplementedError)
1000def network_get_primary_address(binding):
1001 '''
1002 Retrieve the primary network address for a named binding
1003
1004 :param binding: string. The name of a relation of extra-binding
1005 :return: string. The primary IP address for the named binding
1006 :raise: NotImplementedError if run on Juju < 2.0
1007 '''
1008 cmd = ['network-get', '--primary-address', binding]
1009 return subprocess.check_output(cmd).strip()
9791010
=== modified file 'charmhelpers/core/host.py'
--- charmhelpers/core/host.py 2016-01-11 18:16:28 +0000
+++ charmhelpers/core/host.py 2016-06-10 10:55:43 +0000
@@ -30,6 +30,8 @@
30import string30import string
31import subprocess31import subprocess
32import hashlib32import hashlib
33import functools
34import itertools
33from contextlib import contextmanager35from contextlib import contextmanager
34from collections import OrderedDict36from collections import OrderedDict
3537
@@ -126,22 +128,31 @@
126 return subprocess.call(cmd) == 0128 return subprocess.call(cmd) == 0
127129
128130
131_UPSTART_CONF = "/etc/init/{}.conf"
132_INIT_D_CONF = "/etc/init.d/{}"
133
134
129def service_running(service_name):135def service_running(service_name):
130 """Determine whether a system service is running"""136 """Determine whether a system service is running"""
131 if init_is_systemd():137 if init_is_systemd():
132 return service('is-active', service_name)138 return service('is-active', service_name)
133 else:139 else:
134 try:140 if os.path.exists(_UPSTART_CONF.format(service_name)):
135 output = subprocess.check_output(141 try:
136 ['service', service_name, 'status'],142 output = subprocess.check_output(
137 stderr=subprocess.STDOUT).decode('UTF-8')143 ['status', service_name],
138 except subprocess.CalledProcessError:144 stderr=subprocess.STDOUT).decode('UTF-8')
139 return False145 except subprocess.CalledProcessError:
140 else:
141 if ("start/running" in output or "is running" in output):
142 return True
143 else:
144 return False146 return False
147 else:
148 # This works for upstart scripts where the 'service' command
149 # returns a consistent string to represent running 'start/running'
150 if "start/running" in output:
151 return True
152 elif os.path.exists(_INIT_D_CONF.format(service_name)):
153 # Check System V scripts init script return codes
154 return service('status', service_name)
155 return False
145156
146157
147def service_available(service_name):158def service_available(service_name):
@@ -160,13 +171,13 @@
160171
161172
162def init_is_systemd():173def init_is_systemd():
174 """Return True if the host system uses systemd, False otherwise."""
163 return os.path.isdir(SYSTEMD_SYSTEM)175 return os.path.isdir(SYSTEMD_SYSTEM)
164176
165177
166def adduser(username, password=None, shell='/bin/bash', system_user=False,178def adduser(username, password=None, shell='/bin/bash', system_user=False,
167 primary_group=None, secondary_groups=None):179 primary_group=None, secondary_groups=None, uid=None):
168 """180 """Add a user to the system.
169 Add a user to the system.
170181
171 Will log but otherwise succeed if the user already exists.182 Will log but otherwise succeed if the user already exists.
172183
@@ -174,17 +185,23 @@
174 :param str password: Password for user; if ``None``, create a system user185 :param str password: Password for user; if ``None``, create a system user
175 :param str shell: The default shell for the user186 :param str shell: The default shell for the user
176 :param bool system_user: Whether to create a login or system user187 :param bool system_user: Whether to create a login or system user
177 :param str primary_group: Primary group for user; defaults to their username188 :param str primary_group: Primary group for user; defaults to username
178 :param list secondary_groups: Optional list of additional groups189 :param list secondary_groups: Optional list of additional groups
190 :param int uid: UID for user being created
179191
180 :returns: The password database entry struct, as returned by `pwd.getpwnam`192 :returns: The password database entry struct, as returned by `pwd.getpwnam`
181 """193 """
182 try:194 try:
183 user_info = pwd.getpwnam(username)195 user_info = pwd.getpwnam(username)
184 log('user {0} already exists!'.format(username))196 log('user {0} already exists!'.format(username))
197 if uid:
198 user_info = pwd.getpwuid(int(uid))
199 log('user with uid {0} already exists!'.format(uid))
185 except KeyError:200 except KeyError:
186 log('creating user {0}'.format(username))201 log('creating user {0}'.format(username))
187 cmd = ['useradd']202 cmd = ['useradd']
203 if uid:
204 cmd.extend(['--uid', str(uid)])
188 if system_user or password is None:205 if system_user or password is None:
189 cmd.append('--system')206 cmd.append('--system')
190 else:207 else:
@@ -219,14 +236,58 @@
219 return user_exists236 return user_exists
220237
221238
222def add_group(group_name, system_group=False):239def uid_exists(uid):
223 """Add a group to the system"""240 """Check if a uid exists"""
241 try:
242 pwd.getpwuid(uid)
243 uid_exists = True
244 except KeyError:
245 uid_exists = False
246 return uid_exists
247
248
249def group_exists(groupname):
250 """Check if a group exists"""
251 try:
252 grp.getgrnam(groupname)
253 group_exists = True
254 except KeyError:
255 group_exists = False
256 return group_exists
257
258
259def gid_exists(gid):
260 """Check if a gid exists"""
261 try:
262 grp.getgrgid(gid)
263 gid_exists = True
264 except KeyError:
265 gid_exists = False
266 return gid_exists
267
268
269def add_group(group_name, system_group=False, gid=None):
270 """Add a group to the system
271
272 Will log but otherwise succeed if the group already exists.
273
274 :param str group_name: group to create
275 :param bool system_group: Create system group
276 :param int gid: GID for user being created
277
278 :returns: The password database entry struct, as returned by `grp.getgrnam`
279 """
224 try:280 try:
225 group_info = grp.getgrnam(group_name)281 group_info = grp.getgrnam(group_name)
226 log('group {0} already exists!'.format(group_name))282 log('group {0} already exists!'.format(group_name))
283 if gid:
284 group_info = grp.getgrgid(gid)
285 log('group with gid {0} already exists!'.format(gid))
227 except KeyError:286 except KeyError:
228 log('creating group {0}'.format(group_name))287 log('creating group {0}'.format(group_name))
229 cmd = ['addgroup']288 cmd = ['addgroup']
289 if gid:
290 cmd.extend(['--gid', str(gid)])
230 if system_group:291 if system_group:
231 cmd.append('--system')292 cmd.append('--system')
232 else:293 else:
@@ -300,14 +361,12 @@
300361
301362
302def fstab_remove(mp):363def fstab_remove(mp):
303 """Remove the given mountpoint entry from /etc/fstab364 """Remove the given mountpoint entry from /etc/fstab"""
304 """
305 return Fstab.remove_by_mountpoint(mp)365 return Fstab.remove_by_mountpoint(mp)
306366
307367
308def fstab_add(dev, mp, fs, options=None):368def fstab_add(dev, mp, fs, options=None):
309 """Adds the given device entry to the /etc/fstab file369 """Adds the given device entry to the /etc/fstab file"""
310 """
311 return Fstab.add(dev, mp, fs, options=options)370 return Fstab.add(dev, mp, fs, options=options)
312371
313372
@@ -363,8 +422,7 @@
363422
364423
365def file_hash(path, hash_type='md5'):424def file_hash(path, hash_type='md5'):
366 """425 """Generate a hash checksum of the contents of 'path' or None if not found.
367 Generate a hash checksum of the contents of 'path' or None if not found.
368426
369 :param str hash_type: Any hash alrgorithm supported by :mod:`hashlib`,427 :param str hash_type: Any hash alrgorithm supported by :mod:`hashlib`,
370 such as md5, sha1, sha256, sha512, etc.428 such as md5, sha1, sha256, sha512, etc.
@@ -379,10 +437,9 @@
379437
380438
381def path_hash(path):439def path_hash(path):
382 """440 """Generate a hash checksum of all files matching 'path'. Standard
383 Generate a hash checksum of all files matching 'path'. Standard wildcards441 wildcards like '*' and '?' are supported, see documentation for the 'glob'
384 like '*' and '?' are supported, see documentation for the 'glob' module for442 module for more information.
385 more information.
386443
387 :return: dict: A { filename: hash } dictionary for all matched files.444 :return: dict: A { filename: hash } dictionary for all matched files.
388 Empty if none found.445 Empty if none found.
@@ -394,8 +451,7 @@
394451
395452
396def check_hash(path, checksum, hash_type='md5'):453def check_hash(path, checksum, hash_type='md5'):
397 """454 """Validate a file using a cryptographic checksum.
398 Validate a file using a cryptographic checksum.
399455
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.
401 :param str hash_type: Hash algorithm used to generate `checksum`.457 :param str hash_type: Hash algorithm used to generate `checksum`.
@@ -410,10 +466,11 @@
410466
411467
412class ChecksumError(ValueError):468class ChecksumError(ValueError):
469 """A class derived from Value error to indicate the checksum failed."""
413 pass470 pass
414471
415472
416def restart_on_change(restart_map, stopstart=False):473def restart_on_change(restart_map, stopstart=False, restart_functions=None):
417 """Restart services based on configuration files changing474 """Restart services based on configuration files changing
418475
419 This function is used a decorator, for example::476 This function is used a decorator, for example::
@@ -431,27 +488,58 @@
431 restarted if any file matching the pattern got changed, created488 restarted if any file matching the pattern got changed, created
432 or removed. Standard wildcards are supported, see documentation489 or removed. Standard wildcards are supported, see documentation
433 for the 'glob' module for more information.490 for the 'glob' module for more information.
491
492 @param restart_map: {path_file_name: [service_name, ...]
493 @param stopstart: DEFAULT false; whether to stop, start OR restart
494 @param restart_functions: nonstandard functions to use to restart services
495 {svc: func, ...}
496 @returns result from decorated function
434 """497 """
435 def wrap(f):498 def wrap(f):
499 @functools.wraps(f)
436 def wrapped_f(*args, **kwargs):500 def wrapped_f(*args, **kwargs):
437 checksums = {path: path_hash(path) for path in restart_map}501 return restart_on_change_helper(
438 f(*args, **kwargs)502 (lambda: f(*args, **kwargs)), restart_map, stopstart,
439 restarts = []503 restart_functions)
440 for path in restart_map:
441 if path_hash(path) != checksums[path]:
442 restarts += restart_map[path]
443 services_list = list(OrderedDict.fromkeys(restarts))
444 if not stopstart:
445 for service_name in services_list:
446 service('restart', service_name)
447 else:
448 for action in ['stop', 'start']:
449 for service_name in services_list:
450 service(action, service_name)
451 return wrapped_f504 return wrapped_f
452 return wrap505 return wrap
453506
454507
508def restart_on_change_helper(lambda_f, restart_map, stopstart=False,
509 restart_functions=None):
510 """Helper function to perform the restart_on_change function.
511
512 This is provided for decorators to restart services if files described
513 in the restart_map have changed after an invocation of lambda_f().
514
515 @param lambda_f: function to call.
516 @param restart_map: {file: [service, ...]}
517 @param stopstart: whether to stop, start or restart a service
518 @param restart_functions: nonstandard functions to use to restart services
519 {svc: func, ...}
520 @returns result of lambda_f()
521 """
522 if restart_functions is None:
523 restart_functions = {}
524 checksums = {path: path_hash(path) for path in restart_map}
525 r = lambda_f()
526 # create a list of lists of the services to restart
527 restarts = [restart_map[path]
528 for path in restart_map
529 if path_hash(path) != checksums[path]]
530 # create a flat list of ordered services without duplicates from lists
531 services_list = list(OrderedDict.fromkeys(itertools.chain(*restarts)))
532 if services_list:
533 actions = ('stop', 'start') if stopstart else ('restart',)
534 for service_name in services_list:
535 if service_name in restart_functions:
536 restart_functions[service_name](service_name)
537 else:
538 for action in actions:
539 service(action, service_name)
540 return r
541
542
455def lsb_release():543def lsb_release():
456 """Return /etc/lsb-release in a dict"""544 """Return /etc/lsb-release in a dict"""
457 d = {}545 d = {}
@@ -515,7 +603,7 @@
515603
516604
517def list_nics(nic_type=None):605def list_nics(nic_type=None):
518 '''Return a list of nics of given type(s)'''606 """Return a list of nics of given type(s)"""
519 if isinstance(nic_type, six.string_types):607 if isinstance(nic_type, six.string_types):
520 int_types = [nic_type]608 int_types = [nic_type]
521 else:609 else:
@@ -557,12 +645,13 @@
557645
558646
559def set_nic_mtu(nic, mtu):647def set_nic_mtu(nic, mtu):
560 '''Set MTU on a network interface'''648 """Set the Maximum Transmission Unit (MTU) on a network interface."""
561 cmd = ['ip', 'link', 'set', nic, 'mtu', mtu]649 cmd = ['ip', 'link', 'set', nic, 'mtu', mtu]
562 subprocess.check_call(cmd)650 subprocess.check_call(cmd)
563651
564652
565def get_nic_mtu(nic):653def get_nic_mtu(nic):
654 """Return the Maximum Transmission Unit (MTU) for a network interface."""
566 cmd = ['ip', 'addr', 'show', nic]655 cmd = ['ip', 'addr', 'show', nic]
567 ip_output = subprocess.check_output(cmd).decode('UTF-8').split('\n')656 ip_output = subprocess.check_output(cmd).decode('UTF-8').split('\n')
568 mtu = ""657 mtu = ""
@@ -574,6 +663,7 @@
574663
575664
576def get_nic_hwaddr(nic):665def get_nic_hwaddr(nic):
666 """Return the Media Access Control (MAC) for a network interface."""
577 cmd = ['ip', '-o', '-0', 'addr', 'show', nic]667 cmd = ['ip', '-o', '-0', 'addr', 'show', nic]
578 ip_output = subprocess.check_output(cmd).decode('UTF-8')668 ip_output = subprocess.check_output(cmd).decode('UTF-8')
579 hwaddr = ""669 hwaddr = ""
@@ -584,7 +674,7 @@
584674
585675
586def cmp_pkgrevno(package, revno, pkgcache=None):676def cmp_pkgrevno(package, revno, pkgcache=None):
587 '''Compare supplied revno with the revno of the installed package677 """Compare supplied revno with the revno of the installed package
588678
589 * 1 => Installed revno is greater than supplied arg679 * 1 => Installed revno is greater than supplied arg
590 * 0 => Installed revno is the same as supplied arg680 * 0 => Installed revno is the same as supplied arg
@@ -593,7 +683,7 @@
593 This function imports apt_cache function from charmhelpers.fetch if683 This function imports apt_cache function from charmhelpers.fetch if
594 the pkgcache argument is None. Be sure to add charmhelpers.fetch if684 the pkgcache argument is None. Be sure to add charmhelpers.fetch if
595 you call this function, or pass an apt_pkg.Cache() instance.685 you call this function, or pass an apt_pkg.Cache() instance.
596 '''686 """
597 import apt_pkg687 import apt_pkg
598 if not pkgcache:688 if not pkgcache:
599 from charmhelpers.fetch import apt_cache689 from charmhelpers.fetch import apt_cache
@@ -603,19 +693,27 @@
603693
604694
605@contextmanager695@contextmanager
606def chdir(d):696def chdir(directory):
697 """Change the current working directory to a different directory for a code
698 block and return the previous directory after the block exits. Useful to
699 run commands from a specificed directory.
700
701 :param str directory: The directory path to change to for this context.
702 """
607 cur = os.getcwd()703 cur = os.getcwd()
608 try:704 try:
609 yield os.chdir(d)705 yield os.chdir(directory)
610 finally:706 finally:
611 os.chdir(cur)707 os.chdir(cur)
612708
613709
614def chownr(path, owner, group, follow_links=True, chowntopdir=False):710def chownr(path, owner, group, follow_links=True, chowntopdir=False):
615 """711 """Recursively change user and group ownership of files and directories
616 Recursively change user and group ownership of files and directories
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.
618713
714 :param str path: The string path to start changing ownership.
715 :param str owner: The owner string to use when looking up the uid.
716 :param str group: The group string to use when looking up the gid.
619 :param bool follow_links: Also Chown links if True717 :param bool follow_links: Also Chown links if True
620 :param bool chowntopdir: Also chown path itself if True718 :param bool chowntopdir: Also chown path itself if True
621 """719 """
@@ -639,15 +737,23 @@
639737
640738
641def lchownr(path, owner, group):739def lchownr(path, owner, group):
740 """Recursively change user and group ownership of files and directories
741 in a given path, not following symbolic links. See the documentation for
742 'os.lchown' for more information.
743
744 :param str path: The string path to start changing ownership.
745 :param str owner: The owner string to use when looking up the uid.
746 :param str group: The group string to use when looking up the gid.
747 """
642 chownr(path, owner, group, follow_links=False)748 chownr(path, owner, group, follow_links=False)
643749
644750
645def get_total_ram():751def get_total_ram():
646 '''The total amount of system RAM in bytes.752 """The total amount of system RAM in bytes.
647753
648 This is what is reported by the OS, and may be overcommitted when754 This is what is reported by the OS, and may be overcommitted when
649 there are multiple containers hosted on the same machine.755 there are multiple containers hosted on the same machine.
650 '''756 """
651 with open('/proc/meminfo', 'r') as f:757 with open('/proc/meminfo', 'r') as f:
652 for line in f.readlines():758 for line in f.readlines():
653 if line:759 if line:
654760
=== modified file 'charmhelpers/fetch/__init__.py'
--- charmhelpers/fetch/__init__.py 2016-01-11 18:16:28 +0000
+++ charmhelpers/fetch/__init__.py 2016-06-10 10:55:43 +0000
@@ -106,6 +106,14 @@
106 'mitaka/proposed': 'trusty-proposed/mitaka',106 'mitaka/proposed': 'trusty-proposed/mitaka',
107 'trusty-mitaka/proposed': 'trusty-proposed/mitaka',107 'trusty-mitaka/proposed': 'trusty-proposed/mitaka',
108 'trusty-proposed/mitaka': 'trusty-proposed/mitaka',108 'trusty-proposed/mitaka': 'trusty-proposed/mitaka',
109 # Newton
110 'newton': 'xenial-updates/newton',
111 'xenial-newton': 'xenial-updates/newton',
112 'xenial-newton/updates': 'xenial-updates/newton',
113 'xenial-updates/newton': 'xenial-updates/newton',
114 'newton/proposed': 'xenial-proposed/newton',
115 'xenial-newton/proposed': 'xenial-proposed/newton',
116 'xenial-proposed/newton': 'xenial-proposed/newton',
109}117}
110118
111# The order of this list is very important. Handlers should be listed in from119# The order of this list is very important. Handlers should be listed in from
112120
=== modified file 'charmhelpers/fetch/giturl.py'
--- charmhelpers/fetch/giturl.py 2016-01-11 18:16:28 +0000
+++ charmhelpers/fetch/giturl.py 2016-06-10 10:55:43 +0000
@@ -15,7 +15,7 @@
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/>.
1616
17import os17import os
18from subprocess import check_call18from subprocess import check_call, CalledProcessError
19from charmhelpers.fetch import (19from charmhelpers.fetch import (
20 BaseFetchHandler,20 BaseFetchHandler,
21 UnhandledSource,21 UnhandledSource,
@@ -63,6 +63,8 @@
63 branch_name)63 branch_name)
64 try:64 try:
65 self.clone(source, dest_dir, branch, depth)65 self.clone(source, dest_dir, branch, depth)
66 except CalledProcessError as e:
67 raise UnhandledSource(e)
66 except OSError as e:68 except OSError as e:
67 raise UnhandledSource(e.strerror)69 raise UnhandledSource(e.strerror)
68 return dest_dir70 return dest_dir

Subscribers

People subscribed via source and target branches

to all changes: