300 Module vbotka.freebsd.service

Use case

Test the module vbotka.freebsd.service.

Tree

shell> tree .
.
├── ansible.cfg
├── hosts
│   ├── 04_iocage.yml
│   └── 99_constructed.yml
├── iocage.ini
├── pb-test-01.yml
├── pb-test-02.yml
├── pb-test-03.yml
├── pb-test-04.yml
├── pb-test-05.yml
├── pb-test-06.yml
└── pb-test-07.yml

Synopsis

At all running jails in iocage_04:

  • playbook pb-test-01.yml: display sshd rcvar.

  • playbook pb-test-06.yml: display sendmail rcvar.

At the managed node iocage_04:

  • playbook pb-test-02.yml: display sshd rcvar

  • playbook pb-test-03.yml: display enabled services

  • playbook pb-test-04.yml: display sshd status

  • playbook pb-test-05.yml: display sshd commands synopsis

  • playbook pb-test-07.yml: start apcupsd.

Requirements

Notes

  • Jail name doesn’t work in iocage jails. Use JID instead.

See also

Jails at iocage_04

[iocage_04]# iocage list -l
+-----+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+
| JID |   NAME   | BOOT | STATE | TYPE |     RELEASE     |        IP4         | IP6 |    TEMPLATE    | BASEJAIL |
+=====+==========+======+=======+======+=================+====================+=====+================+==========+
| 81  | test_131 | off  | up    | jail | 15.0-RELEASE-p3 | epair0b|10.1.0.224 | -   | ansible_client | no       |
+-----+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+
| 80  | test_132 | off  | up    | jail | 15.0-RELEASE-p3 | epair0b|10.1.0.185 | -   | ansible_client | no       |
+-----+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+
| 82  | test_133 | off  | up    | jail | 15.0-RELEASE-p3 | epair0b|10.1.0.225 | -   | ansible_client | no       |
+-----+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+

ansible.cfg

[defaults]
gathering = explicit
callback_result_format = yaml
display_skipped_hosts = false
host_key_checking = false

[connection]
pipelining = true

Inventory iocage.ini

iocage_01 ansible_host=10.1.0.18
iocage_02 ansible_host=10.1.0.73
iocage_03 ansible_host=10.1.0.17
iocage_04 ansible_host=10.1.0.29

[iocage]
iocage_04

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

Inventory hosts

plugin: vbotka.freebsd.iocage
host: 10.1.0.29
user: admin
get_properties: True
hooks_results:
  - /var/db/dhclient-hook.address.epair0b
compose:
  ansible_host: (iocage_hooks.0 == '-') | ternary(iocage_ip4, iocage_hooks.0)
  iocage_tags: dict(iocage_properties.notes | regex_findall('(\w+)=([\w\-]+)'))
plugin: ansible.builtin.constructed
groups:
    up: iocage_state == 'up'

Display inventory

(env) > ansible-inventory -i hosts --graph
@all:
  |--@ungrouped:
  |--@up:
  |  |--test_131
  |  |--test_132
  |  |--test_133

Playbook pb-test-01.yml

- name: Test module vbotka.freebsd.service. Get running jails sshd rcvar.
  hosts: up
  remote_user: admin

  vars:

    debug: false
    ansible_python_interpreter: auto_silent
    sshd_rcvar: "{{ out.stdout | community.general.jc('ini') }}"
    
  tasks:

    - name: Get sshd rcvar.
      vbotka.freebsd.service:
        script: sshd
        command: rcvar
      register: out

    - ansible.builtin.debug:
        var: out
      when: debug | bool

    - ansible.builtin.debug:
        var: out.stdout

    - ansible.builtin.debug:
        var: sshd_rcvar

    - ansible.builtin.debug:
        var: out.rcvar

Playbook output - jails sshd rcvar

The key and value of rcvar is returned in 1) the attribute rcvar of the registered variable out.rcvar and in 2) the stdout. Usually, you’ll use the first option. The second option shows how to use the filter``community.general.jc``.

(env) > ansible-playbook pb-test-01.yml -i hosts
PLAY [Test module vbotka.freebsd.service. Get running jails sshd rcvar.] *******

TASK [Get sshd rcvar.] *********************************************************
ok: [test_131]
ok: [test_132]
ok: [test_133]

TASK [ansible.builtin.debug] ***************************************************
ok: [test_131] => 
    out.stdout: |-
        # sshd : Secure Shell Daemon
        #
        sshd_enable="YES"
        #   (default: "")
