521 iocage plugins ansible-pull-syslogng-*

Use case

Configure and run a log server. Configure log clients and test them. Use syslog-ng. Clone the iocage plugins ansible-pull-syslogng-server and ansible-pull-syslogng-client.

Quoting syslog-ng - FreeBSD Wiki:

“One of the most typical use of syslog-ng is central log aggregation. … It collects log messages on TCP port 514 and saves them to directories and files based on sender host name and current date.”

Tree

shell > tree .
.
├── ansible.cfg
├── group_vars
│   └── all
│       ├── common.yml
│       └── project-hosts.yml
├── hosts
│   └── 05_iocage.yml
├── host_vars
│   └── iocage_05
│       └── syslog-ng.yml
├── iocage.ini
├── pb-create-jails.yml
├── pb-logclient-test.yml
└── pb-logserver-test.yml

Synopsis

Requirements

Important

For security reasons, you might want to create private repositories with the iocage plugins and configurations. See the example 523 iocage template ansible-repos

Note

ansible.cfg

[defaults]
callback_result_format = yaml
deprecation_warnings = false
display_skipped_hosts = false
gathering = explicit
interpreter_python = auto_silent
log_path = /var/log/ansible.log

[connection]
pipelining = true

Inventory iocage.ini

iocage_05

[iocage]
iocage_05

[iocage:vars]
ansible_user=admin
ansible_become=true
ansible_python_interpreter=auto_silent

hosts

hosts/05_iocage.yml
plugin: vbotka.freebsd.iocage
host: iocage_05
user: admin
sudo: true
get_properties: true
inventory_hostname_tag: alias

compose:
  iocage_tags: dict(iocage_properties.notes | regex_findall('(\w+)=([\w\-]+)'))
  iocage_classes: iocage_properties.notes | regex_findall('(?<=class=)[\w\-]+|(?<=,)[\w\-]+')
# connection plugin vbotka.freebsd.jailexec
  ansible_connection: "'vbotka.freebsd.jailexec'"
  ansible_jail_host: dict(iocage_properties.notes | regex_findall('(\w+)=([\w\-]+)')).vmm | d('none')
  ansible_jail_name: iocage_jid
  ansible_jail_privilege_escalation: "'sudo'"

groups:
  log_servers: iocage_classes is contains('log-server')
  log_clients: iocage_classes is contains('log-client')


keyed_groups:
  - prefix: state
    key: iocage_state
  - prefix: vmm
    key: iocage_tags.vmm

group_vars

group_vars/all/common.yml
ansible_python_interpreter: auto_silent
group_vars/all/project-hosts.yml
project_hosts:
  iocage_05:
    defaultrouter: 172.16.99.1 
    log_server: 172.16.99.10
    # repositories
    repos: 172.16.99.21
    repos_devel: 172.16.99.22
    # plugins
    ansible_pull_syslogng_server: 172.16.99.31

host_vars

host_vars/iocage_05/syslog-ng.yml
enabled_plugins:
  - ansible-pull-syslogng-client
  - ansible-pull-syslogng-server

plugins:
  ansible-pull-syslogng-server:
    git: https://github.com/vbotka/iocage-plugins
    branch: main
    properties:
      ip4: disable
      ip6: disable
      ip6_addr: none
      boot: 0
      defaultrouter: "{{ project_hosts[inventory_hostname]['defaultrouter'] }}"
      ip4_addr: "vnet0|{{ project_hosts[inventory_hostname]['ansible_pull_syslogng_server'] }}/24"
      vnet: 1
  ansible-pull-syslogng-client:
    git: https://github.com/vbotka/iocage-plugins
    branch: main
    properties:
      ip4: disable
      ip6: disable
      ip6_addr: none
      boot: 0
      bpf: 1
      dhcp: 1
      vnet: 1

log_server_properties:
  ip4: disable
  ip6: disable
  ip6_addr: none
  type: jail
  boot: 1
  defaultrouter: "{{ project_hosts[inventory_hostname]['defaultrouter'] }}"
  ip4_addr: "vnet0|{{ project_hosts[inventory_hostname]['log_server'] }}/24"
  vnet: 1

