User’s guide

Introduction

The role installs packages, creates and configures files and services. The handlers are created from user provided data. The control-flow will be determined by the user provided configuration data. Some attributes of the dictionaries determine which Ansible module will be used. This data-driven programming paradigm provides a flexible, and robust framework to apply basic Ansible modules. In the code, each Ansible module is used only once. This makes the implementation, upgrading, and testing of the modules simple and easy.

The user of this role is expected to master at least the following Ansible topics:

The supported OS (FreeBSD and Ubuntu) can use the role to install and configure arbitrary applications. Other Linux distributions, that support the used Ansible modules, should work with minimal changes. BSD*, Debian, and Red Hat ansible_os_family should work out of the box.

There are four imported tasks in the first part of the role to setup handlers, assemble, and check the configuration data:

tasks     description                  tags               enabled (default)
___________________________________________________________________________
setup     create handlers              cl_setup, always   cl_setup=true
vars      assemble configuration data  cl_vars, always    always
sanity    check sanity                 cl_sanity, always  cl_sanity=true
debug     help debugging data          cl_debug           cl_debug=false

Then, there are four imported tasks to manage the infrastructure:

tasks     description                  tags               enabled (default)
___________________________________________________________________________
packages  install packages             cl_packages        cl_install=true
states    modify states of files       cl_states          always
files     configure files              cl_files           always
services  configure services           cl_services        always
  • packages: The Ansible modules package, apt, yum, and snap are used to install Linux packages. In FreeBSD, modules pkgng and portinstall are used to install FreeBSD packages and ports.

  • states: The Ansible module mount is used to mount and unmount paths, and to configure fstab. The module file is used to modify states of files.

  • files: The Ansible modules template, copy, replace, patch, lineinfile, blockinfile, and ini_file are used to configure files.

  • services: The Ansible Module service is used to configure both Linux and BSD services.

See also

The directory contrib comprises examples on how to install and configure various applications and how to create handlers and templates. Some of them are commented Examples.

Hint

Feel free to share your feedback and report issues. The contributions to the project are welcome.

Installation

The most convenient way how to install an Ansible role is to use Ansible Galaxy CLI ansible-galaxy. The utility comes with the standard Ansible package and provides the user with a simple interface to the Ansible Galaxy’s services. For example, take a look at the current status of the role

shell> ansible-galaxy role info vbotka.config_light

and install it

shell> ansible-galaxy role install vbotka.config_light

Install the collections community.general and ansible.posix if necessary

shell> ansible-galaxy collection install ansible.posix
shell> ansible-galaxy collection install community.general

Install yamllint to use the default validation of the created handlers and assembled data. See the variables cl_assemble_validate and cl_handlers_validate in defaults/main.yml. Optionally, install and configure ansible-lint.

Note

  • By default sanity checking of yamllint is disabled (cl_sanity_yamllint: false)

Hint

  • To install specific versions from various sources see Ansible Galaxy

  • Take a look at other roles shell> ansible-galaxy search --author=vbotka

Playbook

Below is a simple playbook that calls this role (11) at a single host srv.example.com (2)

 1shell> cat pb.yml
 2- hosts: srv.example.com
 3  gather_facts: true
 4  connection: ssh
 5  remote_user: admin
 6  become: true
 7  become_user: root
 8  become_method: sudo
 9
10  roles:
11    - vbotka.config_light

Note

  • gather_facts: true (3) must be set to gather facts needed to evaluate OS-specific options of the role. For example, the variable ansible_os_family is needed to select the Ansible module to install packages.

  • For details see Connection Plugins (4-5)

  • and Understanding Privilege Escalation (6-8)

Debug

To see additional information enable debug output in the configuration

cl_debug: true

, or set the extra variable in the command:

shell> ansible-playbook pb.yml -e cl_debug=true

Note

The debug output of this role is optimized for the yaml callback plugin. Set this plugin, for example, in the environment shell> export ANSIBLE_STDOUT_CALLBACK=yaml.

Tags

The tags provide a handy tool to run selected tasks of the role. The below command lists the available tags:

1 shell> ansible-playbook pb.yml --list-tags
2
3 playbook: pb.yml
4
5   play #1 (srv.example.com): srv.example.com        TAGS: []
6   TASK TAGS: [always, cl_debug, cl_files, cl_packages, cl_sanity,
7   cl_services, cl_setup, cl_states, cl_vars]

For example, by using the tag cl_debug display the variables and their values (when enabled cl_debug: true). With this tag specified ‘-t cl_debug’ all tasks imported before the task debug.yml (setup.yml, vars.yml, and sanity.yml) will also run because of the tag always (when enabled cl_sanity: true and cl_setup: true)