ok: [test_132] => 
    out.stdout: |-
        # sshd : Secure Shell Daemon
        #
        sshd_enable="YES"
        #   (default: "")
ok: [test_133] => 
    out.stdout: |-
        # sshd : Secure Shell Daemon
        #
        sshd_enable="YES"
        #   (default: "")

TASK [ansible.builtin.debug] ***************************************************
ok: [test_131] => 
    sshd_rcvar:
        sshd_enable: 'YES'
ok: [test_132] => 
    sshd_rcvar:
        sshd_enable: 'YES'
ok: [test_133] => 
    sshd_rcvar:
        sshd_enable: 'YES'

TASK [ansible.builtin.debug] ***************************************************
ok: [test_131] => 
    out.rcvar:
        sshd_enable: 'YES'
ok: [test_132] => 
    out.rcvar:
        sshd_enable: 'YES'
ok: [test_133] => 
    out.rcvar:
        sshd_enable: 'YES'

PLAY RECAP *********************************************************************
test_131                   : ok=4    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
test_132                   : ok=4    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
test_133                   : ok=4    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   

Playbook pb-test-02.yml

- name: Test module vbotka.freebsd.service. Set dictionary jid_rcvar.
  hosts: iocage

  vars:

    debug: false
    jails: "{{ iocage_list_out.stdout | vbotka.freebsd.iocage('jails') }}"
    jids: "{{ jails | dict2items
                    | selectattr('value.state', 'eq', 'up')
                    | map(attribute='value.jid') }}"
    jid_rcvar: "{{ dict(keys | zip(vals)) }}"
    keys: "{{ service_out.results | map(attribute='item') }}"
    vals: "{{ service_out.results | map(attribute='stdout')
                                  | map('community.general.jc', 'ini') }}"

  tasks:

    - name: Get iocage list of jails.
      environment:
        CRYPTOGRAPHY_OPENSSL_NO_LEGACY: 1
      register: iocage_list_out
      changed_when: false
      ansible.builtin.command: iocage list --long

    - ansible.builtin.debug:
        var: iocage_list_out
      when: debug | bool

    - ansible.builtin.debug:
        var: jails | to_yaml

    - ansible.builtin.debug:
        var: jids | to_yaml

    - name: Jails service sshd rcvar.
      register: service_out
      vbotka.freebsd.service:
        jail: "{{ item }}"
        script: sshd
        command: rcvar
      loop: "{{ jids }}"

    - ansible.builtin.debug:
        var: service_out
      when: debug | bool

    - ansible.builtin.debug:
        var: jid_rcvar

Playbook output - create jid_rcvar

(env) > ansible-playbook pb-test-02.yml -i iocage.ini -e debug=true
PLAY [Test module vbotka.freebsd.service. Set dictionary jid_rcvar.] ***********

TASK [Get iocage list of jails.] ***********************************************
ok: [iocage_04]

TASK [ansible.builtin.debug] ***************************************************
ok: [iocage_04] => 
    iocage_list_out:
        ansible_facts:
            discovered_interpreter_python: /usr/local/bin/python3.11
        changed: false
        cmd:
        - iocage
        - list
        - --long
        delta: '0:00:00.235170'
        end: '2026-02-24 23:42:46.465010'
        failed: false
        msg: ''
        rc: 0
        start: '2026-02-24 23:42:46.229840'
        stderr: ''
        stderr_lines: []
        stdout: |-
            +-----+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+
            | JID |   NAME   | BOOT | STATE | TYPE |     RELEASE     |        IP4         | IP6 |    TEMPLATE    | BASEJAIL |
            +=====+==========+======+=======+======+=================+====================+=====+================+==========+
            | 81  | test_131 | off  | up    | jail | 15.0-RELEASE-p3 | epair0b|10.1.0.224 | -   | ansible_client | no       |
            +-----+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+
            | 80  | test_132 | off  | up    | jail | 15.0-RELEASE-p3 | epair0b|10.1.0.185 | -   | ansible_client | no       |
            +-----+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+
            | 82  | test_133 | off  | up    | jail | 15.0-RELEASE-p3 | epair0b|10.1.0.225 | -   | ansible_client | no       |
            +-----+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+
        stdout_lines:
        - +-----+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+
        - '| JID |   NAME   | BOOT | STATE | TYPE |     RELEASE     |        IP4         |
            IP6 |    TEMPLATE    | BASEJAIL |'
        - +=====+==========+======+=======+======+=================+====================+=====+================+==========+
        - '| 81  | test_131 | off  | up    | jail | 15.0-RELEASE-p3 | epair0b|10.1.0.224
            | -   | ansible_client | no       |'
        - +-----+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+
        - '| 80  | test_132 | off  | up    | jail | 15.0-RELEASE-p3 | epair0b|10.1.0.185
            | -   | ansible_client | no       |'
        - +-----+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+
        - '| 82  | test_133 | off  | up    | jail | 15.0-RELEASE-p3 | epair0b|10.1.0.225
            | -   | ansible_client | no       |'
        - +-----+----------+------+-------+------+-----------------+--------------------+-----+----------------+----------+

