{%- import_yaml "openssh/defaults.yaml" as default_settings -%} {%- set ssh_config = salt['pillar.get']('ssh_config', default=default_settings.ssh_config, merge=True) -%} {#- present in ssh_config and known in actual file options -#} {%- set processed_options = [] -%} {%- set string_or_list_options = ['KexAlgorithms', 'Ciphers', 'MACs'] -%} {%- macro render_raw_option(keyword, value) -%} {%- if value is sameas true -%} {{ keyword }} yes {%- elif value is sameas false -%} {{ keyword }} no {%- elif value is string or value is number -%} {{ keyword }} {{ value }} {%- else -%} {%- for single_value in value -%} {{ keyword }} {{ single_value }} {% endfor -%} {%- endif -%} {%- endmacro -%} {#- generic renderer used for ssh matches, known options, -#} {#- and unknown options -#} {%- macro render_option(keyword, default, config_dict=ssh_config) -%} {%- set value = config_dict.get(keyword, default) -%} {{ render_raw_option(keyword, value) }} {%- endmacro -%} {#- macros for render option according to present -#} {%- macro option_impl(keyword, default, present) -%} {%- if present -%} {%- do processed_options.append(keyword) -%} {%- set prefix='' -%} {%- else -%} {%- set prefix='#' -%} {%- endif -%} {#- add prefix to keyword -#} {%- set keyword = prefix ~ keyword -%} {{ render_option(keyword, default) }} {%- endmacro -%} {#- macros for render option commented by default -#} {%- macro option(keyword, default, present) -%} {{ option_impl(keyword, default, keyword in ssh_config) }} {%- endmacro -%} {#- macros for render option uncommented by default -#} {%- macro option_default_uncommented(keyword, default, present) -%} {{ option_impl(keyword, default, True) }} {%- endmacro -%} {#- macro for collapsing a list into a string -#} {%- macro option_collapselist(keyword, sep) -%} {%- do processed_options.append(keyword) -%} {{keyword}} {{ssh_config.get(keyword)|join(sep)}} {%- endmacro -%} {#- macro for handling an option that can be specified as a list or a string -#} {%- macro option_string_or_list(keyword, default, default_commented, sep=',') -%} {%- if ssh_config.get(keyword, '') is string -%} {%- if default_commented -%} {{ option(keyword, default) }} {%- else -%} {{ option_default_uncommented(keyword, default) }} {%- endif -%} {%- else -%} {{ option_collapselist(keyword, sep) }} {%- endif -%} {%- endmacro -%} {%- if ssh_config.get('ConfigBanner', False) -%} {{ ssh_config['ConfigBanner'] }} {%- else -%} # Do not edit this file manually! # It will be overwritten by salt! {%- endif %} {%- if 'Hosts' in ssh_config %} {%- do processed_options.append('Hosts') %} {% for host, conf in ssh_config['Hosts'].items() %} Host {{ host }} {%- for key, val in conf.items() %} {{ render_raw_option(key, val) }} {%- endfor %} {%- endfor %} {%- endif %} {# Handling unknown in salt template options #} {%- for keyword in ssh_config.keys() %} {#- Matches have to be at the bottom and should be handled differently -#} {%- if not keyword in processed_options and keyword != 'matches' -%} {%- if not keyword in string_or_list_options -%} {#- send a blank default as it doesn't matter #} {{ render_option(keyword, '') }} {%- else -%} {#- same as above #} {{ option_string_or_list(keyword, '', True) }} {%- endif -%} {%- endif -%} {%- endfor %} {# Handle matches last as they need to go at the bottom #} {%- if 'matches' in ssh_config %} {%- for match in ssh_config['matches'].values() %} Match {{ match['type'].keys()[0] }} {{ match['type'].values()[0] }} {%- for keyword in match['options'].keys() %} {{ render_option(keyword, '', config_dict=match['options']) }} {%- endfor %} {%- endfor %} {%- endif %} {#- vim: set ft=jinja : #}