log_client_properties:
  ip4: disable
  ip6: disable
  ip6_addr: none
  type: jail
  boot: 1
  bpf: 1
  dhcp: 1
  vnet: 1

log_clients:
  - foo
  - bar

Playbook output - Fetch iocage plugins

(env) > ansible-playbook vbotka.freebsd.pb_iocage_plugins.yml \
                         -i iocage.ini \
                         -t enabled_plugins \
                         -e debug=true
PLAY [Fetch and stop iocage plugins.] ******************************************

TASK [One tag is required.] ****************************************************
ok: [iocage_05]

TASK [Test the tag is known.] **************************************************
ok: [iocage_05]

TASK [Get already fetched plugins.] ********************************************
ok: [iocage_05]

TASK [Debug fetched plugins debug=true] ****************************************
ok: [iocage_05] => 
    msg: |-
        iocage_plugins:
          ansible-pull-syslogng-client:
              boot: 'off'
              doc_url: '-'
              ip4: '-'
              ip4_dict:
                  ip4: []
                  msg: DHCP (not running)
              ip6: '-'
              jid: None
              portal: '-'
              release: 15.0-RELEASE
              state: down
              template: '-'
              type: pluginv2
          ansible-pull-syslogng-server:
              boot: 'off'
              doc_url: '-'
              ip4: 172.16.99.31
              ip4_dict:
                  ip4:
                  -   ifc: vnet0
                      ip: 172.16.99.31
                      mask: '24'
                  msg: ''
              ip6: '-'
              jid: None
              portal: '-'
              release: 15.0-RELEASE
              state: down
              template: '-'
              type: pluginv2
          ansible-pull-test:
              boot: 'off'
              doc_url: '-'
              ip4: '-'
              ip4_dict:
                  ip4: []
                  msg: DHCP (not running)
              ip6: '-'
              jid: None
              portal: '-'
              release: 15.0-RELEASE
              state: down
              template: '-'
              type: pluginv2

        plugins:
          ansible-pull-syslogng-client:
              branch: main
              git: https://github.com/vbotka/iocage-plugins
              properties:
                  boot: 0
                  bpf: 1
                  dhcp: 1
                  ip4: disable
                  ip6: disable
                  ip6_addr: none
                  vnet: 1
          ansible-pull-syslogng-server:
              branch: main
              git: https://github.com/vbotka/iocage-plugins
              properties:
                  boot: 0
                  defaultrouter: 172.16.99.1
                  ip4: disable
                  ip4_addr: vnet0|172.16.99.31/24
                  ip6: disable
                  ip6_addr: none
                  vnet: 1

TASK [Set required plugins.] ***************************************************
ok: [iocage_05]

TASK [Debug selected plugins debug=true] ***************************************
ok: [iocage_05] => 
    msg: |-
        required_plugins:
          - ansible-pull-syslogng-client
        - ansible-pull-syslogng-server

        selected_plugins:
          []

TASK [Check all required plugins are included in the dictionary plugins.] ******
ok: [iocage_05]

PLAY RECAP *********************************************************************
iocage_05                  : ok=7    changed=0    unreachable=0    failed=0    skipped=3    rescued=0    ignored=0   

List iocage plugins

shell > ssh admin@iocage_05 sudo iocage list -P
+------+------------------------------+------+-------+----------+--------------+-----------------------+-----+----------+--------+---------+
| JID  |             NAME             | BOOT | STATE |   TYPE   |   RELEASE    |          IP4          | IP6 | TEMPLATE | PORTAL | DOC_URL |
+======+==============================+======+=======+==========+==============+=======================+=====+==========+========+=========+
| None | ansible-pull-syslogng-client | off  | down  | pluginv2 | 15.0-RELEASE | DHCP (not running)    | -   | -        | -      | -       |
+------+------------------------------+------+-------+----------+--------------+-----------------------+-----+----------+--------+---------+
| None | ansible-pull-syslogng-server | off  | down  | pluginv2 | 15.0-RELEASE | vnet0|172.16.99.31/24 | -   | -        | -      | -       |
+------+------------------------------+------+-------+----------+--------------+-----------------------+-----+----------+--------+---------+
| None | ansible-pull-test            | off  | down  | pluginv2 | 15.0-RELEASE | DHCP (not running)    | -   | -        | -      | -       |
+------+------------------------------+------+-------+----------+--------------+-----------------------+-----+----------+--------+---------+