TASK [ansible.builtin.debug] ***************************************************
ok: [iocage_04] => 
    jails | to_yaml: |-
        test_131:
          basejail: 'no'
          boot: 'off'
          ip4: 10.1.0.224
          ip4_dict:
            ip4:
            - {ifc: epair0b, ip: 10.1.0.224, mask: '-'}
            msg: ''
          ip6: '-'
          jid: '81'
          release: 15.0-RELEASE-p3
          state: up
          template: ansible_client
          type: jail
        test_132:
          basejail: 'no'
          boot: 'off'
          ip4: 10.1.0.185
          ip4_dict:
            ip4:
            - {ifc: epair0b, ip: 10.1.0.185, mask: '-'}
            msg: ''
          ip6: '-'
          jid: '80'
          release: 15.0-RELEASE-p3
          state: up
          template: ansible_client
          type: jail
        test_133:
          basejail: 'no'
          boot: 'off'
          ip4: 10.1.0.225
          ip4_dict:
            ip4:
            - {ifc: epair0b, ip: 10.1.0.225, mask: '-'}
            msg: ''
          ip6: '-'
          jid: '82'
          release: 15.0-RELEASE-p3
          state: up
          template: ansible_client
          type: jail

TASK [ansible.builtin.debug] ***************************************************
ok: [iocage_04] => 
    jids | to_yaml: |-
        ['81', '80', '82']

TASK [Jails service sshd rcvar.] ***********************************************
ok: [iocage_04] => (item=81)
ok: [iocage_04] => (item=80)
ok: [iocage_04] => (item=82)

TASK [ansible.builtin.debug] ***************************************************
ok: [iocage_04] => 
    service_out:
        changed: false
        deprecations:
        -   collection_name: ansible.builtin
            deprecator:
                resolved_name: ansible.builtin
                type: null
            msg: Importing 'to_bytes' from 'ansible.module_utils._text' is deprecated.
            version: '2.24'
        -   collection_name: ansible.builtin
            deprecator:
                resolved_name: ansible.builtin
                type: null
            msg: Importing 'to_bytes' from 'ansible.module_utils._text' is deprecated.
            version: '2.24'
        -   collection_name: ansible.builtin
            deprecator:
                resolved_name: ansible.builtin
                type: null
            msg: Importing 'to_bytes' from 'ansible.module_utils._text' is deprecated.
            version: '2.24'
        msg: All items completed
        results:
        -   ansible_loop_var: item
            changed: false
            failed: false
            invocation:
                module_args:
                    command: rcvar
                    env: null
                    jail: '81'
                    list_enabled: false
                    script: sshd
                    synopsis: false
                    wait: 0.5
            item: '81'
            rc: 0
            rcvar:
                sshd_enable: 'YES'
            stderr: ''
            stderr_lines: []
            stdout: |-
                # sshd : Secure Shell Daemon
                #
                sshd_enable="YES"
                #   (default: "")
            stdout_lines:
            - '# sshd : Secure Shell Daemon'
            - '#'
            - sshd_enable="YES"
            - '#   (default: "")'
            - ''
        -   ansible_loop_var: item
            changed: false
            failed: false
            invocation:
                module_args:
                    command: rcvar
                    env: null
                    jail: '80'
                    list_enabled: false
                    script: sshd
                    synopsis: false
                    wait: 0.5
            item: '80'
            rc: 0
            rcvar:
                sshd_enable: 'YES'
            stderr: ''
            stderr_lines: []
            stdout: |-
                # sshd : Secure Shell Daemon
                #
                sshd_enable="YES"
                #   (default: "")
            stdout_lines:
            - '# sshd : Secure Shell Daemon'
            - '#'
            - sshd_enable="YES"
            - '#   (default: "")'
            - ''
        -   ansible_loop_var: item
            changed: false
            failed: false
            invocation:
                module_args:
                    command: rcvar
                    env: null
                    jail: '82'
                    list_enabled: false
                    script: sshd
                    synopsis: false
                    wait: 0.5
            item: '82'
            rc: 0
            rcvar:
                sshd_enable: 'YES'
            stderr: ''
            stderr_lines: []
            stdout: |-
                # sshd : Secure Shell Daemon
                #
                sshd_enable="YES"
                #   (default: "")
            stdout_lines:
            - '# sshd : Secure Shell Daemon'
            - '#'
            - sshd_enable="YES"
            - '#   (default: "")'
            - ''
        skipped: false

