155
155
return os.path.basename(sys.argv[0])
159
"""A dictionary representation of the charm's config.yaml, with some
162
- See which values in the dictionary have changed since the previous hook.
163
- For values that have changed, see what the previous value was.
164
- Store arbitrary data for use in a later hook.
166
NOTE: Do not instantiate this object directly - instead call
167
``hookenv.config()``, which will return an instance of :class:`Config`.
172
>>> from charmhelpers.core import hookenv
173
>>> config = hookenv.config()
176
>>> # store a new key/value for later use
177
>>> config['mykey'] = 'myval'
180
>>> # user runs `juju set mycharm foo=baz`
181
>>> # now we're inside subsequent config-changed hook
182
>>> config = hookenv.config()
185
>>> # test to see if this val has changed since last hook
186
>>> config.changed('foo')
188
>>> # what was the previous value?
189
>>> config.previous('foo')
191
>>> # keys/values that we add are preserved across hooks
196
CONFIG_FILE_NAME = '.juju-persistent-config'
198
def __init__(self, *args, **kw):
199
super(Config, self).__init__(*args, **kw)
200
self.implicit_save = True
201
self._prev_dict = None
202
self.path = os.path.join(charm_dir(), Config.CONFIG_FILE_NAME)
203
if os.path.exists(self.path):
206
def __getitem__(self, key):
207
"""For regular dict lookups, check the current juju config first,
208
then the previous (saved) copy. This ensures that user-saved values
209
will be returned by a dict lookup.
213
return dict.__getitem__(self, key)
215
return (self._prev_dict or {})[key]
219
if self._prev_dict is not None:
220
prev_keys = self._prev_dict.keys()
221
return list(set(prev_keys + dict.keys(self)))
223
def load_previous(self, path=None):
224
"""Load previous copy of config from disk.
226
In normal usage you don't need to call this method directly - it
227
is called automatically at object initialization.
231
File path from which to load the previous config. If `None`,
232
config is loaded from the default location. If `path` is
233
specified, subsequent `save()` calls will write to the same
237
self.path = path or self.path
238
with open(self.path) as f:
239
self._prev_dict = json.load(f)
241
def changed(self, key):
242
"""Return True if the current value for this key is different from
246
if self._prev_dict is None:
248
return self.previous(key) != self.get(key)
250
def previous(self, key):
251
"""Return previous value for this key, or None if there
252
is no previous value.
256
return self._prev_dict.get(key)
260
"""Save this config to disk.
262
If the charm is using the :mod:`Services Framework <services.base>`
263
or :meth:'@hook <Hooks.hook>' decorator, this
264
is called automatically at the end of successful hook execution.
265
Otherwise, it should be called directly by user code.
267
To disable automatic saves, set ``implicit_save=False`` on this
272
for k, v in self._prev_dict.iteritems():
275
with open(self.path, 'w') as f:
159
280
def config(scope=None):
160
281
"""Juju charm configuration"""
348
473
class Hooks(object):
349
474
"""A convenient handler for hook functions.
354
480
# register a hook, taking its name from the function name
483
pass # your code here
359
485
# register a hook, providing a custom hook name
360
486
@hooks.hook("config-changed")
361
487
def config_changed():
488
pass # your code here
364
490
if __name__ == "__main__":
365
491
# execute a hook based on the name the program is called by
366
492
hooks.execute(sys.argv)
495
def __init__(self, config_save=True):
370
496
super(Hooks, self).__init__()
498
self._config_save = config_save
373
500
def register(self, name, function):
374
501
"""Register a hook"""