def push(self, generated_dir, remotes_dir): """ Push configuration files that have changes, given user confirmation. """ host_generated_dir = os.sep.join([generated_dir, options.get_hostname()]) host_remotes_dir = os.sep.join([remotes_dir, options.get_hostname()]) for conffile in self.conffiles: conffile.pull(host_remotes_dir) for conffile in self.conffiles: conffile.generate(host_generated_dir) has_diff = lambda conffile: conffile.diff(host_generated_dir, host_remotes_dir, True) with_diffs = filter(has_diff, self.conffiles) if not with_diffs: print(magenta('No configuration files to push for {host}'.format(host=options.get_hostname()))) return print(magenta('The following configuration files have changed for {host}:'.format(host=options.get_hostname()))) print for conffile in with_diffs: print(magenta('\t' + conffile.remote)) if confirm('Push configuration files to {host}?'.format(host=options.get_hostname()), default=False): for conffile in with_diffs: conffile.push(host_generated_dir)
def __init__(self, environment_loader, data_loader): """ On init, load a list of configuration files using the provided Jinja2 environment loader and data loader. The environment loader must return a Jinja2 environment that uses a loader that supports :meth:`jinja2.Environment.list_templates`. """ def load_templates(component): data = data_loader(component) environment = environment_loader(os.path.basename(component)) conffiles = [] for conffile in map(lambda template_name: ConfFile(environment.get_template(template_name), data), environment.list_templates(filter_func=options.filter_func)): other_component = conffile_names.get(conffile.name) if other_component: raise Exception("Found two configuration templates with the same file path." " File: {}, Components: {}" .format(conffile.remote, ",".join([component, other_component]))) conffile_names[conffile.name] = component # store the conffiles for the current role if role == options.get_rolename(): conffiles.append(conffile) return conffiles self.conffiles = [] # Make sure we can generate all templates for the current host. # This will go over all roles for the host. # A mapping between a conffile name # and the component it is generated for. conffile_names = {} for role in get_roles_for_host(options.get_hostname()): self.conffiles.extend(load_templates(role)) for component in get_components_for_role(role): self.conffiles.extend(load_templates(component)) if not self.conffiles: warn("No conffiles found for '{role}' on '{host}' in environment '{environment}'" .format(role=options.get_rolename(), host=options.get_hostname(), environment=options.get_environmentname()))
def diff(self, generated_dir, remotes_dir): """ Show diffs for all configuration files. """ host_generated_dir = os.sep.join([generated_dir, options.get_hostname()]) host_remotes_dir = os.sep.join([remotes_dir, options.get_hostname()]) for conffile in self.conffiles: conffile.pull(host_remotes_dir) for conffile in self.conffiles: conffile.generate(host_generated_dir) for conffile in self.conffiles: conffile.diff(host_generated_dir, host_remotes_dir).show()
def pull(self, remotes_dir): """ Pull remote versions of files into remotes_dir. """ host_remotes_dir = os.sep.join([remotes_dir, options.get_hostname()]) for conffile in self.conffiles: conffile.pull(host_remotes_dir)
def generate(self, generated_dir): """ Write all configuration files to generated_dir. """ host_generated_dir = os.sep.join([generated_dir, options.get_hostname()]) _clear_dir(host_generated_dir) _ensure_dir(host_generated_dir) for conffile in self.conffiles: conffile.generate(host_generated_dir)
def pull(self, remotes_dir): """ Pull remote configuration file to local file. """ local_file_name = os.sep.join([remotes_dir, self.name]) puts('Pulling {file_name} from {host}'.format(file_name=self.remote, host=options.get_hostname())) _ensure_dir(os.path.dirname(local_file_name)) _clear_file(local_file_name) with settings(use_ssh_config=True): if exists(self.remote, use_sudo=options.use_sudo): get(self.remote, local_file_name) else: puts('Not found: {file_name}'.format(file_name=self.remote))
def push(self, generated_dir): """ Push the generated configuration file to the remote host. """ generated_file_name = os.sep.join([generated_dir, self.name]) remote_dir = os.path.dirname(self.remote) puts('Pushing {file_name} to {host}'.format(file_name=self.remote, host=options.get_hostname())) with settings(use_ssh_config=True): mkdir_cmd = sudo if options.use_sudo else run mkdir_cmd('mkdir -p {dir_name}'.format(dir_name=remote_dir)) put(generated_file_name, self.remote, use_sudo=options.use_sudo, mirror_local_mode=True)
def __call__(self, component): """ Load the data for the given component. :param component: a component path, i.e. `{role}/{sub-component}/{component}`. """ is_not_none = lambda x: x is not None module_names = filter(is_not_none, chain(['default'], _get_component_modules(component), [_get_environment_module(), _get_host_module()])) load_module = lambda module_name: import_configuration(module_name, self.data_dir) module_dicts = filter(is_not_none, map(load_module, module_names)) confab_data = dict(confab=dict(environment=options.get_environmentname(), host=options.get_hostname(), component=component)) return merge(confab_data, *module_dicts)
def _get_host_module(): """ Return the current configuration hostname. """ return options.get_hostname()