TASK [ansible.builtin.debug] ***************************************************
ok: [iocage_04] => 
    jid_rcvar:
        '80':
            sshd_enable: 'YES'
        '81':
            sshd_enable: 'YES'
        '82':
            sshd_enable: 'YES'

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

Playbook pb-test-03.yml

- name: Test module vbotka.freebsd.service. Set dictionary jid_service_enabled.
  hosts: iocage

  vars:

    debug: false
    jails: "{{ iocage_list_out.stdout | vbotka.freebsd.iocage('jails') }}"
    jids: "{{ jails | dict2items
                    | selectattr('value.state', 'eq', 'up')
                    | map(attribute='value.jid') }}"
    jid_service_enabled: "{{ dict(keys | zip(vals)) }}"
    keys: "{{ service_out.results | map(attribute='item') }}"
    vals: "{{ service_out.results | map(attribute='stdout_lines')
                                  | map('map', 'basename') }}"

  tasks:

    - name: Get iocage list of jails
      environment:
        CRYPTOGRAPHY_OPENSSL_NO_LEGACY: 1
      register: iocage_list_out
      changed_when: false
      ansible.builtin.command: iocage list --long

    - name: Jails service list enabled
      register: service_out
      vbotka.freebsd.service:
        jail: "{{ item }}"
        list_enabled: true
      loop: "{{ jids }}"

    - ansible.builtin.debug:
        var: service_out
      when: debug | bool

    - ansible.builtin.debug:
        var: jid_service_enabled | to_yaml

Playbook output - enabled services

(env) > ansible-playbook pb-test-03.yml -i iocage.ini -e debug=true
PLAY [Test module vbotka.freebsd.service. Set dictionary jid_service_enabled.] ***

TASK [Get iocage list of jails] ************************************************
ok: [iocage_04]

TASK [Jails service list enabled] **********************************************
ok: [iocage_04] => (item=81)
ok: [iocage_04] => (item=80)
ok: [iocage_04] => (item=82)

