Permalink
| from charmhelpers.cli import cmdline | |
| from charmhelpers.core import unitdata | |
| from charms.reactive.bus import FlagWatch | |
| __all__ = [ | |
| 'set_flag', | |
| 'clear_flag', | |
| 'toggle_flag', | |
| 'register_trigger', | |
| 'is_flag_set', | |
| 'all_flags_set', | |
| 'any_flags_set', | |
| 'set_state', # DEPRECATED | |
| 'remove_state', # DEPRECATED | |
| 'toggle_state', # DEPRECATED | |
| 'is_state', # DEPRECATED | |
| 'all_states', # DEPRECATED | |
| 'get_states', # DEPRECATED | |
| 'any_states', # DEPRECATED | |
| ] | |
| class State(str): | |
| """ | |
| .. deprecated:: 0.5.0 | |
| Use flag instead | |
| A reactive state that can be set. | |
| States are essentially just strings, but this class should be used to enable them | |
| to be discovered and introspected, for documentation, composition, or linting. | |
| This should be used with :class:`StateList`. | |
| """ | |
| pass | |
| class StateList(object): | |
| """ | |
| .. deprecated:: 0.5.0 | |
| use flag instead | |
| Base class for a set of states that can be set by a relation or layer. | |
| This class should be used so that they can be discovered and introspected, | |
| for documentation, composition, or linting. | |
| Example usage:: | |
| class MyRelation(RelationBase): | |
| class states(StateList): | |
| connected = State('{relation_name}.connected') | |
| available = State('{relation_name}.available') | |
| """ | |
| pass | |
| @cmdline.subcommand() | |
| @cmdline.no_output | |
| def set_flag(flag, value=None): | |
| """set_flag(flag) | |
| Set the given flag as active. | |
| :param str flag: Name of flag to set. | |
| .. note:: **Changes to flags are reset when a handler crashes.** Changes to | |
| flags happen immediately, but they are only persisted at the end of a | |
| complete and successful run of the reactive framework. All unpersisted | |
| changes are discarded when a hook crashes. | |
| """ | |
| old_flags = get_flags() | |
| unitdata.kv().update({flag: value}, prefix='reactive.states.') | |
| if flag not in old_flags: | |
| FlagWatch.change(flag) | |
| trigger = _get_trigger(flag) | |
| for flag_name in trigger['set_flag']: | |
| set_flag(flag_name) | |
| for flag_name in trigger['clear_flag']: | |
| clear_flag(flag_name) | |
| @cmdline.subcommand() | |
| @cmdline.no_output | |
| def clear_flag(flag): | |
| """ | |
| Clear / deactivate a flag. | |
| :param str flag: Name of flag to set. | |
| .. note:: **Changes to flags are reset when a handler crashes.** Changes to | |
| flags happen immediately, but they are only persisted at the end of a | |
| complete and successful run of the reactive framework. All unpersisted | |
| changes are discarded when a hook crashes. | |
| """ | |
| old_flags = get_flags() | |
| unitdata.kv().unset('reactive.states.%s' % flag) | |
| unitdata.kv().set('reactive.dispatch.removed_state', True) | |
| if flag in old_flags: | |
| FlagWatch.change(flag) | |
| @cmdline.subcommand() | |
| @cmdline.no_output | |
| def toggle_flag(flag, should_set): | |
| """ | |
| Helper that calls either :func:`set_flag` or :func:`clear_flag`, | |
| depending on the value of `should_set`. | |
| Equivalent to:: | |
| if should_set: | |
| set_flag(flag) | |
| else: | |
| clear_flag(flag) | |
| :param str flag: Name of flag to toggle. | |
| :param bool should_set: Whether to set the flag, or clear it. | |
| .. note:: **Changes to flags are reset when a handler crashes.** Changes to | |
| flags happen immediately, but they are only persisted at the end of a | |
| complete and successful run of the reactive framework. All unpersisted | |
| changes are discarded when a hook crashes. | |
| """ | |
| if should_set: | |
| set_flag(flag) | |
| else: | |
| clear_flag(flag) | |
| @cmdline.subcommand() | |
| @cmdline.no_output | |
| def register_trigger(when, set_flag=None, clear_flag=None): | |
| """ | |
| Register a trigger to set or clear a flag when a given flag is set. | |
| Note: Flag triggers are handled at the same time that the given flag is set. | |
| :param str when: Flag to trigger on. | |
| :param str set_flag: If given, this flag will be set when `when` is set. | |
| :param str clear_flag: If given, this flag will be cleared when `when` is set. | |
| """ | |
| trigger = _get_trigger(when) | |
| if set_flag and set_flag not in trigger['set_flag']: | |
| trigger['set_flag'].append(set_flag) | |
| if clear_flag and clear_flag not in trigger['clear_flag']: | |
| trigger['clear_flag'].append(clear_flag) | |
| _save_trigger(when, trigger) | |
| def _get_trigger(when): | |
| key = 'reactive.flag_triggers.{}'.format(when) | |
| return unitdata.kv().get(key, { | |
| 'set_flag': [], | |
| 'clear_flag': [], | |
| }) | |
| def _save_trigger(when, data): | |
| key = 'reactive.flag_triggers.{}'.format(when) | |
| return unitdata.kv().set(key, data) | |
| @cmdline.subcommand() | |
| @cmdline.test_command | |
| def is_flag_set(flag): | |
| """Assert that a flag is set""" | |
| return any_flags_set(flag) | |
| @cmdline.subcommand() | |
| @cmdline.test_command | |
| def all_flags_set(*desired_flags): | |
| """Assert that all desired_flags are set""" | |
| active_flags = get_flags() | |
| return all(flag in active_flags for flag in desired_flags) | |
| @cmdline.subcommand() | |
| @cmdline.test_command | |
| def any_flags_set(*desired_flags): | |
| """Assert that any of the desired_flags are set""" | |
| active_flags = get_flags() | |
| return any(flag in active_flags for flag in desired_flags) | |
| @cmdline.subcommand() | |
| def get_flags(): | |
| """ | |
| Return a list of all flags which are set. | |
| """ | |
| flags = unitdata.kv().getrange('reactive.states.', strip=True) or {} | |
| return sorted(flags.keys()) | |
| def _get_flag_value(flag, default=None): | |
| return unitdata.kv().get('reactive.states.%s' % flag, default) | |
| # DEPRECATED | |
| @cmdline.subcommand() | |
| @cmdline.no_output | |
| def set_state(state, value=None): | |
| """ | |
| .. deprecated:: 0.5.0 | |
| Alias of :func:`set_flag`. | |
| """ | |
| set_flag(state, value) | |
| @cmdline.subcommand() | |
| @cmdline.no_output | |
| def remove_state(state): | |
| """ | |
| .. deprecated:: 0.5.0 | |
| Alias of :func:`clear_flag`""" | |
| clear_flag(state) | |
| def toggle_state(state, should_set): | |
| """ | |
| .. deprecated:: 0.5.0 | |
| Alias of :func:`toggle_flag`""" | |
| toggle_flag(state, should_set) | |
| @cmdline.subcommand() | |
| @cmdline.test_command | |
| def is_state(state): | |
| """ | |
| .. deprecated:: 0.5.0 | |
| Alias for :func:`is_flag_set`""" | |
| return is_flag_set(state) | |
| @cmdline.subcommand() | |
| @cmdline.test_command | |
| def all_states(*desired_states): | |
| """ | |
| .. deprecated:: 0.5.0 | |
| Alias for :func:`all_flags_set`""" | |
| return all_flags_set(*desired_states) | |
| @cmdline.subcommand() | |
| @cmdline.test_command | |
| def any_states(*desired_states): | |
| """ | |
| .. deprecated:: 0.5.0 | |
| Alias for :func:`any_flags_set`""" | |
| return any_flags_set(*desired_states) | |
| @cmdline.subcommand() | |
| def get_states(): | |
| """ | |
| .. deprecated:: 0.5.0 | |
| Use :func:`get_flags` instead. | |
| Return a mapping of all active states to their values. | |
| """ | |
| return unitdata.kv().getrange('reactive.states.', strip=True) or {} | |
| def get_state(flag, default=None): | |
| """ | |
| .. deprecated:: 0.5.0 | |
| For internal use only. | |
| """ | |
| return _get_flag_value(flag, default) |