Ansible best practices : copy vs. template

Hi,

When I configure a service with Ansible, I usually use the ansible.builtin.template module for configuration file templates, since they allow variables. Here’s an example stub of a main.cf.j2 template file for Postfix:

# /etc/postfix/main.cf
#
# Minimal Postfix configuration for LAN servers

# Disable backwards compatibility
compatibility_level = 2

# Disable IPv6
inet_protocols = ipv4

# Outbound mail only
inet_interfaces = localhost
mailbox_size_limit = 0

# Host
myhostname = {{ansible_hostname}}.{{ansible_dns.search.0}}

# Domain
mydomain = {{ansible_dns.search.0}}

# Authorize local machine only
mynetworks = 127.0.0.0/8

On the other hand, some services have “static” configuration files, meaning I don’t use any variables to install them. Here’s an example chrony.conf:

# /etc/chrony.conf
server 0.fr.pool.ntp.org iburst
server 1.fr.pool.ntp.org iburst
server 2.fr.pool.ntp.org iburst
server 3.fr.pool.ntp.org iburst
driftfile /var/lib/chrony/drift
makestep 1.0 3
rtcsync
logdir /var/log/chrony

Since there are no variables in this file, I just put this file in the roles/ntp_client/files directory and use the ansible.builtin.copy module to install it.

Now I wonder if this is an orthodox way to do things, or if it’s considered good practice to still use the template module and put this configuration file in templates even if there are no variables in it.

Being picky here, I know.

You can use this role: Ansible Galaxy

That way no need to use a config file or template. The readme there gives some examples, eg:

- name: Manage timesync with 3 servers
  hosts: targets
  vars:
    timesync_ntp_servers:
      - hostname: foo.example.com
        iburst: true
      - hostname: bar.example.com
        iburst: true
      - hostname: baz.example.com
        iburst: true
  roles:
    - linux-system-roles.timesync

with custom bits:

    timesync_chrony_custom_settings:
      - "logdir /var/log/chrony"

This can also be installed using:

dnf install rhel-system-roles

without having to install from Ansible Galaxy.