TASK [ansible.builtin.debug] ***************************************************
ok: [iocage_04] => 
    service_out:
        changed: false
        deprecations:
        -   collection_name: ansible.builtin
            deprecator:
                resolved_name: ansible.builtin
                type: null
            msg: Importing 'to_bytes' from 'ansible.module_utils._text' is deprecated.
            version: '2.24'
        -   collection_name: ansible.builtin
            deprecator:
                resolved_name: ansible.builtin
                type: null
            msg: Importing 'to_bytes' from 'ansible.module_utils._text' is deprecated.
            version: '2.24'
        -   collection_name: ansible.builtin
            deprecator:
                resolved_name: ansible.builtin
                type: null
            msg: Importing 'to_bytes' from 'ansible.module_utils._text' is deprecated.
            version: '2.24'
        msg: All items completed
        results:
        -   ansible_loop_var: item
            changed: false
            failed: false
            invocation:
                module_args:
                    command: null
                    env: null
                    jail: '81'
                    list_enabled: true
                    script: null
                    synopsis: false
                    wait: 0.5
            item: '81'
            rc: 0
            stderr: ''
            stderr_lines: []
            stdout: |-
                /etc/rc.d/cleanvar
                /etc/rc.d/cleartmp
                /etc/rc.d/cron
                /etc/rc.d/ip6addrctl
                /etc/rc.d/motd
                /etc/rc.d/netif
                /etc/rc.d/newsyslog
                /etc/rc.d/os-release
                /etc/rc.d/sshd
                /etc/rc.d/syslogd
                /etc/rc.d/utx
                /etc/rc.d/var_run
                /etc/rc.d/virecover
            stdout_lines:
            - /etc/rc.d/cleanvar
            - /etc/rc.d/cleartmp
            - /etc/rc.d/cron
            - /etc/rc.d/ip6addrctl
            - /etc/rc.d/motd
            - /etc/rc.d/netif
            - /etc/rc.d/newsyslog
            - /etc/rc.d/os-release
            - /etc/rc.d/sshd
            - /etc/rc.d/syslogd
            - /etc/rc.d/utx
            - /etc/rc.d/var_run
            - /etc/rc.d/virecover
        -   ansible_loop_var: item
            changed: false
            failed: false
            invocation:
                module_args:
                    command: null
                    env: null
                    jail: '80'
                    list_enabled: true
                    script: null
                    synopsis: false
                    wait: 0.5
            item: '80'
            rc: 0
            stderr: ''
            stderr_lines: []
            stdout: |-
                /etc/rc.d/cleanvar
                /etc/rc.d/cleartmp
                /etc/rc.d/cron
                /etc/rc.d/ip6addrctl
                /etc/rc.d/motd
                /etc/rc.d/netif
                /etc/rc.d/newsyslog
                /etc/rc.d/os-release
                /etc/rc.d/sshd
                /etc/rc.d/syslogd
                /etc/rc.d/utx
                /etc/rc.d/var_run
                /etc/rc.d/virecover
            stdout_lines:
            - /etc/rc.d/cleanvar
            - /etc/rc.d/cleartmp
            - /etc/rc.d/cron
            - /etc/rc.d/ip6addrctl
            - /etc/rc.d/motd
            - /etc/rc.d/netif
            - /etc/rc.d/newsyslog
            - /etc/rc.d/os-release
            - /etc/rc.d/sshd
            - /etc/rc.d/syslogd
            - /etc/rc.d/utx
            - /etc/rc.d/var_run
            - /etc/rc.d/virecover
        -   ansible_loop_var: item
            changed: false
            failed: false
            invocation:
                module_args:
                    command: null
                    env: null
                    jail: '82'
                    list_enabled: true
                    script: null
                    synopsis: false
                    wait: 0.5
            item: '82'
            rc: 0
            stderr: ''
            stderr_lines: []
            stdout: |-
                /etc/rc.d/cleanvar
                /etc/rc.d/cleartmp
                /etc/rc.d/cron
                /etc/rc.d/ip6addrctl
                /etc/rc.d/motd
                /etc/rc.d/netif
                /etc/rc.d/newsyslog
                /etc/rc.d/os-release
                /etc/rc.d/sshd
                /etc/rc.d/syslogd
                /etc/rc.d/utx
                /etc/rc.d/var_run
                /etc/rc.d/virecover
            stdout_lines:
            - /etc/rc.d/cleanvar
            - /etc/rc.d/cleartmp
            - /etc/rc.d/cron
            - /etc/rc.d/ip6addrctl
            - /etc/rc.d/motd
            - /etc/rc.d/netif
            - /etc/rc.d/newsyslog
            - /etc/rc.d/os-release
            - /etc/rc.d/sshd
            - /etc/rc.d/syslogd
            - /etc/rc.d/utx
            - /etc/rc.d/var_run
            - /etc/rc.d/virecover
        skipped: false

TASK [ansible.builtin.debug] ***************************************************
ok: [iocage_04] => 
    jid_service_enabled | to_yaml: |-
        '80': [cleanvar, cleartmp, cron, ip6addrctl, motd, netif, newsyslog, os-release, sshd,
          syslogd, utx, var_run, virecover]
        '81': [cleanvar, cleartmp, cron, ip6addrctl, motd, netif, newsyslog, os-release, sshd,
          syslogd, utx, var_run, virecover]
        '82': [cleanvar, cleartmp, cron, ip6addrctl, motd, netif, newsyslog, os-release, sshd,
          syslogd, utx, var_run, virecover]

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

Playbook pb-test-04.yml