shell> ansible-playbook pb.yml -t cl_debug -e cl_debug=true

See what packages will be installed

shell> ansible-playbook pb.yml -t cl_packages --check

Install packages and exit the play

shell> ansible-playbook pb.yml -t cl_packages

See also

Hint

  • Do not display skipped hosts. Set ANSIBLE_DISPLAY_SKIPPED_HOSTS=false

    shell> ANSIBLE_DISPLAY_SKIPPED_HOSTS=false ansible-playbook pb.yml -t cl_debug
    

Variables

The Default variables control the options of the role.

The most important are the variables that control the collection of the configuration data. In each project, customize the files with the configuration data stored in the directory cl_dird

Note

The names of the dictionaries in the configuration files cl_dird/*.d/* are not used by the role and can be any arbitrary strings that are valid names of Ansible variables. The names must be unique in the particular section (files.d, packages.d, …).

Default variables

Default variables are stored in the directory defaults.

Most of the variables are self-explaining. There are five very important variables cl_handlers, cl_packages, cl_states, cl_services, and cl_files (26-30). These dictionaries, which comprise the configuration data of handlers, packages, services, and files, will be explained in details. By default, these dictionaries are empty.

Best practice is to provide the data either in host_vars and group_vars or as a files in the directories cl_handlersd_dir, cl_packagesd_dir, cl_statesd_dir, cl_servicesd_dir, and cl_filesd_dir (37-41). Both methods can be applied at the same time. The variables will be assembled and combined by the tasks vars_handlers.yml, vars_packages.yml, vars_states.yml, vars_services.yml, and vars_files.yml. The assembled dictionaries, customized for each host in the play, will be stored in the host-specific files cl_packagesd, cl_statesd, cl_servicesd, and cl_filesd (60-63). The variable cl_handlers is not host-specific because the handlers will be created at the controller (localhost) only. Assembled dictionary cl_handlers will be stored in the file cl_handlersd (59). Take a look at the assembled data in the directory cl_dira (58).

By default, the base of the directories is role_path (36). The user is expected to put the configuration data to a more suitable directory, for example, to playbook_dir directory.

[defaults/main.yml]

  1---
  2# defaults for config_light
  3
  4cl_setup: true                  # Import tasks/setup.yml
  5cl_install: true                # Install packages or ports
  6cl_debug: false                 # Print debug output
  7cl_backup: false                # Backup files
  8cl_copyfile_delete: false       # Delete dest then copy samples and defaults
  9cl_template_delete: false       # Delete dest then create from templates
 10
 11# Sanity
 12cl_sanity: true                 # Import tasks/sanity.yml
 13cl_sanity_quiet: true           # Module assert, parameter quiet
 14cl_sanity_collections: false    # Test required collections
 15cl_sanity_modules_pkg: true     # Test modules in cl_packages are supported
 16cl_sanity_yamllint: false       # Test yamllint is installed
 17
 18# Supported
 19cl_supported_linux_family: [Debian, RedHat]
 20cl_supported_modules_pkg: [apt, package, pkgng, snap, yum]
 21
 22# Required collections
 23cl_collections: [ansible.posix, community.general]
 24
 25# Combine assembled data with these variables
 26cl_handlers: {}
 27cl_packages: {}
 28cl_services: {}
 29cl_files: {}
 30cl_states: {}
 31
 32# Assemble data from these directories
 33# cl_dird_owner: root        # no default
 34# cl_dird_group: adm         # no default
 35cl_dird_dmode: '0775'        # default very permissive, restrict if necessary
 36cl_dird: "{{ role_path }}/files"
 37cl_handlersd_dir: "{{ cl_dird }}/handlers.d"
 38cl_packagesd_dir: "{{ cl_dird }}/packages.d"
 39cl_servicesd_dir: "{{ cl_dird }}/services.d"
 40cl_filesd_dir: "{{ cl_dird }}/files.d"
 41cl_statesd_dir: "{{ cl_dird }}/states.d"
 42
 43# Lint
 44cl_yamllint: yamllint
 45cl_yamllint_rules:
 46  extends: default
 47  rules:
 48    line-length:
 49      level: warning
 50cl_assemble_validate: "{{ cl_yamllint }} -d '{{ cl_yamllint_rules|to_json }}' %s"
 51cl_handlers_validate: "{{ cl_yamllint }} -d '{{ cl_yamllint_rules|to_json }}' %s"
 52
 53# Assemble inventory_hostname data into these files
 54# cl_dira_owner: root        # no default
 55# cl_dira_group: adm         # no default
 56cl_dira_dmode: '0775'        # default very permissive, restrict if necessary
 57cl_dira_fmode: '0664'        # default very permissive, restrict if necessary
 58cl_dira: "{{ cl_dird }}/assemble"
 59cl_handlersd: "{{ cl_dira }}/handlersd"  # localhost; not inventory_hostname specific
 60cl_packagesd: "{{ cl_dira }}/packagesd.{{ inventory_hostname }}"
 61cl_servicesd: "{{ cl_dira }}/servicesd.{{ inventory_hostname }}"
 62cl_filesd: "{{ cl_dira }}/filesd.{{ inventory_hostname }}"
 63cl_statesd: "{{ cl_dira }}/statesd.{{ inventory_hostname }}"
 64cl_assemble_regexp: '^(.*)[^~]$' # Any string but terminated by ~
 65# Delete packagesd, servicesd, filesd, and statesd before assembling
 66cl_all_delete: false             # Delete packagesd, servicesd, filesd, and statesd
 67cl_packagesd_delete: false       # Delete packagesd
 68cl_servicesd_delete: false       # Delete servicesd
 69cl_filesd_delete: false          # Delete filesd
 70cl_statesd_delete: false         # Delete statesd
 71
 72# Role handlers directory
 73# cl_handlers_dir_owner: admin   # no default
 74# cl_handlers_dir_group: admin   # no default
 75# cl_handlers_dir_dmode: '0775'  # no default
 76# cl_handlers_main_mode: '0644'  # no default
 77cl_handlers_delete_all: false
 78cl_handlers_delete: false
 79cl_handlers_create: true
 80cl_handlers_dir_become: false
 81
 82# Snap
 83cl_snap_paths:
 84  - /usr/local/sbin
 85  - /usr/local/bin
 86  - /usr/sbin
 87  - /usr/bin
 88  - /sbin
 89  - /bin
 90# - /snap/bin
 91cl_snap_patterns:
 92  - snap
 93
 94# States
 95cl_states_unmount: [absent, unmounted]
 96cl_states_mount: [present, mounted, remounted]
 97cl_states_file: [absent, directory, file, hard, link, touch]
 98
 99# Files
100cl_files_collections:
101  copy: ansible.builtin
102  template: ansible.builtin
103  markers: ansible.builtin
104  create-backup: ansible.builtin
105  patch: ansible.posix
106  lineinfile: ansible.builtin
107  blockinfile: ansible.builtin
108  inifile: ansible.builtin
109  ucl: vbotka.freebsd
110  delete-backup: ansible.builtin
111cl_files_order: "{{ cl_files_collections|dict2items|
112                    selectattr('value', 'in', ['ansible.builtin'] + cl_collections)|
113                    map(attribute='key') }}"
114
115# OS common
116install_retries: 10
117install_delay: 5
118
119# FreeBSD
120freebsd_install_method: packages
121# freebsd_install_method: ports
122freebsd_use_packages: true
123cl_services_freebsd_rcconf_auto: false
124
125# EOF
126...

Warning

The defaults of the variables cl_dird_dmode (35), cl_dira_dmode (56) and cl_dira_fmode (57) to access the configuration data and the assembled dictionaries are very permissive. Restrict the permissions if these dictionaries might comprise classified data.

Configuration data

The configuration data describe the creation of handlers, installation of the packages or ports, and management of files and services. See the below sections on how to create the data for the Ansible modules that serve your use-case best. Review hints in the Examples.

Handlers

Synopsis

The dictionary cl_handlers comprises data to create handlers. The structure of the dictionary depends on the template that is used to create the files with the handlers. For example, the structure below can be used together with the template handlers-auto1.yml.j2.

Parameters

Parameter

Type

Comments

template

string required

Template filename

handlers

list required

List of handlers dictionaries

- handler

string required

Name of the handler

- module

string required

Ansible module in handler

- params

list required

Ansible module parameters

- conditions

list

List of conditions

Examples

FreeBSD handlers for Postfix

[contrib/postfix/conf-light/handlers.d/postfix-freebsd.yml]

 1postfix_freebsd:
 2  template: handlers-auto1.yml.j2
 3  handlers:
 4
 5    - handler: enable and start postfix
 6      module: service
 7      params:
 8        - 'name: postfix'
 9        - 'state: started'
10        - 'enabled: true'
11
12    - handler: disable and stop postfix
13      module: service
14      params:
15        - 'name: postfix'
16        - 'state: stopped'
17        - 'enabled: false'
18
19    - handler: reload postfix
20      module: service
21      params:
22        - 'name: postfix'
23        - 'state: reloaded'
24      conditions:
25        - '- cl_service_postfix_enable|bool'
26
27    - handler: restart postfix
28      module: service
29      params:
30        - 'name: postfix'
31        - 'state: restarted'
32      conditions:
33        - '- cl_service_postfix_enable|bool'
34
35    - handler: postfix check
36      module: command
37      params:
38        - 'cmd: /usr/local/sbin/postfix check'
39
40    - handler: newaliases
41      module: command
42      params:
43        - 'cmd: /usr/bin/newaliases'
44
45#    - handler: 'postmap smtp sasl passwords'
46#      module: command
47#      params:
48#        - 'cmd: /usr/local/sbin/postmap {{ postfix_main_cf_smtp_sasl_password_maps }}'
49
50#    - handler: 'postmap virtual aliases'
51#      module: command
52#      params:
53#        - cmd: /usr/local/sbin/postmap {{ postfix_virtual }}'

Create the handlers

shell> ansible-playbook pb.yml -t cl_vars -e cl_setup=true

Take a look at the file with the handlers

shell> cat roles/vbotka.config_light/handlers/handlers-auto-postfix_freebsd.yml
 1---
 2# Ansible managed
 3# Automatically generated file with handlers.
 4
 5- name: postfix_freebsd enable and start postfix
 6  service:
 7    name: postfix
 8    state: started
 9    enabled: true
10
11- name: postfix_freebsd disable and stop postfix
12  service:
13    name: postfix
14    state: stopped
15    enabled: false
16
17- name: postfix_freebsd reload postfix
18  service:
19    name: postfix
20    state: reloaded
21  when:
22    - cl_service_postfix_enable|bool
23
24- name: postfix_freebsd restart postfix
25  service:
26    name: postfix
27    state: restarted
28  when:
29    - cl_service_postfix_enable|bool
30
31- name: postfix_freebsd postfix check
32  command:
33    cmd: /usr/local/sbin/postfix check
34
35- name: postfix_freebsd newaliases
36  command:
37    cmd: /usr/bin/newaliases
38
39# EOF

The file is imported into the handlers/main.ym

shell> grep handlers-auto-postfix_freebsd.yml roles/vbotka.config_light/handlers/main.yml
- import_tasks: handlers-auto-postfix_freebsd.yml

Note

The template handlers-auto1.yml.j2 is available in the role’s directory templates. The user is expected to create new templates when needed. Feel free to change the structure of the data and to create new templates that might fit the purpose better. Feel free to contribute new templates and configuration examples to the project.

Packages

Synopsis

The dictionary cl_packages comprises managed packages (Linux or BSD) or BSD ports.

FreeBSD

By default packages will be installed. If you want to install ports set

freebsd_install_method: ports
snap

By default snap packages won’t be installed or uninstalled if snap binary can’t be found in cl_snap_paths. If you want the role to fail when snap is missing set

cl_snap_missing_fatal: true

The variables cl_snap_missing_fatal, cl_snap_paths, cl_snap_patterns are declared in defaults/main.yml.

Parameters

Parameter

Type

Comments

name

list required

List of packages or BSD ports

module

string

Ansible module to manage packages.
choices: package, apt, yum, snap, pkgng
(default=package)

state

string

State of packages or BSD ports
(default=present)

.

.

<TBD: see tasks/packages.yml>

Examples

FreeBSD install Postfix package or port

[contrib/postfix/conf-light/packages.d/postfix.yml]

1postfix:
2  module: pkgng
3  name:
4    - mail/postfix
Armbian package for Simple SMTP

[contrib/ssmtp/conf-light/packages.d/ssmtp.yml]

1ssmtp:
2  module: pkgng
3  name:
4    - mail/ssmtp
Ubuntu delete snap packages

[contrib/ubuntu-snap-disable/conf-light/packages.d/snap-deinstall.yml]

 1snap_deinstall_list1:
 2  module: snap
 3  state: absent
 4  name:
 5    - chromium
 6    - core
 7    - core18
 8    - gnome-3-28-1804
 9    - gtk-common-themes
10    - simplenote
11    - tusk
12#   - snapd
13#
14# msg: Ooops! Snap installation failed while executing 'sh -c "/usr/bin/snap remove chromium core
15# core18 gnome-3-28-1804 gtk-common-themes simplenote snapd tusk"', please examine logs and error
16# output for more details.
17# rc: 1
18# stderr: |-
19#   error: cannot remove "chromium", "core", "core18", "gnome-3-28-1804",
20#          "gtk-common-themes", "simplenote", "snapd", "tusk": snap "snapd" is not
21#          removable: remove all other snaps first
Ubuntu purge snapd package

[contrib/ubuntu-snap-disable/conf-light/packages.d/snapd.yml]

1snap_deinstall_list2:
2  module: apt
3  state: absent
4  purge: true
5  name:
6    - snapd

States

Synopsis

The dictionary cl_states comprises the states of the managed files. If mounted, the path is unmounted when state is in the list cl_states_unmount (default=absent)

cl_states_unmount: [absent, unmounted]

Then, the module file is applied if state is in the list cl_states_file (default=file)

cl_states_file: [absent, directory, file, hard, link, touch]

In the end, the path is mounted if state is in the list cl_states_mount (default=absent)

cl_states_mount: [present, mounted, remounted]

The variables cl_states_unmount, cl_states_mount, cl_states_file are declared in defaults/main.yml. Details of the parameters are described in the modules mount and file.

Parameters

Parameter

Type

Comments

path

string required

Path to file

state

string

State of the file

owner

string

Owner of the file

group

string

Group of the file

mode

string

Mode of the file

<TBD: see tasks/states.yml>

Examples

Ownership and permissions of the document root for Lighttpd

[contrib/lighttpd/conf-light/states.d/lighttpd-server-document-root.yml]

1lighttpd_server_document_root:
2  state: directory
3  path: "{{ cl_lighttpd_server_document_root }}"
4  owner: "{{ cl_lighttpd_server_username }}"
5  group: "{{ cl_lighttpd_server_groupname }}"
6  mode: '0750'
Delete snap directories

[contrib/ubuntu-snap-disable/conf-light/states.d/snap.yml]

1snap_root:
2  path: /snap
3  state: absent
4snap_var:
5  path: /var/snap
6  state: absent
7snap_lib_var:
8  path: /var/lib/snapd
9  state: absent

See also

Services

Synopsis

The dictionary cl_services comprises managed services.

Parameters

Parameter

Type

Comments

name

string required

Name of the service

state

string

State of the service default: started

enabled

boolean

Start on boot default: true

Examples

FreeBSD services for Postfix and Sendmail

[contrib/postfix/conf-light/service.d/postfix.yml]

1postfix:
2  name: postfix
3  state: "{{ cl_service_postfix_state }}"
4  enabled: "{{ cl_service_postfix_enable }}"

[contrib/postfix/conf-light/service.d/sendmail.yml]

1sendmail:
2  name: sendmail
3  state: "{{ cl_service_sendmail_state }}"
4  enabled: "{{ cl_service_sendmail_enable }}"

Files

The variable cl_files is a dictionary of the files that shall be managed by this role. It’s optional which Ansible module will be used to manage a file. More options can be applied at the same file. For example, it is possible to create a file by the Ansible module template and modify it by the module lineinfile later. Several options, listed in the default order, are available

  1. copy: If the attribute copyfile is defined in the dictionary

  2. template: If the attribute template is defined in the dictionary

  3. create blockinfile markers: If the attribute markers is defined in the dictionary

  4. patch: If the attribute patch is defined in the dictionary

  5. lineinfile: If the attribute dict or lines is defined in the dictionary

  6. blockinfile: If the attribute blocks is defined in the dictionary

  7. ini_file: If the attribute ini is defined in the dictionary

The variable cl_files_order controls the order of the execution. Multiple options, when present in the dictionary of a file definition, will be applied in this order. In addition to the options, listed above, there are create-backup and delete-backup tasks to backup files that was changed if enabled by cl_backup (default: false). By default, the backup files are created after copy, template, and markers. Fit the order of the execution to your needs.

copy

Copy files.

Parameters for copyfile

Parameter

Type

Comments

path

string required

Path to file

copyfile

dict required

copyfile parameters (see tasks/files-copy.yml)

path

string required

Path of the source file

remote_src

string

Source file from remote

force

boolean

If no, transfer if dest does not exist

<TBD>

owner

string

Owner of the file

group

string

Group of the file

mode

string

Mode of the file

attributes

string

Attributes of the file

validate

string

Command to validate file

handlers

list

List of handlers

Example of copyfile

Create the description of the file (2) and declare the variable for the dictionary (7)

[contrib/lighttpd_nagios/conf-light/files.d/lighttpd-modulesconf.yml]

 1lighttpd-modulesconf:
 2  path: /usr/local/etc/lighttpd/modules.conf
 3  create: true
 4  owner: root
 5  group: wheel
 6  mode: '0644'
 7  copyfile: "{{ cl_lighttpd_modulesconf_copy }}"
 8  markers: "{{ cl_lighttpd_modulesconf_markers }}"
 9  lines: "{{ cl_lighttpd_modulesconf_lines }}"
10  blocks: "{{ cl_lighttpd_modulesconf_blocks }}"
11  handlers:
12    - configtest lighttpd
13    - reload lighttpd

Create the dictionary cl_lighttpd_modulesconf_copy (69)

[contrib/lighttpd_nagios/cl-lighttpd.yml]

68# /usr/local/etc/lighttpd/modules.conf
69cl_lighttpd_modulesconf_copy:
70  path: /usr/local/etc/lighttpd/modules.conf.sample
71  remote_src: true
72  force: false

Then, the command

shell> ansible-playbook config-light.yml -t cl_files_copy

will copy sample file modules.conf.sample to modules.conf if the destination does not exist.

See also

template

Create files from templates.

Parameters for template

Parameter

Type

Comments

path

string required

Path to file

template

dict required

Template parameters (see files-templates.yml)

path

string required

Path of the source file

force

boolean

If no, transfer if dest does not exist

<TBD>

owner

string

Owner of the file

group

string

Group of the file

mode

string

Mode of the file

attributes

string

Attributes of the file

validate

string

Command to validate file

handlers

list

List of handlers

Example of template

File /etc/mail/mailer.conf for postfix

[contrib/postfix/conf-light/files.d/mailer-conf.yml]

1mailerconf:
2  path: /etc/mail/mailer.conf
3  template:
4    path: mailer.conf.j2
5    force: true
6  owner: root
7  group: wheel
8  mode: '0644'

See also

Note

There are couple of templates ready to be used in the directory templates. The user is expected to create new templates when needed. Feel free to contribute new templates to the project.

blockinfile markers

Create markers for Ansible module blockinfile. Mark existing blocks that you want to configure.

Parameters for blockinfile markers

Parameter

Type

Comments

path

string required

Path to file

markers

list required

List of dictionaries (see fn/mark-block.yml)

regex1

string required

Regex of block’s beginning

replace1

string required

Block’s beginning

regex2

string required

Regex of block’s ending

replace2

string required

Block’s ending

Example of blockinfile markers

For example, in file /usr/local/etc/lighttpd/modules.conf, create blockinfile markers in the following block

 1##
 2
 3server.modules = (
 4  "mod_access",
 5  #  "mod_alias",
 6  #  "mod_auth",
 7  #  "mod_authn_file",
 8  #  "mod_evasive",
 9  #  "mod_setenv",
10  #  "mod_usertrack",
11  #  "mod_redirect",
12  #  "mod_rewrite",
13  )
14
15##

Create the description of the file (2) and declare the variable for the list of the markers (8)

[contrib/lighttpd_nagios/conf-light/files.d/lighttpd-modulesconf.yml]

 1lighttpd-modulesconf:
 2  path: /usr/local/etc/lighttpd/modules.conf
 3  create: true
 4  owner: root
 5  group: wheel
 6  mode: '0644'
 7  copyfile: "{{ cl_lighttpd_modulesconf_copy }}"
 8  markers: "{{ cl_lighttpd_modulesconf_markers }}"
 9  lines: "{{ cl_lighttpd_modulesconf_lines }}"
10  blocks: "{{ cl_lighttpd_modulesconf_blocks }}"
11  handlers:
12    - configtest lighttpd
13    - reload lighttpd

Create the list of the dictionaries cl_lighttpd_modulesconf_markers (73)

[contrib/lighttpd_nagios/cl-lighttpd.yml]

68# /usr/local/etc/lighttpd/modules.conf
69cl_lighttpd_modulesconf_copy:
70  path: /usr/local/etc/lighttpd/modules.conf.sample
71  remote_src: true
72  force: false
73cl_lighttpd_modulesconf_markers:
74  - marker: server.modules
75    regex1: 'server.modules\s*=\s*\('
76    replace1: 'server.modules = ('
77    regex2: '\)'
78    replace2: ')'

Then, the command

shell> ansible-playbook config-light.yml -t cl_files_copy,cl_files_markers

will copy sample file modules.conf.sample to modules.conf and will create blockinfile markers

 1##
 2
 3# BEGIN ANSIBLE MANAGED BLOCK server.modules
 4server.modules = (
 5  "mod_access",
 6#  "mod_alias",
 7#  "mod_auth",
 8#  "mod_authn_file",
 9#  "mod_evasive",
10#  "mod_setenv",
11#  "mod_usertrack",
12#  "mod_redirect",
13#  "mod_rewrite",
14
15)
16# END ANSIBLE MANAGED BLOCK server.modules
17
18##

patch

Patch files.

Parameters for patch

Parameter

Type

Comments

path

string required

Path to file to be patched

patch

dict required

Parameters of patch module (see files-patch.yml)

src

string required

Path of the patch file

basedir

path

Apply patch in this dir

<TBD>

handlers

list

List of handlers

Example of patch

File /etc/network.subr for /etc/rc.d/wpa_cli

[contrib/freebsd-custom-image-wpacli/conf-light/files.d/network_subr.yml]

1network_subr:
2  path: "{{ bsd_cimage_mount_path }}/etc/network.subr"
3  patch:
4    src: "{{ playbook_dir }}/files/network.subr.patch"
5    basedir: "{{ bsd_cimage_mount_path }}/etc"

See also

lineinfile

Create or configure lines in a file.

Parameters for lineinfile

Parameter

Type

Comments

path

string required

Path to file

lines

list required

lineinfile params. Either dict or lines is required.

regexp

string required

Regular expression

line

string required

Line

backrefs

state

firstmatch

insertafter

insertbefore

<TBD>

assignment

string

Assignment of key and value in dict

dict

list required

lineinfile params. Either dict or lines is required. (see files-lineinfile.yml)

key

string required

Key value for regexp

value

string required

Value for line

firstmatch

insertafter

insertbefore

<TBD>

owner

string

Owner of the file

group

string

Group of the file

mode

string

Mode of the file

attributes

string

Attributes of the file

other

string

Attributes of module file

create

boolean

Create file

validate

string

Command to validate file

handlers

list

List of handlers

Example of lineinfile with lines

File /usr/local/etc/dma/dma.conf for DragonFly Mail Agent

[contrib/dma/conf-light/files.d/dma-dmaconf.yml]

1dma_dmaconf:
2  path: /usr/local/etc/dma/dma.conf
3  create: true
4  owner: root
5  group: mail
6  mode: '0644'
7  lines: "{{ cl_dma_dmaconf_lines }}"

[contrib/dma/host_vars/srv.example.com/config-light-dma.yml]

20cl_dma_dmaconf_lines:
21    - {regexp: '^SMARTHOST\s*(.*)$', line: 'SMARTHOST {{ cl_dma_smarthost }}'}
22    - {regexp: '^PORT\s*(.*)$', line: 'PORT {{ cl_dma_port }}'}
23    - {regexp: '^AUTHPATH\s*(.*)$', line: 'AUTHPATH {{ cl_dma_authpath }}'}
24    - {regexp: '^ALIASES\s*(.*)$', line: 'ALIASES {{ cl_dma_aliasespath }}'}
25    - {regexp: '^SECURETRANSFER\s*(.*)$', line: 'SECURETRANSFER'}
26    - {regexp: '^STARTTLS\s*(.*)$', line: 'STARTTLS'}
27    - {regexp: '^MASQUERADE\s*(.*)$', line: 'MASQUERADE {{ cl_dma_masquerade }}'}
Example of lineinfile with dict

File /usr/local/etc/lighttpd/lighttpd.conf for lighttpd

[contrib/lighttpd/conf-light/files.d/lighttpd-lighttpdconf.yml]

 1lighttpd-lighttpdconf:
 2  path: /usr/local/etc/lighttpd/lighttpd.conf
 3  create: true
 4  owner: root
 5  group: wheel
 6  mode: '0644'
 7  assignment: ' = '
 8  dict: "{{ cl_lighttpd_lighttpdconf_dict }}"
 9  handlers:
10    - reload lighttpd

[contrib/lighttpd/host_vars/srv.example.com/cl-lighttpd.yml]

10cl_lighttpd_lighttpdconf_dict:
11  - {key: server.port, value: '"{{ cl_lighttpd_server_port }}"'}
12  - {key: server.use-ipv6, value: '"{{ cl_lighttpd_server_useipv6 }}"'}
13  - {key: server.username, value: '"{{ cl_lighttpd_server_username }}"'}
14  - {key: server.groupname, value: '"{{ cl_lighttpd_server_groupname }}"'}
15  - {key: server.document-root, value: '"{{ cl_lighttpd_server_document_root }}"'}

See also

blockinfile

Create or configure blocks in files.

Parameters for blockinfile

Parameter

Type

Comments

path

string required

Path to file

blocks

list required

List of dictionaries (see files-blockinfile.yml)

marker

string required

Label of the marker

block

string required

Text between markers

<TBD>

owner

string

Owner of the file

group

string

Group of the file

mode

string

Mode of the file

create

boolean

Create if does not exist

validate

string

Command to validate file

handlers

list

List of handlers

Example of blockinfileinfile

Create the description of the file (2) and declare the list of the blocks (10)

[contrib/lighttpd_nagios/conf-light/files.d/lighttpd-modulesconf.yml]

 1lighttpd-modulesconf:
 2  path: /usr/local/etc/lighttpd/modules.conf
 3  create: true
 4  owner: root
 5  group: wheel
 6  mode: '0644'
 7  copyfile: "{{ cl_lighttpd_modulesconf_copy }}"
 8  markers: "{{ cl_lighttpd_modulesconf_markers }}"
 9  lines: "{{ cl_lighttpd_modulesconf_lines }}"
10  blocks: "{{ cl_lighttpd_modulesconf_blocks }}"
11  handlers:
12    - configtest lighttpd
13    - reload lighttpd

Create the list of the blocks cl_lighttpd_modulesconf_blocks (89)

[contrib/lighttpd_nagios/cl-lighttpd.yml]

84cl_lighttpd_modulesconf_server_modules:
85  - mod_access
86  - mod_alias
87  - mod_auth
88  - mod_setenv
89cl_lighttpd_modulesconf_blocks:
90  - marker: server.modules
91    block: |
92      server.modules = (
93      {% for module in cl_lighttpd_modulesconf_server_modules %}
94        "{{ module }}",
95      {% endfor %}
96      )

Then, the command

shell> ansible-playbook config-light.yml -t cl_files_blockinfile

will create this block in modules.conf

 1##
 2
 3# BEGIN ANSIBLE MANAGED BLOCK server.modules
 4server.modules = (
 5  "mod_access",
 6  "mod_alias",
 7  "mod_auth",
 8  "mod_setenv",
 9)
10# END ANSIBLE MANAGED BLOCK server.modules
11
12##

See also

ini_file

Create or configure ini entries in a file.

Parameters for ini_file

Parameter

Type

Comments

path

string required

Path to file

ini

list required

ini_file parameters list of dictionaries (see files-inifile.yml)

section

string required

Section name in INI file

option

string

Name of the option

value

string

Value of the option

state

string

If absent the option or section will be removed

allow_no_value

boolean

Allow option without value

no_extra_spaces

boolean

Do not insert spaces

<TBD>

owner

string

Owner of the file

group

string

Group of the file

mode

string

Mode of the file

attributes

string

Attributes of the file

create

boolean

Create file

handlers

list

List of handlers

Example of ini_file

<TODO: No example yet>

See also

Note

Quoting Multiple options with the same name exist #273 “There is no “The INI format”, there are many different interpretations out there what valid INI formats should be …”

Best practice

Check syntax

Check syntax of the playbook

shell> ansible-playbook pb.yml --syntax-check

Validation

Install yamllint to use the default validation of the created handlers and assembled data. See the variables cl_assemble_validate and cl_handlers_validate in defaults/main.yml. Optionally, use other linter, for example, ansible-lint and change the variables. You can disable the validation by clearing the variables

cl_assemble_validate: ''
cl_handlers_validate: ''

Setup

Assemble data, create handlers, check sanity, and display variables. When you take a look at tasks/main.yml you’ll see that the first three groups of the tasks (setup, vars, and sanity) are tagged always. As a result, when you apply the tag cl_debug all three groups of the tasks will be executed before cl_debug

shell> ansible-playbook pb.yml -t cl_debug -e cl_setup=true -e cl_sanity=true -e cl_debug=true

Manage packages

Dry-run the management of packages

shell> ansible-playbook pb.yml -t cl_packages -e cl_install=true -CD

Manage packages

shell> ansible-playbook pb.yml -t cl_packages -e cl_install=true

Then disable the installation cl_install=false to speedup the playbook.

Manage states of files

Dry-run the management of files’ states

shell> ansible-playbook pb.yml -t cl_states -CD

Set the states (existence and attributes) of the files

shell> ansible-playbook pb.yml -t cl_states

Manage configuration files

Dry-run the configuration of files

shell> ansible-playbook pb.yml -t cl_files -CD

Create and modify files

shell> ansible-playbook pb.yml -t cl_files

Manage services

Dry-run the configuration of services

shell> ansible-playbook pb.yml -t cl_services -CD

Configure services

shell> ansible-playbook pb.yml -t cl_services

Hint

If you know what you are doing skip the above selection of particular tags and run the complete role at once

shell> ansible-playbook pb.yml -e cl_setup=true -e cl_install=true

Idempotency

The role and the configuration data in the examples are idempotent. When the application is installed and configured there should be no changes reported by ansible-playbook when running the playbook repeatedly. Disable setup, sanity, debug, and install to speedup the execution when running the playbook periodically to audit the configuration

shell> ansible-playbook pb.yml -e cl_setup=false \
                               -e cl_sanity=false \
                               -e cl_debug=false \
                               -e cl_install=false