[root@rocky8 ~]# dnf repoquery -l rhel-system-roles | grep -i timesync
Last metadata expiration check: 2:20:05 ago on Tue 06 Jun 2023 08:26:11 AM CEST.
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/COPYING-timesync
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/docs/CHANGELOG_timesync.md
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/docs/README_timesync.md
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/docs/timesync
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/docs/timesync/multiple-ntp-servers.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/docs/timesync/single-pool.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/plugins/modules/timesync_provider.sh
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/.ansible-lint
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/CHANGELOG.md
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/README.md
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/defaults
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/defaults/main.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/handlers
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/handlers/main.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/meta
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/meta/main.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/tasks
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/tasks/main.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/tasks/set_vars.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/templates
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/templates/chrony.conf.j2
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/templates/chronyd.sysconfig.j2
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/templates/ntp.conf.j2
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/templates/ntpd.sysconfig.j2
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/templates/phc2sys.sysconfig.j2
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/templates/ptp4l.conf.j2
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/templates/ptp4l.sysconfig.j2
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/templates/timemaster.conf.j2
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/vars
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/vars/CentOS_6.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/vars/CentOS_9.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/vars/Debian.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/vars/OracleLinux_6.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/vars/OracleLinux_7.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/vars/OracleLinux_8.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/vars/OracleLinux_9.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/vars/RedHat_6.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/vars/RedHat_9.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/vars/default.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/roles/timesync/vars/main.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/tests/timesync
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/tests/timesync/.fmf
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/tests/timesync/.fmf/version
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/tests/timesync/inventory.yaml.j2
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/tests/timesync/provision.fmf
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/tests/timesync/setup-snapshot.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/tests/timesync/tests_chrony.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/tests/timesync/tests_default.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/tests/timesync/tests_default_vars.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/tests/timesync/tests_default_wrapper.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/tests/timesync/tests_ntp.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/tests/timesync/tests_ntp_provider1.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/tests/timesync/tests_ntp_provider2.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/tests/timesync/tests_ntp_provider3.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/tests/timesync/tests_ntp_provider4.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/tests/timesync/tests_ntp_provider5.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/tests/timesync/tests_ntp_provider6.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/tests/timesync/tests_ntp_ptp.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/tests/timesync/tests_ptp_multi.yml
/usr/share/ansible/collections/ansible_collections/redhat/rhel_system_roles/tests/timesync/tests_ptp_single.yml
/usr/share/ansible/roles/linux-system-roles.timesync
/usr/share/ansible/roles/rhel-system-roles.timesync
/usr/share/ansible/roles/rhel-system-roles.timesync/CHANGELOG.md
/usr/share/ansible/roles/rhel-system-roles.timesync/COPYING
/usr/share/ansible/roles/rhel-system-roles.timesync/README.html
/usr/share/ansible/roles/rhel-system-roles.timesync/README.md
/usr/share/ansible/roles/rhel-system-roles.timesync/ansible_pytest_extra_requirements.txt
/usr/share/ansible/roles/rhel-system-roles.timesync/custom_requirements.txt
/usr/share/ansible/roles/rhel-system-roles.timesync/defaults
/usr/share/ansible/roles/rhel-system-roles.timesync/defaults/main.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/handlers
/usr/share/ansible/roles/rhel-system-roles.timesync/handlers/main.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/library
/usr/share/ansible/roles/rhel-system-roles.timesync/library/timesync_provider.sh
/usr/share/ansible/roles/rhel-system-roles.timesync/meta
/usr/share/ansible/roles/rhel-system-roles.timesync/meta/main.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/molecule_extra_requirements.txt
/usr/share/ansible/roles/rhel-system-roles.timesync/pylint_extra_requirements.txt
/usr/share/ansible/roles/rhel-system-roles.timesync/pylintrc
/usr/share/ansible/roles/rhel-system-roles.timesync/pytest_extra_requirements.txt
/usr/share/ansible/roles/rhel-system-roles.timesync/tasks
/usr/share/ansible/roles/rhel-system-roles.timesync/tasks/main.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/tasks/set_vars.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/templates
/usr/share/ansible/roles/rhel-system-roles.timesync/templates/chrony.conf.j2
/usr/share/ansible/roles/rhel-system-roles.timesync/templates/chronyd.sysconfig.j2
/usr/share/ansible/roles/rhel-system-roles.timesync/templates/ntp.conf.j2
/usr/share/ansible/roles/rhel-system-roles.timesync/templates/ntpd.sysconfig.j2
/usr/share/ansible/roles/rhel-system-roles.timesync/templates/phc2sys.sysconfig.j2
/usr/share/ansible/roles/rhel-system-roles.timesync/templates/ptp4l.conf.j2
/usr/share/ansible/roles/rhel-system-roles.timesync/templates/ptp4l.sysconfig.j2
/usr/share/ansible/roles/rhel-system-roles.timesync/templates/timemaster.conf.j2
/usr/share/ansible/roles/rhel-system-roles.timesync/tests
/usr/share/ansible/roles/rhel-system-roles.timesync/tests/.fmf
/usr/share/ansible/roles/rhel-system-roles.timesync/tests/.fmf/version
/usr/share/ansible/roles/rhel-system-roles.timesync/tests/inventory.yaml.j2
/usr/share/ansible/roles/rhel-system-roles.timesync/tests/provision.fmf
/usr/share/ansible/roles/rhel-system-roles.timesync/tests/roles
/usr/share/ansible/roles/rhel-system-roles.timesync/tests/setup-snapshot.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/tests/tests_chrony.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/tests/tests_default.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/tests/tests_default_vars.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/tests/tests_default_wrapper.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/tests/tests_ntp.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/tests/tests_ntp_provider1.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/tests/tests_ntp_provider2.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/tests/tests_ntp_provider3.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/tests/tests_ntp_provider4.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/tests/tests_ntp_provider5.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/tests/tests_ntp_provider6.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/tests/tests_ntp_ptp.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/tests/tests_ptp_multi.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/tests/tests_ptp_single.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/tox.ini
/usr/share/ansible/roles/rhel-system-roles.timesync/vars
/usr/share/ansible/roles/rhel-system-roles.timesync/vars/CentOS_6.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/vars/CentOS_9.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/vars/Debian.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/vars/OracleLinux_6.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/vars/OracleLinux_7.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/vars/OracleLinux_8.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/vars/OracleLinux_9.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/vars/RedHat_6.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/vars/RedHat_9.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/vars/default.yml
/usr/share/ansible/roles/rhel-system-roles.timesync/vars/main.yml
/usr/share/doc/rhel-system-roles/collection/roles/timesync
/usr/share/doc/rhel-system-roles/collection/roles/timesync/CHANGELOG.md
/usr/share/doc/rhel-system-roles/collection/roles/timesync/README.html
/usr/share/doc/rhel-system-roles/collection/roles/timesync/README.md
/usr/share/doc/rhel-system-roles/timesync
/usr/share/doc/rhel-system-roles/timesync/CHANGELOG.md
/usr/share/doc/rhel-system-roles/timesync/README.html
/usr/share/doc/rhel-system-roles/timesync/README.md
/usr/share/doc/rhel-system-roles/timesync/example-multiple-ntp-servers-playbook.yml
/usr/share/doc/rhel-system-roles/timesync/example-single-pool-playbook.yml
/usr/share/licenses/rhel-system-roles/timesync.COPYING

and you can use the role from /usr/share/ansible/roles/rhel-system-roles.timesync - some examples also included there under /usr/share/doc/

1 Like

This.
The package has both names: rhel-system-roles.timesync and linux-system-roles.timesync, although the latter is just a symlink to the former.

I prefer dynamic include_role tasks to the roles: list, but the timesync has to be imported. For example:

  - ansible.builtin.import_role:
      name: rhel-system-roles.timesync
    when:
    - timesync_ntp_servers is defined
    - timesync_ntp_servers|length > 0
    tags: timesync

(Most rhel-system-roles can be included.)


As to the copy vs template I’d say that copy is ok when it is clear that parametrization will not be needed. (If you have to deploy binary data, then the template would not be an option.)

The pointed out role shows that neither copy nor template might be necessary, but that is semantic – the role does use something under its hood.

1 Like