- name: Test module vbotka.freebsd.service. Set dictionary jid_service_status.
  hosts: iocage

  vars:

    debug: false
    ansible_python_interpreter: auto_silent
    jails: "{{ iocage_list_out.stdout | vbotka.freebsd.iocage('jails') }}"
    jids: "{{ jails | dict2items
                    | selectattr('value.state', 'eq', 'up')
                    | map(attribute='value.jid') }}"
    jid_service_status: "{{ dict(service_out.results
                                 | community.general.json_query('[].[item, status]')) }}"

  tasks:

    - name: Get iocage list of jails
      environment:
        CRYPTOGRAPHY_OPENSSL_NO_LEGACY: 1
      register: iocage_list_out
      changed_when: false
      ansible.builtin.command: iocage list --long

    - name: Jails sshd status
      register: service_out
      vbotka.freebsd.service:
        jail: "{{ item }}"
        script: sshd
        command: status
      loop: "{{ jids }}"

    - ansible.builtin.debug:
        var: service_out
      when: debug | bool

    - ansible.builtin.debug:
        var: jid_service_status | to_nice_yaml

Playbook output - sshd status

(env) > ansible-playbook pb-test-04.yml -i iocage.ini
PLAY [Test module vbotka.freebsd.service. Set dictionary jid_service_status.] ***

TASK [Get iocage list of jails] ************************************************
ok: [iocage_04]

TASK [Jails sshd status] *******************************************************
ok: [iocage_04] => (item=81)
ok: [iocage_04] => (item=80)
ok: [iocage_04] => (item=82)

TASK [ansible.builtin.debug] ***************************************************
ok: [iocage_04] => 
    jid_service_status | to_nice_yaml: |-
        '80': running
        '81': running
        '82': running

PLAY RECAP *********************************************************************
iocage_04                  : ok=3    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   

Playbook pb-test-05.yml

- name: Test module vbotka.freebsd.service. Get script commands synopsis.
  hosts: iocage

  vars:

    ansible_python_interpreter: auto_silent
    jails: "{{ iocage_list_out.stdout | vbotka.freebsd.iocage('jails') }}"
    jids: "{{ jails | dict2items
                    | selectattr('value.state', 'eq', 'up')
                    | map(attribute='value.jid') }}"

    commands: "{{ script_commands.synopsis.cmds +
                  script_commands.synopsis.prefix
                  | product(script_commands.synopsis.cmds)
                  | map('join') }}"

  tasks:

    - name: Get iocage list of jails
      environment:
        CRYPTOGRAPHY_OPENSSL_NO_LEGACY: 1
      register: iocage_list_out
      changed_when: false
      ansible.builtin.command: iocage list --long

    - name: Jails sshd commands synopsis
      register: script_commands
      vbotka.freebsd.service:
        jail: "{{ jids.0 }}"
        script: sshd
        synopsis: true

    - ansible.builtin.debug:
        var: script_commands

    - ansible.builtin.debug:
        var: commands | to_yaml

Playbook output - sshd commands synopsis

(env) > ansible-playbook pb-test-05.yml -i iocage.ini -l iocage_02
PLAY [Test module vbotka.freebsd.service. Get script commands synopsis.] *******

TASK [Get iocage list of jails] ************************************************
ok: [iocage_04]

TASK [Jails sshd commands synopsis] ********************************************
ok: [iocage_04]

TASK [ansible.builtin.debug] ***************************************************
ok: [iocage_04] => 
    script_commands:
        changed: false
        deprecations:
        -   collection_name: ansible.builtin
            deprecator:
                resolved_name: ansible.builtin
                type: null
            msg: Importing 'to_bytes' from 'ansible.module_utils._text' is deprecated.
            version: '2.24'
        failed: false
        rc: 0
        stderr: |-
            Usage: /etc/rc.d/sshd [fast|force|one|quiet](start|stop|restart|rcvar|enable|disable|delete|enabled|describe|extracommands|configtest|keygen|reload|status|poll)
        stderr_lines:
        - 'Usage: /etc/rc.d/sshd [fast|force|one|quiet](start|stop|restart|rcvar|enable|disable|delete|enabled|describe|extracommands|configtest|keygen|reload|status|poll)'
        stdout: ''
        stdout_lines: []
        synopsis:
            cmds:
            - start
            - stop
            - restart
            - rcvar
            - enable
            - disable
            - delete
            - enabled
            - describe
            - extracommands
            - configtest
            - keygen
            - reload
            - status
            - poll
            prefix:
            - fast
            - force
            - one
            - quiet

TASK [ansible.builtin.debug] ***************************************************
ok: [iocage_04] => 
    commands | to_yaml: |-
        [start, stop, restart, rcvar, enable, disable, delete, enabled, describe, extracommands,
          configtest, keygen, reload, status, poll, faststart, faststop, fastrestart, fastrcvar,
          fastenable, fastdisable, fastdelete, fastenabled, fastdescribe, fastextracommands,
          fastconfigtest, fastkeygen, fastreload, faststatus, fastpoll, forcestart, forcestop,
          forcerestart, forcercvar, forceenable, forcedisable, forcedelete, forceenabled,
          forcedescribe, forceextracommands, forceconfigtest, forcekeygen, forcereload, forcestatus,
          forcepoll, onestart, onestop, onerestart, onercvar, oneenable, onedisable, onedelete,
          oneenabled, onedescribe, oneextracommands, oneconfigtest, onekeygen, onereload,
          onestatus, onepoll, quietstart, quietstop, quietrestart, quietrcvar, quietenable,
          quietdisable, quietdelete, quietenabled, quietdescribe, quietextracommands, quietconfigtest,
          quietkeygen, quietreload, quietstatus, quietpoll]

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

Playbook pb-test-06.yml

- name: Test module vbotka.freebsd.service. Get running jails sendmail rcvar(s).
  hosts: up
  remote_user: admin

  vars:

    ansible_python_interpreter: auto_silent
    
  tasks:

    - name: Get sendmail rcvar(s).
      vbotka.freebsd.service:
        script: sendmail
        command: rcvar
      register: out

    - ansible.builtin.debug:
        var: out.rcvar

Playbook output - sendmail rcvar

shell> ansible-playbook pb-test-06.yml -i hosts
PLAY [Test module vbotka.freebsd.service. Get running jails sendmail rcvar(s).] ***

TASK [Get sendmail rcvar(s).] **************************************************
ok: [test_132]
ok: [test_131]
ok: [test_133]

TASK [ansible.builtin.debug] ***************************************************
ok: [test_131] => 
    out.rcvar:
        sendmail_enable: 'NO'
ok: [test_132] => 
    out.rcvar:
        sendmail_enable: 'NO'
ok: [test_133] => 
    out.rcvar:
        sendmail_enable: 'NO'

PLAY RECAP *********************************************************************
test_131                   : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
test_132                   : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
test_133                   : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Playbook pb-test-07.yml

- name: Test module vbotka.freebsd.service. Start apcupsd.
  hosts: iocage

  vars:

    debug: false
    start_cmd_enable: "{{ rcvar.rcvar.apcupsd_enable == 'YES' }}"
    start_cmd: "{{ start_cmd_enable | ternary('start', 'onestart') }}"
    
  tasks:

    - name: Get apcupsd rcvar.
      register: rcvar
      vbotka.freebsd.service:
        script: apcupsd
        command: rcvar

    - ansible.builtin.debug:
        msg: |
          rcvar.rcvar: {{ rcvar.rcvar }}
          rcvar.rcvar.apcupsd_enable: {{ rcvar.rcvar.apcupsd_enable }}
          start_cmd_enable: {{ start_cmd_enable }}
          start_cmd: {{ start_cmd }}
      when: debug | bool

      # 500ms is enough to complete 'service apcupsd (one)start'.
      # The status before and after the command are different and dictionary status is returned.
      # As a result, the module returns 'changed: true'
    - name: Start apcupsd. By default wait 500ms to complete the command.
      register: out
      vbotka.freebsd.service:
        script: apcupsd
        command: "{{ start_cmd }}"

    - ansible.builtin.debug:
        var: out

    - name: Get apcupsd status.
      register: out
      vbotka.freebsd.service:
        script: apcupsd
        command: status

    - ansible.builtin.debug:
        var: out

    - name: Stop apcupsd. By default wait 500ms to complete the command.
      register: out
      vbotka.freebsd.service:
        script: apcupsd
        command: stop

    - ansible.builtin.debug:
        var: out

      # 200ms is not enough to complete 'service apcupsd (one)start'.
      # The status before and after the command do not change and are not returned.
      # As a result, the module returns 'changed: false'
      # The service apcupsd is started. See the next status.
    - name: Start apcupsd. Wait 200ms to complete the command.
      register: out
      vbotka.freebsd.service:
        script: apcupsd
        command: "{{ start_cmd }}"
        wait: 0.2

    - ansible.builtin.debug:
        var: out

    - name: Get apcupsd status.

      register: out
      vbotka.freebsd.service:
        script: apcupsd
        command: status

    - ansible.builtin.debug:
        var: out