Playbook pb-create-jails.yml

---
- name: Create jails from iocage plugins.
  hosts: iocage_05

  vars:

    client_exist: "{{ groups.all | intersect(log_clients) }}"

  tasks:

    - name: log_client exist.
      when: client_exist | length > 0
      block:

        - name: Assert log_client is in groups.log_clients
          vars:
            missing: "{{ client_exist | difference(groups.log_clients | d([])) }}"
          ansible.builtin.assert:
            that: missing | length == 0
            fail_msg: "[ERR] {{ missing | join(', ') }} not in group log_clients"
            quiet: true

        - name: Display message.
          ansible.builtin.debug:
            msg: "[INFO] {{ client_exist | join(', ') }} exist(s)."

    - name: Create log clients.
      vars:
        _notes: >-
          "vmm={{ inventory_hostname }}
          class=log-client
          alias={{ item }}"
        _properties: >-
          {% for k, v in log_client_properties.items() %}
          {{ k }}={{ v }}
          {% endfor %}
          notes={{ _notes }}
      ansible.builtin.command: >
        iocage clone
        --newmac
        ansible-pull-syslogng-client
        {{ _properties }}
      loop: "{{ log_clients | difference(client_exist) }}"

    - name: End of host if log_server exists.
      when: groups.all is contains('log_server')
      block:

        - name: Assert log_server is in groups.log_servers
          ansible.builtin.assert:
            that: groups.log_servers | d([]) is contains('log_server')
            fail_msg: '[ERR] log_server not in groups.log_servers'
            quiet: true

        - name: Display message.
          ansible.builtin.debug:
            msg: '[INFO] log_server exists.'

        - name: End of host.
          ansible.builtin.meta: end_host

    - name: Create log_server
      vars:
        _notes: >-
          "vmm={{ inventory_hostname }}
          class=log-server
          alias=log_server"
        _properties: >-
          {% for k, v in log_server_properties.items() %}
          {{ k }}={{ v }}
          {% endfor %}
          notes={{ _notes }}
      ansible.builtin.command: >
        iocage clone
        --newmac
        ansible-pull-syslogng-server
        {{ _properties }}

Playbook output - Create jails from iocage plugins

(env) > ansible-playbook pb-create-jails.yml.yml -i iocage.ini -i hosts
PLAY [Create jails from iocage plugins.] ***************************************

TASK [Create log clients.] *****************************************************
changed: [iocage_05] => (item=foo)
changed: [iocage_05] => (item=bar)

TASK [Create log_server] *******************************************************
changed: [iocage_05]

PLAY RECAP *********************************************************************
iocage_05                  : ok=2    changed=2    unreachable=0    failed=0    skipped=4    rescued=0    ignored=0   

Inventory graph

shell > ansible-inventory -i hosts --graph
@all:
  |--@ungrouped:
  |--@state_down:
  |  |--ansible-pull-syslogng-client
  |  |--ansible-pull-syslogng-server
  |  |--ansible-pull-test
  |--@state_up:
  |  |--repos
  |  |--bar
  |  |--foo
  |  |--log_server
  |  |--repos_devel
  |--@vmm_iocage_05:
  |  |--repos
  |  |--bar
  |  |--foo
  |  |--log_server
  |  |--repos_devel
  |--@log_clients:
  |  |--bar
  |  |--foo
  |--@log_servers:
  |  |--log_server

List jails

