Skip to content

Instantly share code, notes, and snippets.

@mjinks
Last active September 28, 2015 17:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mjinks/3762fb4e13a36bc009fe to your computer and use it in GitHub Desktop.
Save mjinks/3762fb4e13a36bc009fe to your computer and use it in GitHub Desktop.
Trying to have Salt create a series of files under '/etc/vsftpd/vsftpd_user_conf'. Extending the formula that creates the main vsftpd config file, /etc/vsftpd.conf.
# vim: sts=2 ts=2 sw=2
{% from "vsftpd/map.jinja" import vsftpd with context %}
vsftpd_user_list:
file.managed:
- name: /etc/vsftpd/vsftpd.user_list
- source: salt://vsftpd/files/vsftpd.user_list
- user: root
- group: root
- mode: 644
- watch_in:
- service: {{ vsftpd.service }}
vsftpd_chroot_list:
file.managed:
- name: /etc/vsftpd/vsftpd.chroot_list
- source: salt://vsftpd/files/vsftpd.chroot_list
- user: root
- group: root
- mode: 644
- watch_in:
- service: {{ vsftpd.service }}
vsftpd_config:
file.managed:
- name: {{ vsftpd.vsftpd_config }}
- source: {{ vsftpd.vsftpd_config_src }}
- template: jinja
- user: root
- group: root
- mode: 644
- watch_in:
- service: {{ vsftpd.service }}
{% for name, conf in pillar.get('vsftpd_user_config', {}).items() if conf.absent is not defined or not conf.absent %}
vsftpd_user_conf_{{ name }}:
file.managed:
- name: /etc/vsftpd/vsftpd_user_conf/{{ name }}
- source: {{ vsftpd.vsftpd_user_config }}
- template: jinja
- context:
vsftpd_user_config: {{ conf | yaml }}
- user: root
- mode: 644
- watch_in:
- service: {{ vsftpd.service }}
{% endfor %}
{% from "vsftpd/map.jinja" import vsftpd with context %}
vsftpd:
{% if vsftpd.server is defined %}
pkg.installed:
- name: {{ vsftpd.server }}
{% endif %}
service.running:
- enable: True
- name: {{ vsftpd.service }}
{% if vsftpd.server is defined %}
- require:
- pkg: {{ vsftpd.server }}
{% endif %}
include:
- vsftpd.config
# The final entry under Debian, '...vsftpd_user_template', is new:
{% set vsftpd = salt['grains.filter_by']({
'Debian': {
'server': 'vsftpd',
'service': 'vsftpd',
'vsftpd_config': '/etc/vsftpd.conf',
'vsftpd_config_dir': '/etc/vsftpd',
'vsftpd_config_src': 'salt://vsftpd/files/vsftpd.conf',
'vsftpd_user_config': 'salt://vsftpd/files/vsftpd_user_template',
},
'FreeBSD': {
'server': 'vsftpd-ssl',
'service': 'vsftpd',
'vsftpd_config': '/usr/local/etc/vsftpd.conf',
'vsftpd_config_dir': '/usr/local/etc/vsftpd',
'vsftpd_config_src': 'salt://vsftpd/files/vsftpd.conf',
},
'RedHat': {
'server': 'vsftpd',
'service': 'vsftpd',
'vsftpd_config': '/etc/vsftpd/vsftpd.conf',
'vsftpd_config_dir': '/etc/vsftpd',
'vsftpd_config_src': 'salt://vsftpd/files/vsftpd.conf',
},
}, merge=salt['pillar.get']('vsftpd:lookup')) %}
{%- set vsftpd_user_config = pillar.get('vsftpd_user_config', {}) -%}
{#- present in vsftpd_config and known in actual file options -#}
{%- set processed_options = [] -%}
{#- generic renderer used for vsftpd known options, -#}
{#- and unknown options -#}
{%- macro render_option(keyword, default, config_dict=vsftpd_user_config) -%}
{%- set value = config_dict.get(keyword, default) -%}
{%- if value is string or value is number -%}
{{ keyword }}={{ value }}
{%- else -%}
{%- for single_value in value -%}
{{ keyword }}={{ single_value }}
{% endfor -%}
{%- endif -%}
{%- 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 vsftpd_user_config) }}
{%- endmacro -%}
{#- macros for render option uncommented by default -#}
{%- macro option_default_uncommented(keyword, default, present) -%}
{{ option_impl(keyword, default, True) }}
{%- endmacro -%}
{# END CRIB - mjinks #}
# THIS FILE IS MANAGED BY SALT. changes here will be lost when
# salt brings this host up to high state.
{{ option_default_uncommented('local_enable', 'YES') }}
{{ option_default_uncommented('write_enable', 'YES') }}
{{ option_default_uncommented('local_umask', '002') }}
{{ option_default_uncommented('dirmessage_enable', 'YES') }}
{{ option_default_uncommented('xferlog_enable', 'YES') }}
{{ option_default_uncommented('dual_log_enable', 'YES') }}
{{ option_default_uncommented('pasv_enable', 'YES') }}
{{ option_default_uncommented('pasv_promiscuous', 'YES') }}
{{ option_default_uncommented('pasv_min_port', '50000') }}
{{ option_default_uncommented('pasv_max_port', '55000') }}
{{ option_default_uncommented('connect_from_port_20', 'YES') }}
{{ option_default_uncommented('vsftpd_log_file', '/var/log/vsftpd.log') }}
{{ option_default_uncommented('xferlog_file', '/var/log/xferlog.log') }}
{{ option_default_uncommented('xferlog_std_format', 'NO') }}
{{ option_default_uncommented('nopriv_user', 'ftpsecure') }}
{{ option_default_uncommented('ftpd_banner', '"Peerless Network Download Server"') }}
{{ option_default_uncommented('chroot_list_enable', 'YES') }}
{{ option_default_uncommented('chroot_list_file', '/etc/vsftpd/vsftpd.chroot_list') }}
# typically custom changes start here
{{ option_default_uncommented('chroot_local_user', 'NO') }}
#allow_writeable_chroot=YES
{{ option_default_uncommented('hide_ids', 'YES') }}
{{ option_default_uncommented('tcp_wrappers', 'NO') }}
{{ option_default_uncommented('use_localtime', 'YES') }}
{{ option_default_uncommented('userlist_deny', 'NO') }}
{{ option_default_uncommented('userlist_enable', 'YES') }}
{{ option_default_uncommented('userlist_file', '/etc/vsftpd/vsftpd.user_list') }}
{{ option_default_uncommented('user_config_dir', '/etc/vsftpd/vsftpd_user_conf') }}
{%- set vsftpd_config = pillar.get('vsftpd_config', {}) -%}
{#- present in vsftpd_config and known in actual file options -#}
{%- set processed_options = [] -%}
{#- generic renderer used for vsftpd known options, -#}
{#- and unknown options -#}
{%- macro render_option(keyword, default, config_dict=vsftpd_config) -%}
{%- set value = config_dict.get(keyword, default) -%}
{%- if value is string or value is number -%}
{{ keyword }}={{ value }}
{%- else -%}
{%- for single_value in value -%}
{{ keyword }}={{ single_value }}
{% endfor -%}
{%- endif -%}
{%- 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 vsftpd_config) }}
{%- endmacro -%}
{#- macros for render option uncommented by default -#}
{%- macro option_default_uncommented(keyword, default, present) -%}
{{ option_impl(keyword, default, True) }}
{%- endmacro -%}
{{ option_default_uncommented('listen', 'YES') }}
{{ option('listen_ipv6', 'YES') }}
{{ option('listen_address', '0.0.0.0' ) }}
{{ option_default_uncommented('anonymous_enable', 'NO') }}
{{ option_default_uncommented('local_enable', 'YES') }}
{{ option('write_enable', 'YES') }}
{{ option('local_umask', '022') }}
{{ option('anon_upload_enable', 'YES') }}
{{ option('anon_mkdir_write_enable', 'YES') }}
{{ option_default_uncommented('dirmessage_enable', 'YES') }}
{{ option_default_uncommented('use_localtime', 'YES') }}
{{ option_default_uncommented('xferlog_enable', 'YES') }}
{{ option('dual_log_enable', 'YES') }}
{{ option('pasv_enable', 'YES') }}
{{ option('pasv_promiscuous', 'YES') }}
{{ option('pasv_min_port', '50000') }}
{{ option('pasv_max_port', '55000') }}
{{ option('connect_from_port_20', 'YES') }}
{{ option('chown_uploads', 'YES') }}
{{ option('chown_username', 'whoever') }}
{{ option('xferlog_file', '/var/log/vsftpd.log') }}
{{ option('xferlog_std_format', 'YES') }}
{{ option('idle_session_timeout', '600') }}
{{ option('data_connection_timeout', '120') }}
{{ option('nopriv_user', 'ftpsecure') }}
{{ option('async_abor_enable', 'YES') }}
{{ option('ascii_upload_enable', 'YES') }}
{{ option('ascii_download_enable', 'YES') }}
{{ option('ftpd_banner', 'Welcome to blah FTP service.') }}
{{ option('deny_email_enable', 'YES') }}
{{ option('banned_email_file', '/etc/vsftpd.banned_emails') }}
{{ option('chroot_local_user', 'YES') }}
{{ option('chroot_local_user', 'YES') }}
{{ option('chroot_list_enable', 'YES') }}
{{ option('chroot_list_file', '/etc/vsftpd.chroot_list') }}
{{ option('ls_recurse_enable', 'YES') }}
{{ option_default_uncommented('secure_chroot_dir', '/var/run/vsftpd/empty') }}{{ option('connect_from_port_20', 'YES') }}
{{ option('chown_uploads', 'YES') }}
{{ option('chown_username', 'whoever') }}
{{ option('xferlog_file', '/var/log/vsftpd.log') }}
{{ option('xferlog_std_format', 'YES') }}
{{ option('idle_session_timeout', '600') }}
{{ option('data_connection_timeout', '120') }}
{{ option('nopriv_user', 'ftpsecure') }}
{{ option('async_abor_enable', 'YES') }}
{{ option('ascii_upload_enable', 'YES') }}
{{ option('ascii_download_enable', 'YES') }}
{{ option('ftpd_banner', 'Welcome to blah FTP service.') }}
{{ option('deny_email_enable', 'YES') }}
{{ option('banned_email_file', '/etc/vsftpd.banned_emails') }}
{{ option('chroot_local_user', 'YES') }}
{{ option('chroot_local_user', 'YES') }}
{{ option('chroot_list_enable', 'YES') }}
{{ option('chroot_list_file', '/etc/vsftpd.chroot_list') }}
{{ option('ls_recurse_enable', 'YES') }}
{{ option_default_uncommented('secure_chroot_dir', '/var/run/vsftpd/empty') }}
{# mjinks 2015/09/09: as above, we do comment this out and i can't figure out how to
express that in the pillar, so altering it here
{{ option_default_uncommented('pam_service_name', 'vsftpd') }} #}
{{ option('pam_service_name', 'vsftpd') }}
{{ option_default_uncommented('rsa_cert_file', '/etc/ssl/certs/ssl-cert-snakeoil.pem') }}
{{ option_default_uncommented('rsa_private_key_file', '/etc/ssl/private/ssl-cert-snakeoil.key') }}
{#
mjinks 2015/09/15: from here, options weren't in the formula, so some
t&e may be underway.
{{ option('ssl_enable', 'YES') }}
{{ option('listen_port', '990') }}
{{ option('ftp_data_port', '989') }}
{{ option('allow_anon_ssl', 'NO') }}
{{ option('force_local_data_ssl', 'YES') }}
{{ option('force_local_logins_ssl', 'YES') }}
{{ option('ssl_tlsv1', 'YES') }}
{{ option('ssl_sslv2', 'NO') }}
{{ option('ssl_sslv3', 'NO') }}
{{ option('require_ssl_reuse', 'NO') }}
{{ option('ssl_ciphers', 'HIGH') }}
{# mjinks 2015/09/15: weirdness: above this point, 'option' works.
below it, we have to use 'option_default_uncommented' or... the
entry shows up commented at the minion.
above this point, either setting appears to work. not clear on
what 'default_uncommented' is really supposed to indicate. #}
{{ option_default_uncommented('userlist_deny', 'NO') }}
{{ option_default_uncommented('userlist_enable', 'YES') }}
{{ option_default_uncommented('userlist_file', '/etc/vsftpd/vsftpd.user_list') }}
{{ option_default_uncommented('user_config_dir', '/etc/vsftpd/vsftpd_user_conf') }}
{# Handling unknown in salt template options #}
{%- for keyword in vsftpd_config.keys() %}
{%- if not keyword in processed_options -%}
{#- send a blank default as it doesn't matter #}
{{ render_option(keyword, '') }}
{%- endif -%}
{%- endfor %}
# If I remove...
# {%- set vsftpd_user_config = pillar.get('vsftpd_user_config', {}) -%}
# ...from my formula, I get garbage (below). If I bring it back, the entries
# I'm trying to create do appear, but they don't get seeded from the pillar.
ID: vsftpd_user_conf_mjinks
Function: file.managed
Name: /etc/vsftpd/vsftpd_user_conf/mjinks
Result: False
Comment: An exception occurred in this state: Traceback (most recent call last):
File "/usr/lib/python2.7/dist-packages/salt/state.py", line 1560, in call
**cdata['kwargs'])
File "/usr/lib/python2.7/dist-packages/salt/states/file.py", line 1423, in managed
**kwargs
File "/usr/lib/python2.7/dist-packages/salt/modules/file.py", line 3142, in check_managed_chang
es
**kwargs)
File "/usr/lib/python2.7/dist-packages/salt/modules/file.py", line 2841, in get_managed
**kwargs)
File "/usr/lib/python2.7/dist-packages/salt/utils/templates.py", line 121, in render_tmpl
output = render_str(tmplstr, context, tmplpath)
File "/usr/lib/python2.7/dist-packages/salt/utils/templates.py", line 346, in render_jinja_tmpl
trace=tracestr)
SaltRenderError: Jinja error: global name 'l_vsftpd_user_config' is not defined
Traceback (most recent call last):
File "/usr/lib/python2.7/dist-packages/salt/utils/templates.py", line 306, in render_jinja_tmpl
output = template.render(**decoded_context)
File "/usr/lib/python2.7/dist-packages/jinja2/environment.py", line 894, in render
return self.environment.handle_exception(exc_info, True)
File "<template>", line 40, in top-level template code
NameError: global name 'l_vsftpd_user_config' is not defined
; line 40
---
[...]
{%- set value = config_dict.get(keyword, default) -%}
{%- if value is string or value is number -%}
{{ keyword }}={{ value }}
{%- else -%}
{%- for single_value in value -%}
{{ keyword }}={{ single_value }} <======================
{% endfor -%}
{%- endif -%}
{%- endmacro -%}
{#- macros for render option according to present -#}
[...]
---
Started: 10:16:27.602326
Duration: 32.987 ms
Changes:
vsftpd_user_config:
mjinks:
anonymous_enable: 'NO'
chroot_list_enable: 'YES'
chroot_list_file: '/etc/vsftpd/vsftpd.chroot_list'
chroot_local_user: 'NEVER'
connect_from_port_20: 'YES'
dirmessage_enable: 'YES'
dual_log_enable: 'YES'
ftpd_banner: '"Peerless And Then Some"'
hide_ids: 'YES'
local_umask: '002'
nopriv_user: 'ftpsecure'
pasv_enable: 'YES'
pasv_max_port: '55000'
pasv_min_port: '50000'
pasv_promiscuous: 'YES'
tcp_wrappers: 'NO'
use_localtime: 'YES'
user_config_dir: '/etc/vsftpd/vsftpd_user_conf'
userlist_deny: 'NO'
userlist_enable: 'YES'
userlist_file: '/etc/vsftpd/vsftpd.user_list'
vsftpd_log_file: '/var/log/vsftpd.log'
write_enable: 'YES'
xferlog_enable: 'YES'
xferlog_file: '/var/log/xferlog.log'
xferlog_std_format: 'NO'
vsftpd_user_config: 'YES'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment