def _wrapped(*args, **kwargs): active_flags = get_flags() missing_flags = [flag for flag in desired_flags if flag not in active_flags] if missing_flags: hookenv.log('%s called before flag%s: %s' % ( short_action_id, 's' if len(missing_flags) > 1 else '', ', '.join(missing_flags)), hookenv.WARNING) return func(*args, **kwargs)
def render_configs(self, configs, adapters_instance=None): """Render the configuration files identified in the list passed as configs. Configs may not only be loaded via OpenStack loaders but also via string templates passed via config options or from relation data. This must be explicitly declared via string_templates dict of a given derived charm class by using a relation name that identifies a relation adapter or config option adapter and a property to be used from that adapter instance. :param configs: list of strings, the names of the configuration files. :param adapters_instance: [optional] the adapters_instance to use. """ if adapters_instance is None: interfaces = [] for f in flags.get_flags(): ep_from_f = relations.endpoint_from_flag(f) if ep_from_f: interfaces.append(ep_from_f) try: adapters_instance = self.adapters_class(interfaces, charm_instance=self) except TypeError: adapters_instance = self.adapters_class(interfaces) with self.restart_on_change(): for conf in configs: # check if we need to load a template from a string config_template = self._get_string_template( conf, adapters_instance) if config_template is False: # got a string template but it was not provided which # means we need to skip this config to avoid rendering return charmhelpers.core.templating.render( source=os.path.basename(conf), template_loader=os_templating.get_loader( 'templates/', self.release), target=conf, context=adapters_instance, config_template=config_template, group=self.group, perms=0o640, )
def _migrate_conversations(): # noqa """ Due to issue #28 (https://github.com/juju-solutions/charms.reactive/issues/28), conversations needed to be updated to be namespaced per relation ID for SERVICE and UNIT scope. To ensure backwards compatibility, this updates all convs in the old format to the new. TODO: Remove in 2.0.0 """ for key, data in unitdata.kv().getrange('reactive.conversations.').items(): if 'local-data' in key: continue if 'namespace' in data: continue relation_name = data.pop('relation_name') if data['scope'] == scopes.GLOBAL: data['namespace'] = relation_name unitdata.kv().set(key, data) else: # split the conv based on the relation ID new_keys = [] for rel_id in hookenv.relation_ids(relation_name): new_key = Conversation._key(rel_id, data['scope']) new_units = set(hookenv.related_units(rel_id)) & set( data['units']) if new_units: unitdata.kv().set( new_key, { 'namespace': rel_id, 'scope': data['scope'], 'units': sorted(new_units), }) new_keys.append(new_key) unitdata.kv().unset(key) # update the states pointing to the old conv key to point to the # (potentially multiple) new key(s) for flag in get_flags(): value = _get_flag_value(flag) if not value: continue if key not in value['conversations']: continue value['conversations'].remove(key) value['conversations'].extend(new_keys) set_flag(flag, value)
def test_get_unset_flags(self): self.assertEqual(flags.get_flags(), []) flags.set_flag('foo') self.assertEqual(flags.get_flags(), ['foo']) self.assertEqual(flags.get_unset_flags('foo', 'bar'), ['bar'])
def installed(): '''Return the set of deb packages completed install''' return set( flag.split('.', 2)[2] for flag in flags.get_flags() if flag.startswith('apt.installed.'))