shell > ssh admin@iocage_05 sudo iocage list -l
+------+--------------------------------------+------+-------+----------+--------------+-----------------------+-----+------------------------------+----------+
| JID  |                 NAME                 | BOOT | STATE |   TYPE   |   RELEASE    |          IP4          | IP6 |           TEMPLATE           | BASEJAIL |
+======+======================================+======+=======+==========+==============+=======================+=====+==============================+==========+
| 26   | ae577716-d682-4f90-9f80-d54ef87bb00e | on   | up    | jail     | 15.0-RELEASE | epair0b|172.16.99.192 | -   | ansible-pull-syslogng-client | yes      |
+------+--------------------------------------+------+-------+----------+--------------+-----------------------+-----+------------------------------+----------+
| None | ansible-pull-syslogng-client         | off  | down  | pluginv2 | 15.0-RELEASE | DHCP (not running)    | -   | -                            | yes      |
+------+--------------------------------------+------+-------+----------+--------------+-----------------------+-----+------------------------------+----------+
| None | ansible-pull-syslogng-server         | off  | down  | pluginv2 | 15.0-RELEASE | vnet0|172.16.99.31/24 | -   | -                            | yes      |
+------+--------------------------------------+------+-------+----------+--------------+-----------------------+-----+------------------------------+----------+
| None | ansible-pull-test                    | off  | down  | pluginv2 | 15.0-RELEASE | DHCP (not running)    | -   | -                            | yes      |
+------+--------------------------------------+------+-------+----------+--------------+-----------------------+-----+------------------------------+----------+
| 25   | be7bcbc8-af70-4784-86a4-34811ba1136f | on   | up    | jail     | 15.0-RELEASE | epair0b|172.16.99.191 | -   | ansible-pull-syslogng-client | yes      |
+------+--------------------------------------+------+-------+----------+--------------+-----------------------+-----+------------------------------+----------+
| 27   | fce96a84-8d2a-451f-8887-f4aebb0ad31a | on   | up    | jail     | 15.0-RELEASE | vnet0|172.16.99.10/24 | -   | ansible-pull-syslogng-server | yes      |
+------+--------------------------------------+------+-------+----------+--------------+-----------------------+-----+------------------------------+----------+
| 2    | repos                                | on   | up    | jail     | 15.0-RELEASE | vnet0|172.16.99.21/24 | -   | ansible-repos                | no       |
+------+--------------------------------------+------+-------+----------+--------------+-----------------------+-----+------------------------------+----------+
| 3    | repos-devel                          | on   | up    | jail     | 15.0-RELEASE | vnet0|172.16.99.22/24 | -   | ansible-repos                | no       |
+------+--------------------------------------+------+-------+----------+--------------+-----------------------+-----+------------------------------+----------+

Playbook pb-logserver-test.yml

