def render_config(self, *args): """ Render Kerberos configuration file and Apache configuration to be used by Keystone. """ # ensure that a directory we need is there ch_host.mkdir(APACHE_LOCATION) self.render_configs(self.string_templates.keys()) core.templating.render( source=APACHE_CONF_TEMPLATE, template_loader=os_templating.get_loader( 'templates/', self.release), target='{}/{}'.format(APACHE_LOCATION, APACHE_CONF_TEMPLATE), context=self.adapters_class(args, charm_instance=self), ) core.templating.render( source=KERBEROS_CONF_TEMPLATE, template_loader=os_templating.get_loader( 'templates/', self.release), target="/etc/krb5.conf", context=self.adapters_class(args, charm_instance=self), )
def install(self): """Custom install function. :param self: Self :type self: MySQLRouterCharm instance :side effect: Executes other functions :returns: This function is called for its side effect :rtype: None """ # TODO: charms.openstack should probably do this # Need to configure source first self.configure_source() super().install() # Neither MySQL Router nor MySQL common packaging creates a user, group # or home dir. As we want it to run as a system user in a predictable # location create all of these. # Create the group if not ch_core.host.group_exists(self.mysqlrouter_group): ch_core.host.add_group( self.mysqlrouter_group, system_group=True) # Create the user if not ch_core.host.user_exists(self.mysqlrouter_user): ch_core.host.adduser( self.mysqlrouter_user, shell="/usr/sbin/nologin", system_user=True, primary_group=self.mysqlrouter_group, home_dir=self.mysqlrouter_home_dir) # Create the directory if not os.path.exists(self.mysqlrouter_home_dir): ch_core.host.mkdir( self.mysqlrouter_home_dir, owner=self.mysqlrouter_user, group=self.mysqlrouter_group, perms=0o755) # Systemd File ch_core.templating.render( source="mysqlrouter.service", template_loader=os_templating.get_loader( 'templates/', self.release), target=self.systemd_file, context=self.adapters_instance, group=self.group, perms=0o755, ) cmd = ["systemctl", "enable", self.name] subprocess.check_output(cmd, stderr=subprocess.STDOUT) # Logrotate File ch_core.templating.render( source="logrotate", template_loader=os_templating.get_loader( "templates/", self.release), target=self.logrotate_file, context={ "owner": self.mysqlrouter_user, "group": self.mysqlrouter_group }, perms=0o644, )
def manage(): config = hookenv.config() release = os_release('neutron-common') manager = ServiceManager([ # Actions which have no prerequisites and can be rerun { 'service': 'odl-setup', 'data_ready': [ odl_utils.install_packages, ], 'provided_data': [ odl_data.NeutronApiSDNRelation(), ], }, { 'service': 'api-render', 'required_data': [ odl_data.ODLControllerRelation(), config, odl_data.ConfigTranslation(), ], 'data_ready': [ helpers.render_template( source='ml2_conf.ini', template_loader=get_loader('templates/', release), target='/etc/neutron/plugins/ml2/ml2_conf.ini', on_change_action=(partial(remote_restart, 'neutron-plugin-api-subordinate', 'neutron-server')), ), ] }, ]) manager.manage()
def render_config(self, restart_trigger): """Render the domain specific LDAP configuration for the application """ checksum = ch_host.file_hash(self.configuration_file) core.templating.render(source=KEYSTONE_CONF_TEMPLATE, template_loader=os_templating.get_loader( 'templates/', self.release), target=self.configuration_file, context=self.adapters_instance) tmpl_changed = (checksum != ch_host.file_hash(self.configuration_file)) cert = hookenv.config('tls-ca-ldap') cert_changed = False if cert: ca_file = self.options.backend_ca_file old_cert_csum = ch_host.file_hash(ca_file) ch_host.write_file(ca_file, cert, owner='root', group='root', perms=0o644) cert_csum = ch_host.file_hash(ca_file) cert_changed = (old_cert_csum != cert_csum) if tmpl_changed or cert_changed: restart_trigger()
def manage(): config = hookenv.config() release = os_release('neutron-common') manager = ServiceManager([ # onos services setup { 'service': 'onos-setup', 'data_ready': [ onos_package.install_packages, ], 'provided_data': [ onos_relation.BuildSDNRelation(), ], }, { 'service': 'api-render', 'required_data': [ onos_relation.ONOSControllerRelation(), config, onos_relation.ConfigTranslation(), ], 'data_ready': [ helpers.render_template( source='ml2_conf.ini', template_loader=get_loader('templates/', release), target='/etc/neutron/plugins/ml2/ml2_conf.ini', on_change_action=(partial( remote_restart, 'neutron-plugin-api-subordinate', 'neutron-server')), ), ], }, ]) manager.manage()
def manage(): config = hookenv.config() release = os_release('neutron-common') manager = ServiceManager([ # onos services setup { 'service': 'onos-setup', 'data_ready': [ onos_package.install_packages, ], 'provided_data': [ onos_relation.BuildSDNRelation(), ], }, { 'service': 'api-render', 'required_data': [ onos_relation.ONOSControllerRelation(), config, onos_relation.ConfigTranslation(), ], 'data_ready': [ helpers.render_template( source='ml2_conf.ini', template_loader=get_loader('templates/', release), target='/etc/neutron/plugins/ml2/ml2_conf.ini', on_change_action=(partial(remote_restart, 'neutron-plugin-api-subordinate', 'neutron-server')), ), ], }, ]) manager.manage()
def render_configs(self, configs): with self.restart_on_change(): for conf in configs: render(source=os.path.basename(conf), template_loader=get_loader('templates/', self.release), target=conf, context=self.adapter_instance)
def render_config(self, *args): """ Render Service Provider configuration file to be used by Apache and provided to idP out of band to establish mutual trust. """ owner = 'root' group = 'www-data' # group read and exec is needed for mellon to read the rendered # files, otherwise it will fail in a cryptic way dperms = 0o650 # file permissions are a bit more restrictive than defaults in # charm-helpers but directory permissions are the main protection # mechanism in this case fileperms = 0o440 # ensure that a directory we need is there ch_host.mkdir('/etc/apache2/mellon', perms=dperms, owner=owner, group=group) self.render_configs(self.string_templates.keys()) # For now the template name does not match # basename(file_path/file_name). This is necessary to enable multiple # instantiations of keystone-saml-mellon using service_name() in the # file names. So not using self.render_with_interfaces(args) # TODO: Make a mapping mechanism between target and source templates # in charms.openstack core.templating.render( source='mellon-sp-metadata.xml', template_loader=os_templating.get_loader('templates/', self.release), target=self.options.sp_metadata_file, context=self.adapters_class(args, charm_instance=self), owner=owner, group=group, perms=fileperms) core.templating.render( source='apache-mellon-location.conf', template_loader=os_templating.get_loader('templates/', self.release), target=self.options.sp_location_config, context=self.adapters_class(args, charm_instance=self), owner=owner, group=group, perms=fileperms)
def get_template_for_release_and_server(self, os_release, server, mock_log): if not server: server = 'object' loader = get_loader('./templates', os_release) env = Environment(loader=loader) return env.get_template('{}-server.conf'.format(server))
def render_config(self, restart_trigger): """Render the domain specific LDAP configuration for the application """ checksum = ch_host.path_hash(self.configuration_file) core.templating.render(source=KEYSTONE_CONF_TEMPLATE, template_loader=os_templating.get_loader( 'templates/', self.release), target=self.configuration_file, context=self.adapters_instance) if checksum != ch_host.path_hash(self.configuration_file): restart_trigger()
def render_config(self, *args): """ Render Service Provider configuration file to be used by Apache and provided to idP out of band to establish mutual trust. """ owner = 'root' group = 'www-data' # group read and exec is needed for mellon to read the rendered # files, otherwise it will fail in a cryptic way dperms = 0o650 # file permissions are a bit more restrictive than defaults in # charm-helpers but directory permissions are the main protection # mechanism in this case fileperms = 0o440 # ensure that a directory we need is there ch_host.mkdir('/etc/apache2/mellon', perms=dperms, owner=owner, group=group) core.templating.render( source='apache-oidc-location.conf', template_loader=os_templating.get_loader('templates/', self.release), target=self.options.oidc_location_config, context=self.adapters_class(args, charm_instance=self), owner=owner, group=group, perms=fileperms) core.templating.render( source='oidc.conf', template_loader=os_templating.get_loader('templates/', self.release), target=self.options.oidc_conf, context=self.adapters_class(args, charm_instance=self), owner=owner, group=group, perms=fileperms)
def test_get_loader_some_search_paths(self, isdir): '''Ensure loader reverse searches of some release template dirs''' isdir.return_value = True choice_loader = templating.get_loader('/tmp/foo', os_release='grizzly') dirs = [l.searchpath for l in choice_loader.loaders] common_tmplts = os.path.join(os.path.dirname(templating.__file__), 'templates') expected = [['/tmp/foo/grizzly'], ['/tmp/foo/folsom'], ['/tmp/foo/essex'], ['/tmp/foo/diablo'], ['/tmp/foo'], [common_tmplts]] self.assertEquals(dirs, expected)
def get_template_for_release_and_server( self, os_release, server, mock_log): if not server: server = 'object' loader = get_loader('./templates', os_release) env = Environment(loader=loader) return env.get_template('{}-server.conf'.format(server))
def get_config_for_principal(self, auth_data): """Assuming that the configuration data is valid, return the configuration data for the principal charm. The format of the complete returned data is: { "<config file>: <string> } If the configuration is not complete, or we don't have auth data from the principal charm, then we return and emtpy dictionary {} :param auth_data: the raw dictionary received from the principal charm :returns: structure described above. """ # If there is no auth_data yet, then we can't write our config. if not auth_data: return {} # If the state from the assess_status is not None then we're blocked, # so don't send any config to the principal. state, message = self.custom_assess_status_check() if state: return {} options = self.options # tiny optimisation for less typing. # If there is no backend name, then we can't send the data yet as the # manila-charm won't know what to do with it. if not options.share_backend_name: return {} # We have the auth data & the config is reasonably sensible. # We can try and render the config file segment. # TODO this is horrible, and we should have something in # charms.openstack to do this, but we need a c.r relation to be able to # add it to the adapters_instance manila_plugin = relations.endpoint_from_flag('manila-plugin.available') self.adapters_instance.add_relation(manila_plugin) rendered_configs = charmhelpers.core.templating.render( source=os.path.basename(MANILA_CONF), template_loader=os_templating.get_loader( 'templates/', self.release), target=None, context=self.adapters_instance) return { MANILA_CONF: rendered_configs }
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 send_config(self, event): if not self.custom_status_check(): return if self.options.driver_handles_share_servers: if not self.manila_plugin.authentication_data: logging.warning( "Manila plugin authentication_data is required when " "'driver-handles-share-servers' config is enabled.") event.defer() return rendered_configs = ch_templating.render( source=os.path.basename(interface_manila_plugin.MANILA_CONF), template_loader=os_templating.get_loader('templates/', self.release), target=None, context=self.adapters) self.manila_plugin.send_backend_config(self.options.share_backend_name, rendered_configs) self.state.is_started = True self.update_status()
def render_configs(self, configs, adapters_instance=None): """Render the configuration files identified in the list passed as configs. If adapters_instance is None then the self.adapters_instance is used that was setup in the __init__() method. :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: adapters_instance = self.adapters_instance with self.restart_on_change(): for conf in configs: charmhelpers.core.templating.render( source=os.path.basename(conf), template_loader=os_templating.get_loader( 'templates/', self.release), target=conf, context=adapters_instance)
def render_configs(self, configs, adapters_instance=None): """Render the configuration files identified in the list passed as configs. If adapters_instance is None then the self.adapters_instance is used that was setup in the __init__() method. Note, if no interfaces were passed (the default) then there will be no interfaces. TODO: need to work out how to make this function more useful - at the moment, with a default setup, this function is only useful to render_with_interfaces() which constructs a new adapters_instance anyway. 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: adapters_instance = self.adapters_instance def get_str_tmpl(conf, adapters_instance): """ Find out if a charm class provides meta information about whether this is a template to be fetched from a string dynamically or not. """ config_template = None tmpl_meta = self.string_templates.get(conf) if tmpl_meta: # meta information exists but not clear if an attribute has # been set yet either via config option or via relation data config_template = False rel_name, property = tmpl_meta if hasattr(adapters_instance, rel_name): conf_tmpl_adapter = getattr(adapters_instance, rel_name) if hasattr(conf_tmpl_adapter, property): config_template = getattr(conf_tmpl_adapter, property) else: raise Exception('{} does not contain {} property' ''.format(conf_tmpl_adapter, property)) return config_template with self.restart_on_change(): for conf in configs: # check if we need to load a template from a string config_template = get_str_tmpl(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)
def get_template_for_release(self, os_release, mock_log): loader = get_loader('./templates', os_release) env = Environment(loader=loader) return env.get_template('proxy-server.conf')