Playbook output - start apcupsd

(env) > ansible-playbook pb-test-07.yml -i iocage.ini
PLAY [Test module vbotka.freebsd.service. Start apcupsd.] **********************

TASK [Get apcupsd rcvar.] ******************************************************
ok: [iocage_04]

TASK [ansible.builtin.debug] ***************************************************
ok: [iocage_04] => 
    msg: |-
        rcvar.rcvar: {'apcupsd_enable': 'NO'}
        rcvar.rcvar.apcupsd_enable: NO
        start_cmd_enable: False
        start_cmd: onestart

TASK [Start apcupsd. By default wait 500ms to complete the command.] ***********
changed: [iocage_04]

TASK [ansible.builtin.debug] ***************************************************
ok: [iocage_04] => 
    out:
        changed: true
        deprecations:
        -   collection_name: ansible.builtin
            deprecator:
                resolved_name: ansible.builtin
                type: null
            msg: Importing 'to_bytes' from 'ansible.module_utils._text' is deprecated.
            version: '2.24'
        failed: false
        onestart: Starting apcupsd.
        rc: 0
        state:
            post: |-
                apcupsd is running as pid 86133.
            pre: |-
                apcupsd is not running.
        stderr: ''
        stderr_lines: []
        stdout: |-
            Starting apcupsd.
        stdout_lines:
        - Starting apcupsd.

TASK [Get apcupsd status.] *****************************************************
ok: [iocage_04]

TASK [ansible.builtin.debug] ***************************************************
ok: [iocage_04] => 
    out:
        changed: false
        deprecations:
        -   collection_name: ansible.builtin
            deprecator:
                resolved_name: ansible.builtin
                type: null
            msg: Importing 'to_bytes' from 'ansible.module_utils._text' is deprecated.
            version: '2.24'
        failed: false
        rc: 0
        status: running
        stderr: ''
        stderr_lines: []
        stdout: |-
            apcupsd is running as pid 86133.
        stdout_lines:
        - apcupsd is running as pid 86133.

TASK [Stop apcupsd. By default wait 500ms to complete the command.] ************
changed: [iocage_04]

TASK [ansible.builtin.debug] ***************************************************
ok: [iocage_04] => 
    out:
        changed: true
        deprecations:
        -   collection_name: ansible.builtin
            deprecator:
                resolved_name: ansible.builtin
                type: null
            msg: Importing 'to_bytes' from 'ansible.module_utils._text' is deprecated.
            version: '2.24'
        failed: false
        rc: 0
        state:
            post: |-
                apcupsd is not running.
            pre: |-
                apcupsd is running as pid 86133.
        stderr: ''
        stderr_lines: []
        stdout: |-
            Stopping apcupsd.
            Waiting for PIDS: 86133.
        stdout_lines:
        - Stopping apcupsd.
        - 'Waiting for PIDS: 86133.'
        stop: 'Waiting for PIDS: 86133'

TASK [Start apcupsd. Wait 200ms to complete the command.] **********************
ok: [iocage_04]

TASK [ansible.builtin.debug] ***************************************************
ok: [iocage_04] => 
    out:
        changed: false
        deprecations:
        -   collection_name: ansible.builtin
            deprecator:
                resolved_name: ansible.builtin
                type: null
            msg: Importing 'to_bytes' from 'ansible.module_utils._text' is deprecated.
            version: '2.24'
        failed: false
        onestart: Starting apcupsd.
        rc: 0
        stderr: ''
        stderr_lines: []
        stdout: |-
            Starting apcupsd.
        stdout_lines:
        - Starting apcupsd.

TASK [Get apcupsd status.] *****************************************************
ok: [iocage_04]

TASK [ansible.builtin.debug] ***************************************************
ok: [iocage_04] => 
    out:
        changed: false
        deprecations:
        -   collection_name: ansible.builtin
            deprecator:
                resolved_name: ansible.builtin
                type: null
            msg: Importing 'to_bytes' from 'ansible.module_utils._text' is deprecated.
            version: '2.24'
        failed: false
        rc: 0
        status: running
        stderr: ''
        stderr_lines: []
        stdout: |-
            apcupsd is running as pid 86416.
        stdout_lines:
        - apcupsd is running as pid 86416.

PLAY RECAP *********************************************************************
iocage_04                  : ok=12   changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0