---
- name: Test Log Server.
  hosts: log_servers
    
  tasks:

    - name: Run commands.
      register: out
      ansible.builtin.shell: "{{ item }}"
      loop:
        - rm -rf /var/log/remote/localhost/*
        - service syslog-ng status
        - loggen -i -S -n 1 localhost 514
        - sleep 5; find /var/log/remote/localhost/ -name *.log | xargs cat

    - name: Debug.
      when: debug | d(false) | bool
      ansible.builtin.debug:
        msg: |
          {% for i in out.results %}
          shell> {{ i.item }}
          {% if i.stdout | length > 0 %}
          {{ i.stdout }}
          {% endif %}
          {% if i.stderr | length > 0 %}
          {{ i.stderr }}
          {% endif %}

          {% endfor %}

Playbook output - Test Log Server

(env) > ansible-playbook pb-logserver-test.yml -i hosts -e debug=true
PLAY [Test Log Server.] ********************************************************

TASK [Run commands.] ***********************************************************
changed: [log_server] => (item=rm -rf /var/log/remote/localhost/*)
changed: [log_server] => (item=service syslog-ng status)
changed: [log_server] => (item=loggen -i -S -n 1 localhost 514)
changed: [log_server] => (item=sleep 5; find /var/log/remote/localhost/ -name *.log | xargs cat)

TASK [Debug.] ******************************************************************
ok: [log_server] => 
    msg: |-
        shell> rm -rf /var/log/remote/localhost/*

        shell> service syslog-ng status
        syslog_ng is running as pid 59400.

        shell> loggen -i -S -n 1 localhost 514
        count=1, rate = 125000.00 msg/sec
        average rate = 2.00 msg/sec, count=1, time=0.500228, (average) msg size=256, bandwidth=0.50 kB/sec

        shell> sleep 5; find /var/log/remote/localhost/ -name *.log | xargs cat
        Jun 28 10:53:09 localhost prg00000[1234]: seq: 0000000000, thread: 0000, runid: 1782636789, stamp: 2026-06-28T10:53:09 PADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADD

PLAY RECAP *********************************************************************
log_server                 : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Playbook pb-logclient-test.yml

---
- name: Test Log Clients.
  hosts: log_clients

  vars:

    log_server: "{{ hostvars['log_server']['iocage_ip4'] }}"

  tasks:

    - name: Run loggen
      register: out
      ansible.builtin.command: "loggen -i -S -n 1 {{ log_server }} 514"

    - name: Debug.
      ansible.builtin.debug:
        var: out.stderr

- name: Display the logs.
  hosts: log_server
    
  tasks:

    - name: Get log files paths.
      register: out
      ansible.builtin.find:
        paths: /var/log/remote
        recurse: true
        patterns: '*.log'

    - name: Get log files.
      register: out
      ansible.builtin.command: "cat {{ item }}"
      loop: "{{ out.files | map(attribute='path') }}"

    - name: Display log files.
      ansible.builtin.debug:
        msg: |
          {{ item.stdout }}

          - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      loop: "{{ out.results }}"
      loop_control:
        label: "{{ item.cmd }}"

Playbook output - Test Log Clients

(env) > ansible-playbook pb-logclient-test.yml -i hosts
PLAY [Test Log Clients.] *******************************************************

TASK [Run loggen] **************************************************************
changed: [foo]
changed: [bar]

TASK [Debug.] ******************************************************************
ok: [bar] => 
    out.stderr: |-
        count=1, rate = 166666.67 msg/sec
        average rate = 2.00 msg/sec, count=1, time=0.500381, (average) msg size=256, bandwidth=0.50 kB/sec
ok: [foo] => 
    out.stderr: |-
        count=1, rate = 125000.00 msg/sec
        average rate = 2.00 msg/sec, count=1, time=0.500329, (average) msg size=256, bandwidth=0.50 kB/sec

PLAY [Display the logs.] *******************************************************

TASK [Get log files paths.] ****************************************************
ok: [log_server]

TASK [Get log files.] **********************************************************
changed: [log_server] => (item=/var/log/remote/172.16.99.192/2026_06_28.log)
changed: [log_server] => (item=/var/log/remote/172.16.99.191/2026_06_28.log)

TASK [Display log files.] ******************************************************
ok: [log_server] => (item=['cat', '/var/log/remote/172.16.99.192/2026_06_28.log']) => 
    msg: |-
        Jun 28 10:52:06 172.16.99.192 prg00000[1234]: seq: 0000000000, thread: 0000, runid: 1782636726, stamp: 2026-06-28T10:52:06 PADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADD

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ok: [log_server] => (item=['cat', '/var/log/remote/172.16.99.191/2026_06_28.log']) => 
    msg: |-
        Jun 28 10:52:06 172.16.99.191 prg00000[1234]: seq: 0000000000, thread: 0000, runid: 1782636726, stamp: 2026-06-28T10:52:06 PADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADDPADD

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

PLAY RECAP *********************************************************************
bar                        : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
foo                        : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
log_server                 : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Hint

Use lnav utility on the log server to display all logfiles in the the directory /var/log/remote. For example,

shell > iocage console c8a9d789-fa02-4ce3-af66-41c848f87b0f
root@c8a9d789-fa02-4ce3-af66-41c848f87b0f:~ # lnav -r /var/log/remote/

To find the UUID, run iocage list -l and look for the jail created from the template ansible-pull-syslogng-server.