auto sync charmhelpers

This commit is contained in:
Ryan Beisner 2015-04-16 21:32:48 +00:00
parent 785a2a7b4c
commit 111e186e38
7 changed files with 82 additions and 11 deletions

View File

@ -20,11 +20,13 @@
# Authors: # Authors:
# Charm Helpers Developers <juju@lists.ubuntu.com> # Charm Helpers Developers <juju@lists.ubuntu.com>
from __future__ import print_function
import os import os
import json import json
import yaml import yaml
import subprocess import subprocess
import sys import sys
import errno
from subprocess import CalledProcessError from subprocess import CalledProcessError
import six import six
@ -87,7 +89,18 @@ def log(message, level=None):
if not isinstance(message, six.string_types): if not isinstance(message, six.string_types):
message = repr(message) message = repr(message)
command += [message] command += [message]
subprocess.call(command) # Missing juju-log should not cause failures in unit tests
# Send log output to stderr
try:
subprocess.call(command)
except OSError as e:
if e.errno == errno.ENOENT:
if level:
message = "{}: {}".format(level, message)
message = "juju-log: {}".format(message)
print(message, file=sys.stderr)
else:
raise
class Serializable(UserDict): class Serializable(UserDict):
@ -566,3 +579,29 @@ class Hooks(object):
def charm_dir(): def charm_dir():
"""Return the root directory of the current charm""" """Return the root directory of the current charm"""
return os.environ.get('CHARM_DIR') return os.environ.get('CHARM_DIR')
@cached
def action_get(key=None):
"""Gets the value of an action parameter, or all key/value param pairs"""
cmd = ['action-get']
if key is not None:
cmd.append(key)
cmd.append('--format=json')
action_data = json.loads(subprocess.check_output(cmd).decode('UTF-8'))
return action_data
def action_set(values):
"""Sets the values to be returned after the action finishes"""
cmd = ['action-set']
for k, v in list(values.items()):
cmd.append('{}={}'.format(k, v))
subprocess.check_call(cmd)
def action_fail(message):
"""Sets the action status to failed and sets the error message.
The results set by action_set are preserved."""
subprocess.check_call(['action-fail', message])

View File

@ -339,12 +339,16 @@ def lsb_release():
def pwgen(length=None): def pwgen(length=None):
"""Generate a random pasword.""" """Generate a random pasword."""
if length is None: if length is None:
# A random length is ok to use a weak PRNG
length = random.choice(range(35, 45)) length = random.choice(range(35, 45))
alphanumeric_chars = [ alphanumeric_chars = [
l for l in (string.ascii_letters + string.digits) l for l in (string.ascii_letters + string.digits)
if l not in 'l0QD1vAEIOUaeiou'] if l not in 'l0QD1vAEIOUaeiou']
# Use a crypto-friendly PRNG (e.g. /dev/urandom) for making the
# actual password
random_generator = random.SystemRandom()
random_chars = [ random_chars = [
random.choice(alphanumeric_chars) for _ in range(length)] random_generator.choice(alphanumeric_chars) for _ in range(length)]
return(''.join(random_chars)) return(''.join(random_chars))

View File

