Usage as a role dependency
The debops.postfix
role can be used as a dependency by other Ansible roles
to manage contents of the /etc/postfix/main.cf
and
/etc/postfix/master.cf
configuration files idempotently. Configuration
options from multiple roles can be merged together and included in the Postfix
configuration, or removed conditionally.
Dependent role variable
The role exposes the postfix__dependent_maincf
and
postfix__dependent_mastercf
variables which can be used to define
Postfix configuration options and services by other Ansible roles through the
role dependent variables.
The variables are an YAML lists with YAML dictionaries as entries. A short format of the configuration uses the dictionary key as a name of the dependent role and dictionary value as that role's configuration, in the format defined by Default variable details: postfix__maincf and Default variable details: postfix__mastercf variables, respectively (see playbook excerpt below):
roles:
- role: debops.postfix
postfix__dependent_maincf:
- role_name: '{{ role_name__postfix__dependent_maincf }}'
postfix__dependent_mastercf:
- role_name: '{{ role_name__postfix__dependent_mastercf }}'
The extended version of the configuration uses YAML dictionaries with specific parameters:
role
Required. Name of the role, used to save its configuration in a YAML dictionary on the Ansible Controller. Shouldn't be changed once selected, otherwise the configuration will be desynchronized.
config
Required. YAML list with configuration of the Postfix options and services in the same format defined by Default variable details: postfix__maincf and Default variable details: postfix__mastercf variables.
state
Optional. If not specified or
present
, the configuration will be included in the generated configuration files. Ifabsent
, the configuration will be removed from the configuration files. Ifignore
, a given configuration entries will be skipped during data evaluation and won't affect any existing entries.
An example extended configuration (playbook excerpt):
roles:
- role: debops.postfix
postfix__dependent_maincf:
- role: 'role_name'
config: '{{ role_name__postfix__dependent_maincf }}'
postfix__dependent_mastercf:
- role: 'role_name'
config: '{{ role_name__postfix__dependent_mastercf }}'
The above configuration layout allows for use of the multiple role dependencies in one playbook by providing configuration of each role in a separate configuration entry.
Dependent configuration storage and retrieval
The dependent configuration from other roles is stored in the secret/
directory on the Ansible Controller (see debops.secret for more details) in
a JSON file (one for each variable), with each role configuration in a separate
dictionary. The debops.postfix
role reads these files when Ansible local
facts indicate that the Postfix is installed, otherwise empty files are
created. This ensures that the stale configuration is not present on a new or
re-installed host.
The YAML dictionaries from different roles are merged with the main
configuration in the postfix__combined_maincf
and
postfix__combined_mastercf
variables that are used to generate the
final configuration. The merge order of the different postfix__*_maincf
and
postfix__*_mastercf
variables allows to further affect the dependent
configuration through Ansible inventory if necessary, therefore the Ansible
roles that use this method don't need to provide additional variables for this
purpose themselves.
Example role default variables
---
# This is a set of default variables in an example 'application' role that uses
# dependent variables to pass configuration to 'debops.postfix' role.
# Additional APT packages to install for Postfix
application__postfix__dependent_packages:
- 'postfix-pgsql'
# Postfix main.cf configuration
application__postfix__dependent_maincf:
- name: 'application_destination_recipient_limit'
value: 1
# Postfix master.cf configuration
application__postfix__dependent_mastercf:
- name: 'application'
type: 'unix'
unpriv: False
chroot: False
command: 'pipe'
args: |
flags=FR user=application argv=/usr/local/lib/application/bin/in-pipe
${nexthop} ${user}
Example role playbook
---
# This is a playbook for an example 'application' role which uses
# 'debops.postfix' as a dependency and passes its own set of
# configuration options to it.
- name: Manage application
collections: [ 'debops.debops' ]
hosts: [ 'debops_service_application' ]
become: True
environment: '{{ inventory__environment | d({})
| combine(inventory__group_environment | d({}))
| combine(inventory__host_environment | d({})) }}'
pre_tasks:
# This role along with 'debops.etc_aliases' can be used to maintain the
# /etc/aliases database.
#
#- name: Prepare etc_aliases environment
# import_role:
# name: 'etc_aliases'
# tasks_from: 'main_env'
# tags: [ 'role::etc_aliases', 'role::secret', 'role::postfix' ]
- name: Prepare postfix environment
ansible.builtin.import_role:
name: 'postfix'
tasks_from: 'main_env'
tags: [ 'role::postfix', 'role::secret', 'role::ferm' ]
roles:
- role: secret
tags: [ 'role::secret', 'role::postfix' ]
secret__directories:
- '{{ postfix__secret__directories }}'
# Normally a 'debops.ferm' role would be here for 'debops.postfix'
# to manage the firewall. You don't need it if you run the main
# 'debops.postfix' playbook before yours.
#
#- role: ferm
# tags: [ 'role::ferm', 'skip::ferm' ]
# ferm__dependent_rules:
# - '{{ etc_aliases__secret__directories }}'
# - '{{ postfix__ferm__dependent_rules }}'
#- role: etc_aliases
# tags: [ 'role::etc_aliases' ]
- role: postfix
tags: [ 'role::postfix' ]
postfix__dependent_packages:
- '{{ application__postfix__dependent_packages }}'
postfix__dependent_maincf:
# Short form of dependent configuration
- application: '{{ application__postfix__dependent_maincf }}'
postfix__dependent_mastercf:
# Expanded form of dependent configuration
- role: 'application'
config: '{{ application__postfix__dependent_mastercf }}'
state: 'present'
- role: application
tags: [ 'role::application' ]