1
"Interactions with the Juju environment"
2
# source: 27:lp:charmsupport
3
# Copyright 2012 Canonical Ltd.
6
# Matthew Wedgwood <matthew.wedgwood@canonical.com>
18
def log(message, level=DEBUG):
19
"Write a message to the juju log"
20
subprocess.call( [ 'juju-log', '-l', level, message ] )
22
class Serializable(object):
23
"Wrapper, an object that can be serialized to yaml or json"
24
def __init__(self, obj):
26
super(Serializable, self).__init__()
27
self._wrapped_obj = obj
29
def __getattr__(self, attr):
30
# see if this object has attr
31
if attr in self.__dict__:
32
return getattr(self, attr)
33
# proxy to the wrapped object
36
def __getitem__(self, key):
37
return self._wrapped_obj[key]
40
"Serialize the object to json"
41
return json.dumps(self._wrapped_obj)
44
"Serialize the object to yaml"
45
return yaml.dump(self._wrapped_obj)
47
def execution_environment():
48
"""A convenient bundling of the current execution context"""
50
context['conf'] = config()
51
context['unit'] = local_unit()
52
context['rel'] = relations_of_type()
53
context['env'] = os.environ
56
def in_relation_hook():
57
"Determine whether we're running in a relation hook"
58
return os.environ.has_key('JUJU_RELATION')
61
"The scope for the current relation hook"
62
return os.environ['JUJU_RELATION']
64
"The relation ID for the current relation hook"
65
return os.environ['JUJU_RELATION_ID']
68
return os.environ['JUJU_UNIT_NAME']
70
"The remote unit for the current relation hook"
71
return os.environ['JUJU_REMOTE_UNIT']
73
def config(scope=None):
74
"Juju charm configuration"
75
config_cmd_line = ['config-get']
77
config_cmd_line.append(scope)
78
config_cmd_line.append('--format=json')
80
config_data = json.loads(subprocess.check_output(config_cmd_line))
81
except (ValueError, OSError, subprocess.CalledProcessError) as err:
82
log(str(err), level=ERROR)
84
return Serializable(config_data)
86
def relation_ids(reltype=None):
87
"A list of relation_ids"
88
reltype = reltype or relation_type()
90
relid_cmd_line = ['relation-ids', '--format=json', reltype]
91
relids.extend(json.loads(subprocess.check_output(relid_cmd_line)))
94
def related_units(relid=None):
95
"A list of related units"
96
relid = relid or relation_id()
97
units_cmd_line = ['relation-list', '--format=json', '-r', relid]
98
units = json.loads(subprocess.check_output(units_cmd_line))
101
def relation_for_unit(unit=None):
102
"Get the json represenation of a unit's relation"
103
unit = unit or remote_unit()
104
relation_cmd_line = ['relation-get', '--format=json', '-', unit]
106
relation = json.loads(subprocess.check_output(relation_cmd_line))
107
except (ValueError, OSError, subprocess.CalledProcessError), err:
108
log(str(err), level=ERROR)
111
if key.endswith('-list'):
112
relation[key] = relation[key].split()
113
relation['__unit__'] = unit
114
return Serializable(relation)
116
def relations_for_id(relid=None):
117
"Get relations of a specific relation ID"
119
relid = relid or relation_ids()
120
for unit in related_units(relid):
121
unit_data = relation_for_unit(unit)
122
unit_data['__relid__'] = relid
123
relation_data.append(unit_data)
126
def relations_of_type(reltype=None):
127
"Get relations of a specific type"
129
if in_relation_hook():
130
reltype = reltype or relation_type()
131
for relid in relation_ids(reltype):
132
for relation in relations_for_id(relid):
133
relation['__relid__'] = relid
134
relation_data.append(relation)
137
class UnregisteredHookError(Exception): pass
141
super(Hooks, self).__init__()
143
def register(self, name, function):
144
self._hooks[name] = function
145
def execute(self, args):
146
hook_name = os.path.basename(args[0])
147
if hook_name in self._hooks:
148
self._hooks[hook_name]()
150
raise UnregisteredHookError(hook_name)