@ -139,7 +139,7 @@ class MysqlRelation(RelationContext):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.required_keys = ['host', 'user', 'password', 'database'] self.required_keys = ['host', 'user', 'password', 'database']
super(HttpRelation).__init__(self, *args, **kwargs) RelationContext.__init__(self, *args, **kwargs)
class HttpRelation(RelationContext): class HttpRelation(RelationContext):
@ -154,7 +154,7 @@ class HttpRelation(RelationContext):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.required_keys = ['host', 'port'] self.required_keys = ['host', 'port']
super(HttpRelation).__init__(self, *args, **kwargs) RelationContext.__init__(self, *args, **kwargs)
def provide_data(self): def provide_data(self):
return { return {

View File

@ -33,9 +33,9 @@ def bool_from_string(value):
value = value.strip().lower() value = value.strip().lower()
if value in ['y', 'yes', 'true', 't']: if value in ['y', 'yes', 'true', 't', 'on']:
return True return True
elif value in ['n', 'no', 'false', 'f']: elif value in ['n', 'no', 'false', 'f', 'off']:
return False return False
msg = "Unable to interpret string value '%s' as boolean" % (value) msg = "Unable to interpret string value '%s' as boolean" % (value)

View File

@ -443,7 +443,7 @@ class HookData(object):
data = hookenv.execution_environment() data = hookenv.execution_environment()
self.conf = conf_delta = self.kv.delta(data['conf'], 'config') self.conf = conf_delta = self.kv.delta(data['conf'], 'config')
self.rels = rels_delta = self.kv.delta(data['rels'], 'rels') self.rels = rels_delta = self.kv.delta(data['rels'], 'rels')
self.kv.set('env', data['env']) self.kv.set('env', dict(data['env']))
self.kv.set('unit', data['unit']) self.kv.set('unit', data['unit'])
self.kv.set('relid', data.get('relid')) self.kv.set('relid', data.get('relid'))
return conf_delta, rels_delta return conf_delta, rels_delta

View File

@ -118,6 +118,9 @@ class AmuletUtils(object):
longs, or can be a function that evaluate a variable and returns a longs, or can be a function that evaluate a variable and returns a
bool. bool.
""" """
self.log.debug('actual: {}'.format(repr(actual)))
self.log.debug('expected: {}'.format(repr(expected)))
for k, v in six.iteritems(expected): for k, v in six.iteritems(expected):
if k in actual: if k in actual:
if (isinstance(v, six.string_types) or if (isinstance(v, six.string_types) or
@ -134,7 +137,6 @@ class AmuletUtils(object):
def validate_relation_data(self, sentry_unit, relation, expected): def validate_relation_data(self, sentry_unit, relation, expected):
"""Validate actual relation data based on expected relation data.""" """Validate actual relation data based on expected relation data."""
actual = sentry_unit.relation(relation[0], relation[1]) actual = sentry_unit.relation(relation[0], relation[1])
self.log.debug('actual: {}'.format(repr(actual)))
return self._validate_dict_data(expected, actual) return self._validate_dict_data(expected, actual)
def _validate_list_data(self, expected, actual): def _validate_list_data(self, expected, actual):

View File

@ -15,6 +15,7 @@
# along with charm-helpers. If not, see <http://www.gnu.org/licenses/>. # along with charm-helpers. If not, see <http://www.gnu.org/licenses/>.
import six import six
from collections import OrderedDict
from charmhelpers.contrib.amulet.deployment import ( from charmhelpers.contrib.amulet.deployment import (
AmuletDeployment AmuletDeployment
) )
@ -43,7 +44,7 @@ class OpenStackAmuletDeployment(AmuletDeployment):
Determine if the local branch being tested is derived from its Determine if the local branch being tested is derived from its
stable or next (dev) branch, and based on this, use the corresonding stable or next (dev) branch, and based on this, use the corresonding
stable or next branches for the other_services.""" stable or next branches for the other_services."""
base_charms = ['mysql', 'mongodb', 'rabbitmq-server'] base_charms = ['mysql', 'mongodb']
if self.stable: if self.stable:
for svc in other_services: for svc in other_services:
@ -100,12 +101,37 @@ class OpenStackAmuletDeployment(AmuletDeployment):
""" """
(self.precise_essex, self.precise_folsom, self.precise_grizzly, (self.precise_essex, self.precise_folsom, self.precise_grizzly,
self.precise_havana, self.precise_icehouse, self.precise_havana, self.precise_icehouse,
self.trusty_icehouse) = range(6) self.trusty_icehouse, self.trusty_juno, self.trusty_kilo,
self.utopic_juno, self.vivid_kilo) = range(10)
releases = { releases = {
('precise', None): self.precise_essex, ('precise', None): self.precise_essex,
('precise', 'cloud:precise-folsom'): self.precise_folsom, ('precise', 'cloud:precise-folsom'): self.precise_folsom,
('precise', 'cloud:precise-grizzly'): self.precise_grizzly, ('precise', 'cloud:precise-grizzly'): self.precise_grizzly,
('precise', 'cloud:precise-havana'): self.precise_havana, ('precise', 'cloud:precise-havana'): self.precise_havana,
('precise', 'cloud:precise-icehouse'): self.precise_icehouse, ('precise', 'cloud:precise-icehouse'): self.precise_icehouse,
('trusty', None): self.trusty_icehouse} ('trusty', None): self.trusty_icehouse,
('trusty', 'cloud:trusty-juno'): self.trusty_juno,
('trusty', 'cloud:trusty-kilo'): self.trusty_kilo,
('utopic', None): self.utopic_juno,
('vivid', None): self.vivid_kilo}
return releases[(self.series, self.openstack)] return releases[(self.series, self.openstack)]
def _get_openstack_release_string(self):
"""Get openstack release string.
Return a string representing the openstack release.
"""
releases = OrderedDict([
('precise', 'essex'),
('quantal', 'folsom'),
('raring', 'grizzly'),
('saucy', 'havana'),
('trusty', 'icehouse'),
('utopic', 'juno'),
('vivid', 'kilo'),
])
if self.openstack:
os_origin = self.openstack.split(':')[1]
return os_origin.split('%s-' % self.series)[1].split('/')[0]
else:
return releases[self.series]