├── __init__.py ├── test ├── iocage.py ├── vars │ ├── groups.d │ │ ├── group_all.yml │ │ ├── group_jail.yml │ │ ├── group_setup.yml │ │ ├── group_template.yml │ │ ├── group_base.yml │ │ ├── group_present_absent_restart.yml │ │ ├── group_absent.yml │ │ ├── group_start_restart_stop_crash.yml │ │ ├── group_start_restart_stop.yml │ │ ├── group_present_start_exec_set1.yml │ │ └── group_test.yml │ └── tests.d │ │ ├── absent_start_crash.yml │ │ ├── absent_stop_crash.yml │ │ ├── absent_absent.yml │ │ ├── absent_restart_crash.yml │ │ ├── base_exists.yml │ │ ├── fetch.yml │ │ ├── test_exec.yml │ │ ├── test_restart.yml │ │ ├── test_start2.yml │ │ ├── test_start_crash.yml │ │ ├── test_stop_crash.yml │ │ ├── test_absent2.yml │ │ ├── test_pkg.yml │ │ ├── test_restart_crash.yml │ │ ├── template_start.yml │ │ ├── template_stop.yml │ │ ├── test_stop.yml │ │ ├── base_set.yml │ │ ├── test_start.yml │ │ ├── test_start3.yml │ │ ├── test_present.yml │ │ ├── jail_restore.yml │ │ ├── base_set_template_no.yml │ │ ├── facts.yml │ │ ├── test_clone.yml │ │ ├── test_pkg_crash.yml │ │ ├── base_clone.yml │ │ ├── template_create.yml │ │ ├── test_absent.yml │ │ ├── base_create.yml │ │ ├── jail_absent.yml │ │ └── test_set.yml ├── extra_vars │ ├── test_31-debug.yml │ ├── test_32-debug.yml │ ├── test_X-debug-n1.yml │ ├── test_31-debug-n2.yml │ ├── test_jail-exec_cmd.yml │ └── test_jail-set_properties.yml ├── tasks │ ├── custom_stats_pass.yml │ ├── custom_stats_end.yml │ ├── custom_stats_start.yml │ ├── custom_stats_crash.yml │ ├── custom_stats_fail.yml │ ├── group_jail.yml │ ├── group_setup.yml │ ├── group_present_absent_restart.yml │ ├── group_template.yml │ ├── group_base.yml │ ├── template_start_force.yml │ ├── group_absent.yml │ ├── group_start_restart_stop_crash.yml │ ├── group_present_start_exec_set1.yml │ ├── group_start_restart_stop.yml │ ├── misc_get_all.yml │ ├── sanity.yml │ ├── group_test.yml │ ├── absent_start_crash.yml │ ├── absent_stop_crash.yml │ ├── absent_restart_crash.yml │ ├── base_exists.yml │ ├── test_start_crash.yml │ ├── test_stop_crash.yml │ ├── absent_absent.yml │ ├── fetch.yml │ ├── test_exec.yml │ ├── test_restart_crash.yml │ ├── template_start_crash.yml │ ├── test_restart.yml │ ├── test_start2.yml │ ├── test_absent2.yml │ ├── template_stop.yml │ ├── test_pkg.yml │ ├── test_start.yml │ ├── test_stop.yml │ ├── test_start3.yml │ ├── test_present.yml │ ├── test_set.yml │ ├── test_pkg_crash.yml │ ├── base_clone.yml │ ├── test_absent.yml │ ├── test_clone.yml │ ├── template_create.yml │ ├── jail_absent.yml │ ├── base_create.yml │ ├── facts.yml │ ├── base_set.yml │ ├── base_set_template_no.yml │ ├── jail_restore.yml │ └── group_all.yml ├── .ansible-lint ├── templates │ ├── group_all.j2 │ ├── group.j2 │ ├── iocage_test.yml.j2 │ ├── command.j2 │ └── command_crash.j2 ├── hosts.example ├── .yamllint ├── ansible.cfg.example ├── iocage_test.yml └── configure.yml ├── .gitignore ├── LICENSE ├── CHANGELOG.md ├── README.md └── iocage.py /__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/iocage.py: -------------------------------------------------------------------------------- 1 | ../iocage.py -------------------------------------------------------------------------------- /test/vars/groups.d/group_all.yml: -------------------------------------------------------------------------------- 1 | --- 2 | group_all: 3 | template: group_all 4 | tests: [] 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .*~ 2 | *~ 3 | .*.sw* 4 | collections 5 | hosts 6 | ansible.cfg 7 | TESTING 8 | TODO 9 | -------------------------------------------------------------------------------- /test/extra_vars/test_31-debug.yml: -------------------------------------------------------------------------------- 1 | --- 2 | my_hosts: test_23 3 | my_jname: test_31 4 | my_debug: true 5 | -------------------------------------------------------------------------------- /test/extra_vars/test_32-debug.yml: -------------------------------------------------------------------------------- 1 | --- 2 | my_hosts: test_23 3 | my_jname: test_32 4 | my_debug: true 5 | -------------------------------------------------------------------------------- /test/extra_vars/test_X-debug-n1.yml: -------------------------------------------------------------------------------- 1 | --- 2 | my_hosts: test_23 3 | my_jname: test_X 4 | my_debug: true 5 | -------------------------------------------------------------------------------- /test/extra_vars/test_31-debug-n2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | my_hosts: test_23,test_29 3 | my_jname: test_31 4 | my_debug: true 5 | my_strategy: free 6 | -------------------------------------------------------------------------------- /test/extra_vars/test_jail-exec_cmd.yml: -------------------------------------------------------------------------------- 1 | --- 2 | my_hosts: test_23 3 | my_jname: test_jail 4 | cmd: /bin/ls -la /root 5 | my_debug: true 6 | -------------------------------------------------------------------------------- /test/tasks/custom_stats_pass.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - ansible.builtin.set_stats: 3 | aggregate: true 4 | per_host: true 5 | data: 6 | ok: 1 7 | -------------------------------------------------------------------------------- /test/vars/groups.d/group_jail.yml: -------------------------------------------------------------------------------- 1 | --- 2 | group_jail: 3 | template: group 4 | tests: 5 | - test: jail_absent 6 | - test: jail_restore 7 | -------------------------------------------------------------------------------- /test/tasks/custom_stats_end.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - ansible.builtin.set_stats: 3 | per_host: true 4 | data: 5 | a2: "{{ '%b %d %H:%M:%S'|strftime }}" 6 | -------------------------------------------------------------------------------- /test/tasks/custom_stats_start.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - ansible.builtin.set_stats: 3 | per_host: true 4 | data: 5 | a1: "{{ '%b %d %H:%M:%S'|strftime }}" 6 | -------------------------------------------------------------------------------- /test/vars/groups.d/group_setup.yml: -------------------------------------------------------------------------------- 1 | --- 2 | group_setup: 3 | template: group 4 | tests: 5 | - test: sanity 6 | - test: facts 7 | - test: fetch 8 | -------------------------------------------------------------------------------- /test/extra_vars/test_jail-set_properties.yml: -------------------------------------------------------------------------------- 1 | --- 2 | my_hosts: test_23 3 | my_jname: test_jail 4 | properties: 5 | ip4_addr: "em0|10.1.0.99/24" 6 | my_debug: true 7 | -------------------------------------------------------------------------------- /test/tasks/custom_stats_crash.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - ansible.builtin.set_stats: 3 | aggregate: true 4 | per_host: true 5 | data: 6 | crash: "{{ _test_name }}," 7 | -------------------------------------------------------------------------------- /test/tasks/custom_stats_fail.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - ansible.builtin.set_stats: 3 | aggregate: true 4 | per_host: true 5 | data: 6 | fail: "{{ _test_name }}," 7 | -------------------------------------------------------------------------------- /test/vars/groups.d/group_template.yml: -------------------------------------------------------------------------------- 1 | --- 2 | group_template: 3 | template: group 4 | tests: 5 | - test: template_create 6 | - test: template_stop 7 | - test: template_start_crash 8 | -------------------------------------------------------------------------------- /test/.ansible-lint: -------------------------------------------------------------------------------- 1 | --- 2 | verbosity: 1 3 | quiet: False 4 | parseable: True 5 | use_default_rules: True 6 | rulesdir: 7 | - $HOME/.ansible/ansible-lint-rules 8 | skip_list: 9 | - unnamed-task 10 | -------------------------------------------------------------------------------- /test/vars/groups.d/group_base.yml: -------------------------------------------------------------------------------- 1 | --- 2 | group_base: 3 | template: group 4 | tests: 5 | - test: base_create 6 | - test: base_exists 7 | - test: base_set_template_no 8 | - test: base_clone 9 | -------------------------------------------------------------------------------- /test/vars/groups.d/group_present_absent_restart.yml: -------------------------------------------------------------------------------- 1 | --- 2 | group_present_absent_restart: 3 | template: group 4 | tests: 5 | - test: test_present 6 | - test: test_absent 7 | - test: test_restart_crash 8 | -------------------------------------------------------------------------------- /test/vars/groups.d/group_absent.yml: -------------------------------------------------------------------------------- 1 | --- 2 | group_absent: 3 | template: group 4 | tests: 5 | - test: absent_absent 6 | - test: absent_stop_crash 7 | - test: absent_restart_crash 8 | - test: absent_start_crash 9 | -------------------------------------------------------------------------------- /test/tasks/group_jail.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | - ansible.builtin.import_tasks: tasks/jail_absent.yml 4 | vars: 5 | _test_name: jail_absent 6 | - ansible.builtin.import_tasks: tasks/jail_restore.yml 7 | vars: 8 | _test_name: jail_restore 9 | -------------------------------------------------------------------------------- /test/vars/groups.d/group_start_restart_stop_crash.yml: -------------------------------------------------------------------------------- 1 | --- 2 | group_start_restart_stop_crash: 3 | template: group 4 | tests: 5 | - test: test_absent 6 | - test: test_start_crash 7 | - test: test_restart_crash 8 | - test: test_stop_crash 9 | -------------------------------------------------------------------------------- /test/templates/group_all.j2: -------------------------------------------------------------------------------- 1 | #jinja2: trim_blocks: False 2 | --- 3 | # {{ ansible_managed }} 4 | {% for i in iocage_test_db.keys()|sort %} 5 | - ansible.builtin.import_tasks: tasks/{{ i }}.yml 6 | vars: 7 | _test_name: {{ i }} 8 | tags: [never, {{ i }}] 9 | {% endfor %} 10 | -------------------------------------------------------------------------------- /test/tasks/group_setup.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | - ansible.builtin.import_tasks: tasks/sanity.yml 4 | vars: 5 | _test_name: sanity 6 | - ansible.builtin.import_tasks: tasks/facts.yml 7 | vars: 8 | _test_name: facts 9 | - ansible.builtin.import_tasks: tasks/fetch.yml 10 | vars: 11 | _test_name: fetch 12 | -------------------------------------------------------------------------------- /test/vars/groups.d/group_start_restart_stop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | group_start_restart_stop: 3 | template: group 4 | tests: 5 | - test: test_clone 6 | - test: test_start 7 | - test: test_start 8 | - test: test_restart 9 | - test: test_stop 10 | - test: test_stop 11 | - test: test_restart 12 | - test: test_absent 13 | -------------------------------------------------------------------------------- /test/templates/group.j2: -------------------------------------------------------------------------------- 1 | #jinja2: trim_blocks: False 2 | --- 3 | # {{ ansible_managed }} 4 | 5 | {%- for i in group.tests %} 6 | - ansible.builtin.import_tasks: tasks/{{ i.test }}.yml 7 | vars: 8 | _test_name: {{ i.test }} 9 | {%- if i.vars is defined %} 10 | {{ i.vars|to_nice_yaml(indent=2)|indent(width=4) }} 11 | {%- endif %} 12 | {%- endfor %} 13 | -------------------------------------------------------------------------------- /test/hosts.example: -------------------------------------------------------------------------------- 1 | [test] 2 | test_23 ansible_host=10.1.0.73 3 | test_29 ansible_host=10.1.0.17 4 | 5 | [test:vars] 6 | ansible_connection=ssh 7 | ansible_user=admin 8 | ansible_python_interpreter=/usr/local/bin/python3.7 9 | ansible_perl_interpreter=/usr/local/bin/perl 10 | # ansible_become=yes 11 | # ansible_become_user=root 12 | # ansible_become_method=sudo 13 | -------------------------------------------------------------------------------- /test/vars/groups.d/group_present_start_exec_set1.yml: -------------------------------------------------------------------------------- 1 | --- 2 | group_present_start_exec_set1: 3 | template: group 4 | tests: 5 | - test: test_present 6 | - test: test_start 7 | - test: test_exec 8 | vars: 9 | cmd: /bin/ls -la /root 10 | - test: test_set 11 | vars: 12 | properties: 13 | ip4_addr: 'em0|10.1.0.99/24' 14 | -------------------------------------------------------------------------------- /test/tasks/group_present_absent_restart.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | - ansible.builtin.import_tasks: tasks/test_present.yml 4 | vars: 5 | _test_name: test_present 6 | - ansible.builtin.import_tasks: tasks/test_absent.yml 7 | vars: 8 | _test_name: test_absent 9 | - ansible.builtin.import_tasks: tasks/test_restart_crash.yml 10 | vars: 11 | _test_name: test_restart_crash 12 | -------------------------------------------------------------------------------- /test/tasks/group_template.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | - ansible.builtin.import_tasks: tasks/template_create.yml 4 | vars: 5 | _test_name: template_create 6 | - ansible.builtin.import_tasks: tasks/template_stop.yml 7 | vars: 8 | _test_name: template_stop 9 | - ansible.builtin.import_tasks: tasks/template_start_crash.yml 10 | vars: 11 | _test_name: template_start_crash 12 | -------------------------------------------------------------------------------- /test/vars/tests.d/absent_start_crash.yml: -------------------------------------------------------------------------------- 1 | --- 2 | absent_start_crash: 3 | template: command_crash 4 | label: 'absent_start_crash: Check if absent jail can not be started' 5 | iocage: 6 | state: started 7 | name: absent 8 | assert: 9 | - '_msg1 == ansible_failed_result.msg' 10 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }}' 11 | vars: 12 | _msg1: "\"Jail 'absent' doesn't exist\"" 13 | -------------------------------------------------------------------------------- /test/vars/tests.d/absent_stop_crash.yml: -------------------------------------------------------------------------------- 1 | --- 2 | absent_stop_crash: 3 | template: command_crash 4 | label: 'absent_stop_crash: Check if absent jail can not be stopped' 5 | iocage: 6 | state: stopped 7 | name: absent 8 | assert: 9 | - '_msg1 == ansible_failed_result.msg' 10 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }}' 11 | vars: 12 | _msg1: "\"Jail 'absent' doesn't exist\"" 13 | -------------------------------------------------------------------------------- /test/.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | extends: default 3 | 4 | rules: 5 | braces: 6 | max-spaces-inside: 1 7 | level: error 8 | brackets: 9 | max-spaces-inside: 1 10 | level: error 11 | comments: disable 12 | comments-indentation: disable 13 | line-length: 14 | max: 160 15 | level: warning 16 | truthy: 17 | allowed-values: ['true', 'false', 'True', 'False'] 18 | indentation: 19 | spaces: 2 20 | indent-sequences: true 21 | -------------------------------------------------------------------------------- /test/vars/tests.d/absent_absent.yml: -------------------------------------------------------------------------------- 1 | --- 2 | absent_absent: 3 | template: command 4 | label: 'absent_absent: Check if absent jail can be destroyed' 5 | iocage: 6 | state: absent 7 | name: absent 8 | debug: 9 | - var: result.msg 10 | assert: 11 | - '_msg1 == result.msg' 12 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }}' 13 | vars: 14 | _msg1: "\"Jail absent is already absent.\"" 15 | -------------------------------------------------------------------------------- /test/vars/tests.d/absent_restart_crash.yml: -------------------------------------------------------------------------------- 1 | --- 2 | absent_restart_crash: 3 | template: command_crash 4 | label: 'absent_restart_crash: Check if absent jail can not be restarted' 5 | iocage: 6 | state: restarted 7 | name: absent 8 | assert: 9 | - '_msg1 == ansible_failed_result.msg' 10 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }}' 11 | vars: 12 | _msg1: "\"Jail 'absent' doesn't exist\"" 13 | -------------------------------------------------------------------------------- /test/tasks/group_base.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | - ansible.builtin.import_tasks: tasks/base_create.yml 4 | vars: 5 | _test_name: base_create 6 | - ansible.builtin.import_tasks: tasks/base_exists.yml 7 | vars: 8 | _test_name: base_exists 9 | - ansible.builtin.import_tasks: tasks/base_set_template_no.yml 10 | vars: 11 | _test_name: base_set_template_no 12 | - ansible.builtin.import_tasks: tasks/base_clone.yml 13 | vars: 14 | _test_name: base_clone 15 | -------------------------------------------------------------------------------- /test/tasks/template_start_force.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # template_start_force [TODO] - - - - - - - - - - - - - - - - - - - - - - - 3 | 4 | # - name: Check if template jail can be force-started 5 | # iocage: 6 | # state: started 7 | # name: "test_template_{{ label }}" 8 | # # force: yes 9 | # # TODO should this pass or fail? 10 | # # ignore_errors: yes 11 | 12 | - ansible.builtin.debug: 13 | msg: template_start_force not implemented yet. 14 | when: debug|bool 15 | -------------------------------------------------------------------------------- /test/vars/groups.d/group_test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | group_test: 3 | template: group 4 | tests: 5 | - test: test_present 6 | - test: test_absent 7 | - test: test_clone 8 | - test: test_start 9 | - test: test_start2 10 | - test: test_exec 11 | vars: 12 | cmd: /bin/ls -la /root 13 | - test: test_restart 14 | - test: test_stop 15 | - test: test_pkg_crash 16 | - test: test_start3 17 | - test: test_absent 18 | - test: test_absent2 19 | -------------------------------------------------------------------------------- /test/vars/tests.d/base_exists.yml: -------------------------------------------------------------------------------- 1 | --- 2 | base_exists: 3 | template: command 4 | label: 'base_exists: Check if {{ lbr }} basejail {{ rbr }} exists' 5 | iocage: 6 | state: exists 7 | name: '{{ lbr }} basejail {{ rbr }}' 8 | debug: 9 | - var: result.msg 10 | assert: 11 | - '_msg1 == result.msg' 12 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Miising: {{ lbr }} _msg1 {{ rbr }}' 13 | vars: 14 | _msg1: "\"Jail {{ lbr }} basejail {{ rbr }} exists\"" 15 | -------------------------------------------------------------------------------- /test/vars/tests.d/fetch.yml: -------------------------------------------------------------------------------- 1 | --- 2 | fetch: 3 | template: command 4 | label: 'fetch: Check if release {{ lbr }} release {{ rbr }} exists' 5 | iocage: 6 | state: fetched 7 | release: "{{ lbr }} release {{ rbr }}" 8 | assert: 9 | - 'result.msg is search(release)' 10 | - 'not result.changed' 11 | - 'not result.failed' 12 | - 'result.stderr_lines|length == 0' 13 | - 'result.stdout_lines|length == 0' 14 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed.' 15 | -------------------------------------------------------------------------------- /test/vars/tests.d/test_exec.yml: -------------------------------------------------------------------------------- 1 | --- 2 | test_exec: 3 | template: command 4 | label: 'test_exec: Check if exec works in jail {{ lbr }} jname {{ rbr }}' 5 | iocage: 6 | state: exec 7 | name: '{{ lbr }} jname {{ rbr }}' 8 | cmd: '{{ lbr }} cmd {{ rbr }}' 9 | debug: 10 | - var: result.msg 11 | assert: 12 | - '_msg1 in result.msg' 13 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }}' 14 | vars: 15 | _msg1: "\"rc: 0\"" 16 | -------------------------------------------------------------------------------- /test/tasks/group_absent.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | - ansible.builtin.import_tasks: tasks/absent_absent.yml 4 | vars: 5 | _test_name: absent_absent 6 | - ansible.builtin.import_tasks: tasks/absent_stop_crash.yml 7 | vars: 8 | _test_name: absent_stop_crash 9 | - ansible.builtin.import_tasks: tasks/absent_restart_crash.yml 10 | vars: 11 | _test_name: absent_restart_crash 12 | - ansible.builtin.import_tasks: tasks/absent_start_crash.yml 13 | vars: 14 | _test_name: absent_start_crash 15 | -------------------------------------------------------------------------------- /test/vars/tests.d/test_restart.yml: -------------------------------------------------------------------------------- 1 | --- 2 | test_restart: 3 | template: command 4 | label: 'test_restart: Check if jail {{ lbr }} jname {{ rbr }} can be restarted' 5 | iocage: 6 | state: restarted 7 | name: '{{ lbr }} jname {{ rbr }}' 8 | debug: 9 | - var: result.msg 10 | assert: 11 | - '_msg1 in result.msg' 12 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }}' 13 | vars: 14 | _msg1: "\"Jail {{ lbr }} jname {{ rbr }} was restarted.\"" 15 | -------------------------------------------------------------------------------- /test/vars/tests.d/test_start2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | test_start2: 3 | template: command 4 | label: 'test_start2: Check if jail {{ lbr }} jname {{ rbr }} can be started again' 5 | iocage: 6 | state: started 7 | name: '{{ lbr }} jname {{ rbr }}' 8 | debug: 9 | - var: result.msg 10 | assert: 11 | - '_msg2 == result.msg' 12 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg2 {{ rbr }}' 13 | vars: 14 | _msg2: "\"Jail {{ lbr }} jname {{ rbr }} already started\"" 15 | -------------------------------------------------------------------------------- /test/tasks/group_start_restart_stop_crash.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | - ansible.builtin.import_tasks: tasks/test_absent.yml 4 | vars: 5 | _test_name: test_absent 6 | - ansible.builtin.import_tasks: tasks/test_start_crash.yml 7 | vars: 8 | _test_name: test_start_crash 9 | - ansible.builtin.import_tasks: tasks/test_restart_crash.yml 10 | vars: 11 | _test_name: test_restart_crash 12 | - ansible.builtin.import_tasks: tasks/test_stop_crash.yml 13 | vars: 14 | _test_name: test_stop_crash 15 | -------------------------------------------------------------------------------- /test/vars/tests.d/test_start_crash.yml: -------------------------------------------------------------------------------- 1 | --- 2 | test_start_crash: 3 | template: command_crash 4 | label: 'test_start_crash: Check if not-existent jail {{ lbr }} jname {{ rbr }} can not be started' 5 | iocage: 6 | state: started 7 | name: '{{ lbr }} jname {{ rbr }}' 8 | assert: 9 | - '_msg1 == ansible_failed_result.msg' 10 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }}' 11 | vars: 12 | _msg1: "\"Jail '{{ lbr }} jname {{ rbr }}' doesn't exist\"" 13 | -------------------------------------------------------------------------------- /test/vars/tests.d/test_stop_crash.yml: -------------------------------------------------------------------------------- 1 | --- 2 | test_stop_crash: 3 | template: command_crash 4 | label: 'test_stop_crash: Check if not-existent jail {{ lbr }} jname {{ rbr }} can not be stopped' 5 | iocage: 6 | state: stopped 7 | name: '{{ lbr }} jname {{ rbr }}' 8 | assert: 9 | - '_msg1 == ansible_failed_result.msg' 10 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }}' 11 | vars: 12 | _msg1: "\"Jail '{{ lbr }} jname {{ rbr }}' doesn't exist\"" 13 | -------------------------------------------------------------------------------- /test/vars/tests.d/test_absent2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | test_absent2: 3 | template: command 4 | label: 'test_absent2: Check if jail {{ lbr }} jname {{ rbr }} can be destroyed again' 5 | iocage: 6 | state: absent 7 | name: '{{ lbr }} jname {{ rbr }}' 8 | debug: 9 | - var: result.msg 10 | assert: 11 | - '_msg2 == result.msg' 12 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg2 {{ rbr }}' 13 | vars: 14 | _msg2: "\"Jail {{ lbr }} jname {{ rbr }} is already absent.\"" 15 | -------------------------------------------------------------------------------- /test/vars/tests.d/test_pkg.yml: -------------------------------------------------------------------------------- 1 | --- 2 | test_pkg: 3 | template: command 4 | label: 'test_pkg: Check if pkg info works in started jail {{ lbr }} jname {{ rbr }}' 5 | iocage: 6 | state: pkg 7 | name: '{{ lbr }} jname {{ rbr }}' 8 | cmd: 'info' 9 | debug: 10 | - var: result.msg 11 | assert: 12 | - '_msg1 in result.msg' 13 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }}' 14 | vars: 15 | _msg1: "\"was executed in jail '{{ lbr }} jname {{ rbr }}'\"" 16 | -------------------------------------------------------------------------------- /test/vars/tests.d/test_restart_crash.yml: -------------------------------------------------------------------------------- 1 | --- 2 | test_restart_crash: 3 | template: command_crash 4 | label: 'test_restart_crash: Check if not-existent jail {{ lbr }} jname {{ rbr }} can not be restarted' 5 | iocage: 6 | state: restarted 7 | name: '{{ lbr }} jname {{ rbr }}' 8 | assert: 9 | - '_msg1 == ansible_failed_result.msg' 10 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }}' 11 | vars: 12 | _msg1: "\"Jail '{{ lbr }} jname {{ rbr }}' doesn't exist\"" 13 | -------------------------------------------------------------------------------- /test/vars/tests.d/template_start.yml: -------------------------------------------------------------------------------- 1 | --- 2 | template_start_crash: 3 | template: command_crash 4 | label: 'template_start_crash: Check if template {{ lbr }} basejail {{ rbr }} can not be started' 5 | iocage: 6 | state: started 7 | name: '{{ lbr }} basejail {{ rbr }}' 8 | assert: 9 | - '_msg1 in ansible_failed_result.msg' 10 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }}' 11 | vars: 12 | _msg1: "\"Jail {{ lbr }} basejail {{ rbr }} could not be started\"" 13 | -------------------------------------------------------------------------------- /test/vars/tests.d/template_stop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | template_stop: 3 | template: command 4 | label: 'template_stop: Check if template {{ lbr }} basejail {{ rbr }} can not be stopped' 5 | iocage: 6 | state: stopped 7 | name: '{{ lbr }} basejail {{ rbr }}' 8 | debug: 9 | - var: result.msg 10 | assert: 11 | - '_msg1 in result.msg' 12 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }}' 13 | vars: 14 | _msg1: "\"Jail {{ lbr }} basejail {{ rbr }} already stopped\"" 15 | -------------------------------------------------------------------------------- /test/tasks/group_present_start_exec_set1.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | - ansible.builtin.import_tasks: tasks/test_present.yml 4 | vars: 5 | _test_name: test_present 6 | - ansible.builtin.import_tasks: tasks/test_start.yml 7 | vars: 8 | _test_name: test_start 9 | - ansible.builtin.import_tasks: tasks/test_exec.yml 10 | vars: 11 | _test_name: test_exec 12 | cmd: /bin/ls -la /root 13 | 14 | - ansible.builtin.import_tasks: tasks/test_set.yml 15 | vars: 16 | _test_name: test_set 17 | properties: 18 | ip4_addr: em0|10.1.0.99/24 19 | -------------------------------------------------------------------------------- /test/ansible.cfg.example: -------------------------------------------------------------------------------- 1 | [defaults] 2 | inventory = $PWD/hosts 3 | roles_path = $PWD/roles 4 | collections_path = $PWD/collections 5 | retry_files_enabled = false 6 | stdout_callback = yaml 7 | log_path = /var/log/ansible.log 8 | 9 | [ssh_connection] 10 | pipelining = true 11 | 12 | [colors] 13 | changed = purple 14 | debug = bright yellow 15 | deprecate = blue 16 | diff_add = green 17 | diff_lines = cyan 18 | diff_remove = red 19 | error = red 20 | highlight = white 21 | ok = green 22 | skip = yellow 23 | unreachable = bright red 24 | verbose = blue 25 | warn = bright purple 26 | -------------------------------------------------------------------------------- /test/vars/tests.d/test_stop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | test_stop: 3 | template: command 4 | label: 'test_stop: Check if jail {{ lbr }} jname {{ rbr }} can be stopped' 5 | iocage: 6 | state: stopped 7 | name: '{{ lbr }} jname {{ rbr }}' 8 | debug: 9 | - var: result.msg 10 | assert: 11 | - '_msg1 in result.msg or _msg2 == result.msg' 12 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }} or {{ lbr }} _msg2 {{ rbr }}' 13 | vars: 14 | _msg1: "\"Jail {{ lbr }} jname {{ rbr }} was stopped.\"" 15 | _msg2: "\"Jail {{ lbr }} jname {{ rbr }} already stopped\"" 16 | -------------------------------------------------------------------------------- /test/vars/tests.d/base_set.yml: -------------------------------------------------------------------------------- 1 | --- 2 | base_set: 3 | template: command 4 | label: 'base_set: Verify that {{ lbr }} basejail {{ rbr }} can be converted' 5 | iocage: 6 | state: set 7 | name: '{{ lbr }} basejail {{ rbr }}' 8 | properties: '{{ lbr }} properties {{ rbr }}' 9 | debug: 10 | - var: result.msg 11 | - var: iocage_templates[basejail].properties.template 12 | assert: 13 | - '_msg1 in result.msg' 14 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }}' 15 | vars: 16 | _msg1: "\"already set for jail {{ lbr }} basejail {{ rbr }}\"" 17 | -------------------------------------------------------------------------------- /test/vars/tests.d/test_start.yml: -------------------------------------------------------------------------------- 1 | --- 2 | test_start: 3 | template: command 4 | label: 'test_start: Check if jail {{ lbr }} jname {{ rbr }} can be started' 5 | iocage: 6 | state: started 7 | name: '{{ lbr }} jname {{ rbr }}' 8 | debug: 9 | - var: result.msg 10 | assert: 11 | - '_msg1 in result.msg or _msg2 == result.msg' 12 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }} or {{ lbr }} _msg2 {{ rbr }}' 13 | vars: 14 | _msg1: "\"Jail {{ lbr }} jname {{ rbr }} was started.\"" 15 | _msg2: "\"Jail {{ lbr }} jname {{ rbr }} already started\"" 16 | -------------------------------------------------------------------------------- /test/vars/tests.d/test_start3.yml: -------------------------------------------------------------------------------- 1 | --- 2 | test_start3: 3 | template: command 4 | label: 'test_start3: Check if jail {{ lbr }} jname {{ rbr }} can be started again' 5 | iocage: 6 | state: started 7 | name: '{{ lbr }} jname {{ rbr }}' 8 | debug: 9 | - var: result.msg 10 | assert: 11 | - '_msg1 in result.msg or _msg2 == result.msg' 12 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }} or {{ lbr }} _msg2 {{ rbr }}' 13 | vars: 14 | _msg1: "\"Jail {{ lbr }} jname {{ rbr }} was started.\"" 15 | _msg2: "\"Jail {{ lbr }} jname {{ rbr }} already started\"" 16 | -------------------------------------------------------------------------------- /test/vars/tests.d/test_present.yml: -------------------------------------------------------------------------------- 1 | --- 2 | test_present: 3 | template: command 4 | label: 'test_present: Check if {{ lbr }} jname {{ rbr }} can be created' 5 | iocage: 6 | state: present 7 | name: '{{ lbr }} jname {{ rbr }}' 8 | debug: 9 | - var: result.msg 10 | assert: 11 | - '_msg1 in result.msg or _msg2 == result.msg' 12 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }} or {{ lbr }} _msg2 {{ rbr }}' 13 | vars: 14 | _msg1: "\"Jail '{{ lbr }} jname {{ rbr }}' was created with properties {}.\"" 15 | _msg2: "\"{{ lbr }} jname {{ rbr }} already exists\"" 16 | -------------------------------------------------------------------------------- /test/vars/tests.d/jail_restore.yml: -------------------------------------------------------------------------------- 1 | --- 2 | jail_restore: 3 | template: command 4 | label: 'jail_restore: Verify that base jail {{ lbr }} basejail {{ rbr }} can be converted back' 5 | iocage: 6 | state: set 7 | name: '{{ lbr }} basejail {{ rbr }}' 8 | properties: 9 | template: 'yes' 10 | debug: 11 | - var: iocage_templates[basejail].properties.template 12 | - var: result.msg 13 | assert: 14 | - '_msg1 in result.msg' 15 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }}' 16 | vars: 17 | _msg1: "\"already set for jail {{ lbr }} basejail {{ rbr }}\"" 18 | -------------------------------------------------------------------------------- /test/vars/tests.d/base_set_template_no.yml: -------------------------------------------------------------------------------- 1 | --- 2 | base_set_template_no: 3 | template: command 4 | label: 'base_set_template_no: Verify that {{ lbr }} basejail {{ rbr }} can be converted' 5 | iocage: 6 | state: set 7 | name: '{{ lbr }} basejail {{ rbr }}' 8 | properties: 9 | template: "no" 10 | debug: 11 | - var: result.msg 12 | - var: iocage_templates[basejail].properties.template 13 | assert: 14 | - '_msg1 in result.msg' 15 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }}' 16 | vars: 17 | _msg1: "\"already set for jail {{ lbr }} basejail {{ rbr }}\"" 18 | -------------------------------------------------------------------------------- /test/vars/tests.d/facts.yml: -------------------------------------------------------------------------------- 1 | --- 2 | facts: 3 | template: command 4 | label: 'facts: Get all iocage_* facts by default' 5 | debug: 6 | - msg: |- 7 | iocage_releases = {{ lbr }} ansible_facts.iocage_releases {{ rbr }} 8 | iocage_templates.keys() = {{ lbr }} ansible_facts.iocage_templates.keys()|list {{ rbr }} 9 | iocage_jails.keys() = {{ lbr }} ansible_facts.iocage_jails.keys()|list {{ rbr }} 10 | assert: 11 | - 'not result.changed' 12 | - 'not result.failed' 13 | - 'result.stderr_lines|length == 0' 14 | - 'result.stdout_lines|length == 0' 15 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed.' 16 | -------------------------------------------------------------------------------- /test/vars/tests.d/test_clone.yml: -------------------------------------------------------------------------------- 1 | --- 2 | test_clone: 3 | template: command 4 | label: 'test_clone: Check if test jail can be cloned' 5 | iocage: 6 | state: cloned 7 | name: '{{ lbr }} jname {{ rbr }}' 8 | clone_from: '{{ lbr }} basejail {{ rbr }}' 9 | debug: 10 | - var: result.msg 11 | assert: 12 | - '_msg1 in result.msg or _msg2 == result.msg' 13 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }} or {{ lbr }} _msg2 {{ rbr }}' 14 | vars: 15 | _msg1: "\"Jail '{{ lbr }} jname {{ rbr }}' was created with properties {}.\"" 16 | _msg2: "\"{{ lbr }} jname {{ rbr }} already exists\"" 17 | -------------------------------------------------------------------------------- /test/vars/tests.d/test_pkg_crash.yml: -------------------------------------------------------------------------------- 1 | --- 2 | test_pkg_crash: 3 | template: command_crash 4 | label: 'test_pkg_crash: Check if pkg info does not work in not-started jail {{ lbr }} jname {{ rbr }}' 5 | iocage: 6 | state: pkg 7 | name: '{{ lbr }} jname {{ rbr }}' 8 | cmd: 'info' 9 | assert: 10 | - '_msg1 == ansible_failed_result.msg or _msg2 == ansible_failed_result.msg' 11 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }} or {{ lbr }} _msg2 {{ rbr }}' 12 | vars: 13 | _msg1: "\"Jail '{{ lbr }} jname {{ rbr }}' doesn't exist\"" 14 | _msg2: "\"Jail '{{ lbr }} jname {{ rbr }}' not running\"" 15 | -------------------------------------------------------------------------------- /test/vars/tests.d/base_clone.yml: -------------------------------------------------------------------------------- 1 | --- 2 | base_clone: 3 | template: command 4 | label: 'base_clone: Check if {{ lbr }} jname {{ rbr }} can be cloned' 5 | iocage: 6 | state: cloned 7 | name: '{{ lbr }} jname {{ rbr }}' 8 | clone_from: '{{ lbr }} basejail {{ rbr }}' 9 | debug: 10 | - var: result.msg 11 | assert: 12 | - '_msg1 in result.msg or _msg2 == result.msg' 13 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }} or {{ lbr }} _msg2 {{ rbr }}' 14 | vars: 15 | _msg1: "\"'{{ lbr }} jname {{ rbr }}' was created with properties {}.\"" 16 | _msg2: "\"{{ lbr }} jname {{ rbr }} already exists\"" 17 | -------------------------------------------------------------------------------- /test/vars/tests.d/template_create.yml: -------------------------------------------------------------------------------- 1 | --- 2 | template_create: 3 | template: command 4 | label: 'template_create: Check if template {{ lbr }} basejail {{ rbr }} can be created' 5 | iocage: 6 | state: template 7 | name: '{{ lbr }} basejail {{ rbr }}' 8 | release: '{{ lbr }} release {{ rbr }}' 9 | debug: 10 | - var: result.msg 11 | assert: 12 | - '_msg1 in result.msg or _msg2 in result.msg' 13 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }} or {{ lbr }} _msg2 {{ rbr }}' 14 | vars: 15 | _msg1: "\"{{ lbr }} basejail {{ rbr }} was created\"" 16 | _msg2: "\"{{ lbr }} basejail {{ rbr }} already exists\"" 17 | -------------------------------------------------------------------------------- /test/vars/tests.d/test_absent.yml: -------------------------------------------------------------------------------- 1 | --- 2 | test_absent: 3 | template: command 4 | label: 'test_absent: Check if jail {{ lbr }} jname {{ rbr }} can be destroyed' 5 | iocage: 6 | state: absent 7 | name: '{{ lbr }} jname {{ rbr }}' 8 | debug: 9 | - var: result.msg 10 | assert: 11 | - '_msg1 in result.msg or _msg2 == result.msg' 12 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }} or {{ lbr }} _msg2 {{ rbr }}' 13 | vars: 14 | _msg1: "\"Jail '{{ lbr }} jname {{ rbr }}' was destroyed., Jail {{ lbr }} jname {{ rbr }} removed from iocage_jails.\"" 15 | _msg2: "\"Jail {{ lbr }} jname {{ rbr }} is already absent.\"" 16 | -------------------------------------------------------------------------------- /test/vars/tests.d/base_create.yml: -------------------------------------------------------------------------------- 1 | --- 2 | base_create: 3 | template: command 4 | label: 'base_create: Check if {{ lbr }} basejail {{ rbr }} can be created' 5 | iocage: 6 | state: basejail 7 | name: '{{ lbr }} basejail {{ rbr }}' 8 | release: '{{ lbr }} release {{ rbr }}' 9 | debug: 10 | - var: result.msg 11 | assert: 12 | - '_msg1 in result.msg or _msg2 == result.msg' 13 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }} or {{ lbr }} _msg2 {{ rbr }}' 14 | vars: 15 | _msg1: "\"Jail '{{ lbr }} basejail {{ rbr }}' was created with properties {}.\"" 16 | _msg2: "\"{{ lbr }} basejail {{ rbr }} already exists\"" 17 | -------------------------------------------------------------------------------- /test/vars/tests.d/jail_absent.yml: -------------------------------------------------------------------------------- 1 | --- 2 | jail_absent: 3 | template: command 4 | label: 'jail_absent: Check if cloned jail {{ lbr }} jname {{ rbr }} can be destroyed' 5 | iocage: 6 | state: absent 7 | name: '{{ lbr }} jname {{ rbr }}' 8 | debug: 9 | - var: result.msg 10 | assert: 11 | - '_msg1 == result.msg or _msg2 == result.msg' 12 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }} or {{ lbr }} _msg2 {{ rbr }}' 13 | vars: 14 | _msg1: "\"Jail '{{ lbr }} jname {{ rbr }}' was destroyed., Jail {{ lbr }} jname {{ rbr }} removed from iocage_jails.\"" 15 | _msg2: "\"Jail {{ lbr }} jname {{ rbr }} is already absent.\"" 16 | -------------------------------------------------------------------------------- /test/vars/tests.d/test_set.yml: -------------------------------------------------------------------------------- 1 | --- 2 | test_set: 3 | template: command 4 | label: 'test_set: Set properties at {{ lbr }} jname {{ rbr }}' 5 | iocage: 6 | state: set 7 | name: '{{ lbr }} jname {{ rbr }}' 8 | properties: '{{ lbr }} properties {{ rbr }}' 9 | debug: 10 | - var: result.msg 11 | debug2: 12 | - var: iocage_templates[basejail].properties 13 | assert: 14 | - '_msg1 in result.msg or _msg2 in result.msg' 15 | msg_err: '[ERR] {{ lbr }} _test_name {{ rbr }} failed. Missing: {{ lbr }} _msg1 {{ rbr }} or {{ lbr }} _msg2 {{ rbr }}' 16 | vars: 17 | _msg1: "\"were set on jail '{{ lbr }} jname {{ rbr }}'\"" 18 | _msg2: "\"already set for jail {{ lbr }} jname {{ rbr }}\"" 19 | -------------------------------------------------------------------------------- /test/tasks/group_start_restart_stop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | - ansible.builtin.import_tasks: tasks/test_clone.yml 4 | vars: 5 | _test_name: test_clone 6 | - ansible.builtin.import_tasks: tasks/test_start.yml 7 | vars: 8 | _test_name: test_start 9 | - ansible.builtin.import_tasks: tasks/test_start.yml 10 | vars: 11 | _test_name: test_start 12 | - ansible.builtin.import_tasks: tasks/test_restart.yml 13 | vars: 14 | _test_name: test_restart 15 | - ansible.builtin.import_tasks: tasks/test_stop.yml 16 | vars: 17 | _test_name: test_stop 18 | - ansible.builtin.import_tasks: tasks/test_stop.yml 19 | vars: 20 | _test_name: test_stop 21 | - ansible.builtin.import_tasks: tasks/test_restart.yml 22 | vars: 23 | _test_name: test_restart 24 | - ansible.builtin.import_tasks: tasks/test_absent.yml 25 | vars: 26 | _test_name: test_absent 27 | -------------------------------------------------------------------------------- /test/tasks/misc_get_all.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - ansible.builtin.set_fact: 3 | _crash: true 4 | 5 | - block: 6 | - name: "misc_get_all: Get all properties of {{ basejail }}" 7 | iocage: 8 | state: get 9 | name: "{{ basejail }}" 10 | register: result 11 | - ansible.builtin.set_fact: 12 | _crash: false 13 | - ansible.builtin.debug: 14 | var: result 15 | when: debug|bool 16 | rescue: 17 | - ansible.builtin.debug: 18 | var: ansible_failed_result 19 | - ansible.builtin.import_tasks: custom_stats_crash.yml 20 | 21 | - block: 22 | - ansible.builtin.assert: 23 | that: _msg1 in result.msg or _msg2 == result.msg 24 | - ansible.builtin.import_tasks: custom_stats_pass.yml 25 | rescue: 26 | - ansible.builtin.debug: 27 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }} or {{ _msg2 }}" 28 | when: debug|bool 29 | - ansible.builtin.import_tasks: custom_stats_fail.yml 30 | vars: 31 | _msg1: "Jail '{{ basejail }}' was created with properties {}." 32 | _msg2: "{{ basejail }} already exists" 33 | when: not _crash 34 | -------------------------------------------------------------------------------- /test/tasks/sanity.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - block: 3 | - name: "sanity: Test python required {{ python_required }}" 4 | ansible.builtin.setup: 5 | gather_subset: min 6 | - ansible.builtin.debug: 7 | var: ansible_python.executable 8 | when: debug|bool 9 | - ansible.builtin.assert: 10 | that: 11 | - ansible_python.version.major >= python_required.0|int 12 | - ansible_python.version.micro >= python_required.1|int 13 | fail_msg: "[ERR] {{ _test_name }} failes. Pyhton >= {{ python_required }} is required on the node." 14 | tags: sanity_python 15 | 16 | - block: 17 | - name: "sanity: Test iocage is installed" 18 | ansible.builtin.command: 19 | cmd: iocage --version 20 | register: result 21 | - ansible.builtin.debug: 22 | var: result.stdout 23 | when: debug|bool 24 | rescue: 25 | - ansible.builtin.debug: 26 | var: ansible_failed_result 27 | when: debug|bool 28 | - ansible.builtin.fail: 29 | msg: "[ERR] {{ _test_name }} failes. devel/iocage is required on the node." 30 | tags: sanity_iocage 31 | 32 | - ansible.builtin.import_tasks: custom_stats_pass.yml 33 | -------------------------------------------------------------------------------- /test/tasks/group_test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | - ansible.builtin.import_tasks: tasks/test_present.yml 4 | vars: 5 | _test_name: test_present 6 | - ansible.builtin.import_tasks: tasks/test_absent.yml 7 | vars: 8 | _test_name: test_absent 9 | - ansible.builtin.import_tasks: tasks/test_clone.yml 10 | vars: 11 | _test_name: test_clone 12 | - ansible.builtin.import_tasks: tasks/test_start.yml 13 | vars: 14 | _test_name: test_start 15 | - ansible.builtin.import_tasks: tasks/test_start2.yml 16 | vars: 17 | _test_name: test_start2 18 | - ansible.builtin.import_tasks: tasks/test_exec.yml 19 | vars: 20 | _test_name: test_exec 21 | cmd: /bin/ls -la /root 22 | 23 | - ansible.builtin.import_tasks: tasks/test_restart.yml 24 | vars: 25 | _test_name: test_restart 26 | - ansible.builtin.import_tasks: tasks/test_stop.yml 27 | vars: 28 | _test_name: test_stop 29 | - ansible.builtin.import_tasks: tasks/test_pkg_crash.yml 30 | vars: 31 | _test_name: test_pkg_crash 32 | - ansible.builtin.import_tasks: tasks/test_start3.yml 33 | vars: 34 | _test_name: test_start3 35 | - ansible.builtin.import_tasks: tasks/test_absent.yml 36 | vars: 37 | _test_name: test_absent 38 | - ansible.builtin.import_tasks: tasks/test_absent2.yml 39 | vars: 40 | _test_name: test_absent2 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2015, Perceivon Hosting Inc. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY [COPYRIGHT HOLDER] AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL [COPYRIGHT HOLDER] OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | -------------------------------------------------------------------------------- /test/templates/iocage_test.yml.j2: -------------------------------------------------------------------------------- 1 | #jinja2: trim_blocks: False 2 | --- 3 | # {{ ansible_managed }} 4 | 5 | - hosts: "{{ lbr }} my_hosts|default('localhost') {{ rbr }}" 6 | strategy: "{{ lbr }} my_strategy|default('linear') {{ rbr }}" 7 | gather_facts: false 8 | become: true 9 | become_method: sudo 10 | 11 | vars: 12 | 13 | python_required: "{{ lbr }} my_python_required|default('36') {{ rbr }}" 14 | jname: "{{ lbr }} my_jname|default('test_jail') {{ rbr }}" 15 | release: "{{ lbr }} my_release|default('13.0-RELEASE') {{ rbr }}" 16 | label_default: "{{ lbr }} release|regex_replace('[\\W]', '_') {{ rbr }}" 17 | label: "{{ lbr }} my_label|default(label_default) {{ rbr }}" 18 | basejail_default: "test_basejail_{{ lbr }} label {{ rbr }}" 19 | basejail: "{{ lbr }} my_basejail|default(basejail_default) {{ rbr }}" 20 | properties: "{{ lbr }} my_properties|default({}) {{ rbr }}" 21 | debug: "{{ lbr }} my_debug|default(false) {{ rbr }}" 22 | debug2: "{{ lbr }} my_debug2|default(false) {{ rbr }}" 23 | 24 | tasks: 25 | 26 | - ansible.builtin.import_tasks: tasks/custom_stats_start.yml 27 | tags: always 28 | {% for i in iocage_group_db.keys()|sort %} 29 | - ansible.builtin.import_tasks: tasks/{{ i }}.yml 30 | tags: {{ i }} 31 | {% endfor %} 32 | - ansible.builtin.import_tasks: tasks/custom_stats_end.yml 33 | tags: always 34 | -------------------------------------------------------------------------------- /test/tasks/absent_start_crash.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to crash with expected message(s). 5 | # Status: 6 | # pass ..... module crash with expected message(s) 7 | # fail ..... module crash without expected message(s) 8 | # crash .... module does not crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: false 12 | 13 | - block: 14 | - name: " >>> TEST START: absent_start_crash: Check if absent jail can not be started" 15 | iocage: 16 | { 17 | "name": "absent", 18 | "state": "started" 19 | } 20 | register: result 21 | - ansible.builtin.debug: 22 | var: result 23 | when: debug2|bool 24 | - ansible.builtin.import_tasks: custom_stats_crash.yml 25 | rescue: 26 | - ansible.builtin.set_fact: 27 | _crash: true 28 | - ansible.builtin.debug: 29 | var: ansible_failed_result 30 | when: debug|bool 31 | 32 | - block: 33 | - ansible.builtin.assert: 34 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ ansible_failed_result.msg }}" 35 | success_msg: "[OK] {{ _test_name }}: Passed: {{ ansible_failed_result.msg }}" 36 | that: 37 | - _msg1 == ansible_failed_result.msg 38 | - ansible.builtin.import_tasks: custom_stats_pass.yml 39 | rescue: 40 | - ansible.builtin.debug: 41 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }}" 42 | when: debug|bool 43 | - ansible.builtin.import_tasks: custom_stats_fail.yml 44 | vars: 45 | _msg1: "Jail 'absent' doesn't exist" 46 | when: _crash 47 | -------------------------------------------------------------------------------- /test/tasks/absent_stop_crash.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to crash with expected message(s). 5 | # Status: 6 | # pass ..... module crash with expected message(s) 7 | # fail ..... module crash without expected message(s) 8 | # crash .... module does not crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: false 12 | 13 | - block: 14 | - name: " >>> TEST START: absent_stop_crash: Check if absent jail can not be stopped" 15 | iocage: 16 | { 17 | "name": "absent", 18 | "state": "stopped" 19 | } 20 | register: result 21 | - ansible.builtin.debug: 22 | var: result 23 | when: debug2|bool 24 | - ansible.builtin.import_tasks: custom_stats_crash.yml 25 | rescue: 26 | - ansible.builtin.set_fact: 27 | _crash: true 28 | - ansible.builtin.debug: 29 | var: ansible_failed_result 30 | when: debug|bool 31 | 32 | - block: 33 | - ansible.builtin.assert: 34 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ ansible_failed_result.msg }}" 35 | success_msg: "[OK] {{ _test_name }}: Passed: {{ ansible_failed_result.msg }}" 36 | that: 37 | - _msg1 == ansible_failed_result.msg 38 | - ansible.builtin.import_tasks: custom_stats_pass.yml 39 | rescue: 40 | - ansible.builtin.debug: 41 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }}" 42 | when: debug|bool 43 | - ansible.builtin.import_tasks: custom_stats_fail.yml 44 | vars: 45 | _msg1: "Jail 'absent' doesn't exist" 46 | when: _crash 47 | -------------------------------------------------------------------------------- /test/tasks/absent_restart_crash.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to crash with expected message(s). 5 | # Status: 6 | # pass ..... module crash with expected message(s) 7 | # fail ..... module crash without expected message(s) 8 | # crash .... module does not crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: false 12 | 13 | - block: 14 | - name: " >>> TEST START: absent_restart_crash: Check if absent jail can not be restarted" 15 | iocage: 16 | { 17 | "name": "absent", 18 | "state": "restarted" 19 | } 20 | register: result 21 | - ansible.builtin.debug: 22 | var: result 23 | when: debug2|bool 24 | - ansible.builtin.import_tasks: custom_stats_crash.yml 25 | rescue: 26 | - ansible.builtin.set_fact: 27 | _crash: true 28 | - ansible.builtin.debug: 29 | var: ansible_failed_result 30 | when: debug|bool 31 | 32 | - block: 33 | - ansible.builtin.assert: 34 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ ansible_failed_result.msg }}" 35 | success_msg: "[OK] {{ _test_name }}: Passed: {{ ansible_failed_result.msg }}" 36 | that: 37 | - _msg1 == ansible_failed_result.msg 38 | - ansible.builtin.import_tasks: custom_stats_pass.yml 39 | rescue: 40 | - ansible.builtin.debug: 41 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }}" 42 | when: debug|bool 43 | - ansible.builtin.import_tasks: custom_stats_fail.yml 44 | vars: 45 | _msg1: "Jail 'absent' doesn't exist" 46 | when: _crash 47 | -------------------------------------------------------------------------------- /test/tasks/base_exists.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: base_exists: Check if {{ basejail }} exists" 15 | iocage: 16 | { 17 | "name": "{{ basejail }}", 18 | "state": "exists" 19 | } 20 | register: result 21 | - ansible.builtin.set_fact: 22 | _crash: false 23 | - ansible.builtin.debug: 24 | var: result 25 | when: debug2|bool 26 | - ansible.builtin.debug: 27 | var: result.msg 28 | when: debug|bool 29 | rescue: 30 | - ansible.builtin.debug: 31 | var: ansible_failed_result 32 | when: debug|bool 33 | - ansible.builtin.import_tasks: custom_stats_crash.yml 34 | 35 | - block: 36 | - ansible.builtin.assert: 37 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 38 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 39 | that: 40 | - _msg1 == result.msg 41 | - ansible.builtin.import_tasks: custom_stats_pass.yml 42 | rescue: 43 | - ansible.builtin.debug: 44 | msg: "[ERR] {{ _test_name }} failed. Miising: {{ _msg1 }}" 45 | when: debug|bool 46 | - ansible.builtin.import_tasks: custom_stats_fail.yml 47 | vars: 48 | _msg1: "Jail {{ basejail }} exists" 49 | when: not _crash 50 | -------------------------------------------------------------------------------- /test/tasks/test_start_crash.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to crash with expected message(s). 5 | # Status: 6 | # pass ..... module crash with expected message(s) 7 | # fail ..... module crash without expected message(s) 8 | # crash .... module does not crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: false 12 | 13 | - block: 14 | - name: " >>> TEST START: test_start_crash: Check if not-existent jail {{ jname }} can not be started" 15 | iocage: 16 | { 17 | "name": "{{ jname }}", 18 | "state": "started" 19 | } 20 | register: result 21 | - ansible.builtin.debug: 22 | var: result 23 | when: debug2|bool 24 | - ansible.builtin.import_tasks: custom_stats_crash.yml 25 | rescue: 26 | - ansible.builtin.set_fact: 27 | _crash: true 28 | - ansible.builtin.debug: 29 | var: ansible_failed_result 30 | when: debug|bool 31 | 32 | - block: 33 | - ansible.builtin.assert: 34 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ ansible_failed_result.msg }}" 35 | success_msg: "[OK] {{ _test_name }}: Passed: {{ ansible_failed_result.msg }}" 36 | that: 37 | - _msg1 == ansible_failed_result.msg 38 | - ansible.builtin.import_tasks: custom_stats_pass.yml 39 | rescue: 40 | - ansible.builtin.debug: 41 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }}" 42 | when: debug|bool 43 | - ansible.builtin.import_tasks: custom_stats_fail.yml 44 | vars: 45 | _msg1: "Jail '{{ jname }}' doesn't exist" 46 | when: _crash 47 | -------------------------------------------------------------------------------- /test/tasks/test_stop_crash.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to crash with expected message(s). 5 | # Status: 6 | # pass ..... module crash with expected message(s) 7 | # fail ..... module crash without expected message(s) 8 | # crash .... module does not crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: false 12 | 13 | - block: 14 | - name: " >>> TEST START: test_stop_crash: Check if not-existent jail {{ jname }} can not be stopped" 15 | iocage: 16 | { 17 | "name": "{{ jname }}", 18 | "state": "stopped" 19 | } 20 | register: result 21 | - ansible.builtin.debug: 22 | var: result 23 | when: debug2|bool 24 | - ansible.builtin.import_tasks: custom_stats_crash.yml 25 | rescue: 26 | - ansible.builtin.set_fact: 27 | _crash: true 28 | - ansible.builtin.debug: 29 | var: ansible_failed_result 30 | when: debug|bool 31 | 32 | - block: 33 | - ansible.builtin.assert: 34 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ ansible_failed_result.msg }}" 35 | success_msg: "[OK] {{ _test_name }}: Passed: {{ ansible_failed_result.msg }}" 36 | that: 37 | - _msg1 == ansible_failed_result.msg 38 | - ansible.builtin.import_tasks: custom_stats_pass.yml 39 | rescue: 40 | - ansible.builtin.debug: 41 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }}" 42 | when: debug|bool 43 | - ansible.builtin.import_tasks: custom_stats_fail.yml 44 | vars: 45 | _msg1: "Jail '{{ jname }}' doesn't exist" 46 | when: _crash 47 | -------------------------------------------------------------------------------- /test/tasks/absent_absent.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: absent_absent: Check if absent jail can be destroyed" 15 | iocage: 16 | { 17 | "name": "absent", 18 | "state": "absent" 19 | } 20 | register: result 21 | - ansible.builtin.set_fact: 22 | _crash: false 23 | - ansible.builtin.debug: 24 | var: result 25 | when: debug2|bool 26 | - ansible.builtin.debug: 27 | var: result.msg 28 | when: debug|bool 29 | rescue: 30 | - ansible.builtin.debug: 31 | var: ansible_failed_result 32 | when: debug|bool 33 | - ansible.builtin.import_tasks: custom_stats_crash.yml 34 | 35 | - block: 36 | - ansible.builtin.assert: 37 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 38 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 39 | that: 40 | - _msg1 == result.msg 41 | - ansible.builtin.import_tasks: custom_stats_pass.yml 42 | rescue: 43 | - ansible.builtin.debug: 44 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }}" 45 | when: debug|bool 46 | - ansible.builtin.import_tasks: custom_stats_fail.yml 47 | vars: 48 | _msg1: "Jail absent is already absent." 49 | when: not _crash 50 | -------------------------------------------------------------------------------- /test/tasks/fetch.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: fetch: Check if release {{ release }} exists" 15 | iocage: 16 | { 17 | "release": "{{ release }}", 18 | "state": "fetched" 19 | } 20 | register: result 21 | - ansible.builtin.set_fact: 22 | _crash: false 23 | - ansible.builtin.debug: 24 | var: result 25 | when: debug2|bool 26 | rescue: 27 | - ansible.builtin.debug: 28 | var: ansible_failed_result 29 | when: debug|bool 30 | - ansible.builtin.import_tasks: custom_stats_crash.yml 31 | 32 | - block: 33 | - ansible.builtin.assert: 34 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 35 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 36 | that: 37 | - result.msg is search(release) 38 | - not result.changed 39 | - not result.failed 40 | - result.stderr_lines|length == 0 41 | - result.stdout_lines|length == 0 42 | - ansible.builtin.import_tasks: custom_stats_pass.yml 43 | rescue: 44 | - ansible.builtin.debug: 45 | msg: "[ERR] {{ _test_name }} failed." 46 | when: debug|bool 47 | - ansible.builtin.import_tasks: custom_stats_fail.yml 48 | when: not _crash 49 | -------------------------------------------------------------------------------- /test/tasks/test_exec.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: test_exec: Check if exec works in jail {{ jname }}" 15 | iocage: 16 | { 17 | "cmd": "{{ cmd }}", 18 | "name": "{{ jname }}", 19 | "state": "exec" 20 | } 21 | register: result 22 | - ansible.builtin.set_fact: 23 | _crash: false 24 | - ansible.builtin.debug: 25 | var: result 26 | when: debug2|bool 27 | - ansible.builtin.debug: 28 | var: result.msg 29 | when: debug|bool 30 | rescue: 31 | - ansible.builtin.debug: 32 | var: ansible_failed_result 33 | when: debug|bool 34 | - ansible.builtin.import_tasks: custom_stats_crash.yml 35 | 36 | - block: 37 | - ansible.builtin.assert: 38 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 39 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 40 | that: 41 | - _msg1 in result.msg 42 | - ansible.builtin.import_tasks: custom_stats_pass.yml 43 | rescue: 44 | - ansible.builtin.debug: 45 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }}" 46 | when: debug|bool 47 | - ansible.builtin.import_tasks: custom_stats_fail.yml 48 | vars: 49 | _msg1: "rc: 0" 50 | when: not _crash 51 | -------------------------------------------------------------------------------- /test/tasks/test_restart_crash.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to crash with expected message(s). 5 | # Status: 6 | # pass ..... module crash with expected message(s) 7 | # fail ..... module crash without expected message(s) 8 | # crash .... module does not crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: false 12 | 13 | - block: 14 | - name: " >>> TEST START: test_restart_crash: Check if not-existent jail {{ jname }} can not be restarted" 15 | iocage: 16 | { 17 | "name": "{{ jname }}", 18 | "state": "restarted" 19 | } 20 | register: result 21 | - ansible.builtin.debug: 22 | var: result 23 | when: debug2|bool 24 | - ansible.builtin.import_tasks: custom_stats_crash.yml 25 | rescue: 26 | - ansible.builtin.set_fact: 27 | _crash: true 28 | - ansible.builtin.debug: 29 | var: ansible_failed_result 30 | when: debug|bool 31 | 32 | - block: 33 | - ansible.builtin.assert: 34 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ ansible_failed_result.msg }}" 35 | success_msg: "[OK] {{ _test_name }}: Passed: {{ ansible_failed_result.msg }}" 36 | that: 37 | - _msg1 == ansible_failed_result.msg 38 | - ansible.builtin.import_tasks: custom_stats_pass.yml 39 | rescue: 40 | - ansible.builtin.debug: 41 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }}" 42 | when: debug|bool 43 | - ansible.builtin.import_tasks: custom_stats_fail.yml 44 | vars: 45 | _msg1: "Jail '{{ jname }}' doesn't exist" 46 | when: _crash 47 | -------------------------------------------------------------------------------- /test/tasks/template_start_crash.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to crash with expected message(s). 5 | # Status: 6 | # pass ..... module crash with expected message(s) 7 | # fail ..... module crash without expected message(s) 8 | # crash .... module does not crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: false 12 | 13 | - block: 14 | - name: " >>> TEST START: template_start_crash: Check if template {{ basejail }} can not be started" 15 | iocage: 16 | { 17 | "name": "{{ basejail }}", 18 | "state": "started" 19 | } 20 | register: result 21 | - ansible.builtin.debug: 22 | var: result 23 | when: debug2|bool 24 | - ansible.builtin.import_tasks: custom_stats_crash.yml 25 | rescue: 26 | - ansible.builtin.set_fact: 27 | _crash: true 28 | - ansible.builtin.debug: 29 | var: ansible_failed_result 30 | when: debug|bool 31 | 32 | - block: 33 | - ansible.builtin.assert: 34 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ ansible_failed_result.msg }}" 35 | success_msg: "[OK] {{ _test_name }}: Passed: {{ ansible_failed_result.msg }}" 36 | that: 37 | - _msg1 in ansible_failed_result.msg 38 | - ansible.builtin.import_tasks: custom_stats_pass.yml 39 | rescue: 40 | - ansible.builtin.debug: 41 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }}" 42 | when: debug|bool 43 | - ansible.builtin.import_tasks: custom_stats_fail.yml 44 | vars: 45 | _msg1: "Jail {{ basejail }} could not be started" 46 | when: _crash 47 | -------------------------------------------------------------------------------- /test/tasks/test_restart.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: test_restart: Check if jail {{ jname }} can be restarted" 15 | iocage: 16 | { 17 | "name": "{{ jname }}", 18 | "state": "restarted" 19 | } 20 | register: result 21 | - ansible.builtin.set_fact: 22 | _crash: false 23 | - ansible.builtin.debug: 24 | var: result 25 | when: debug2|bool 26 | - ansible.builtin.debug: 27 | var: result.msg 28 | when: debug|bool 29 | rescue: 30 | - ansible.builtin.debug: 31 | var: ansible_failed_result 32 | when: debug|bool 33 | - ansible.builtin.import_tasks: custom_stats_crash.yml 34 | 35 | - block: 36 | - ansible.builtin.assert: 37 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 38 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 39 | that: 40 | - _msg1 in result.msg 41 | - ansible.builtin.import_tasks: custom_stats_pass.yml 42 | rescue: 43 | - ansible.builtin.debug: 44 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }}" 45 | when: debug|bool 46 | - ansible.builtin.import_tasks: custom_stats_fail.yml 47 | vars: 48 | _msg1: "Jail {{ jname }} was restarted." 49 | when: not _crash 50 | -------------------------------------------------------------------------------- /test/tasks/test_start2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: test_start2: Check if jail {{ jname }} can be started again" 15 | iocage: 16 | { 17 | "name": "{{ jname }}", 18 | "state": "started" 19 | } 20 | register: result 21 | - ansible.builtin.set_fact: 22 | _crash: false 23 | - ansible.builtin.debug: 24 | var: result 25 | when: debug2|bool 26 | - ansible.builtin.debug: 27 | var: result.msg 28 | when: debug|bool 29 | rescue: 30 | - ansible.builtin.debug: 31 | var: ansible_failed_result 32 | when: debug|bool 33 | - ansible.builtin.import_tasks: custom_stats_crash.yml 34 | 35 | - block: 36 | - ansible.builtin.assert: 37 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 38 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 39 | that: 40 | - _msg2 == result.msg 41 | - ansible.builtin.import_tasks: custom_stats_pass.yml 42 | rescue: 43 | - ansible.builtin.debug: 44 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg2 }}" 45 | when: debug|bool 46 | - ansible.builtin.import_tasks: custom_stats_fail.yml 47 | vars: 48 | _msg2: "Jail {{ jname }} already started" 49 | when: not _crash 50 | -------------------------------------------------------------------------------- /test/tasks/test_absent2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: test_absent2: Check if jail {{ jname }} can be destroyed again" 15 | iocage: 16 | { 17 | "name": "{{ jname }}", 18 | "state": "absent" 19 | } 20 | register: result 21 | - ansible.builtin.set_fact: 22 | _crash: false 23 | - ansible.builtin.debug: 24 | var: result 25 | when: debug2|bool 26 | - ansible.builtin.debug: 27 | var: result.msg 28 | when: debug|bool 29 | rescue: 30 | - ansible.builtin.debug: 31 | var: ansible_failed_result 32 | when: debug|bool 33 | - ansible.builtin.import_tasks: custom_stats_crash.yml 34 | 35 | - block: 36 | - ansible.builtin.assert: 37 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 38 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 39 | that: 40 | - _msg2 == result.msg 41 | - ansible.builtin.import_tasks: custom_stats_pass.yml 42 | rescue: 43 | - ansible.builtin.debug: 44 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg2 }}" 45 | when: debug|bool 46 | - ansible.builtin.import_tasks: custom_stats_fail.yml 47 | vars: 48 | _msg2: "Jail {{ jname }} is already absent." 49 | when: not _crash 50 | -------------------------------------------------------------------------------- /test/tasks/template_stop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: template_stop: Check if template {{ basejail }} can not be stopped" 15 | iocage: 16 | { 17 | "name": "{{ basejail }}", 18 | "state": "stopped" 19 | } 20 | register: result 21 | - ansible.builtin.set_fact: 22 | _crash: false 23 | - ansible.builtin.debug: 24 | var: result 25 | when: debug2|bool 26 | - ansible.builtin.debug: 27 | var: result.msg 28 | when: debug|bool 29 | rescue: 30 | - ansible.builtin.debug: 31 | var: ansible_failed_result 32 | when: debug|bool 33 | - ansible.builtin.import_tasks: custom_stats_crash.yml 34 | 35 | - block: 36 | - ansible.builtin.assert: 37 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 38 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 39 | that: 40 | - _msg1 in result.msg 41 | - ansible.builtin.import_tasks: custom_stats_pass.yml 42 | rescue: 43 | - ansible.builtin.debug: 44 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }}" 45 | when: debug|bool 46 | - ansible.builtin.import_tasks: custom_stats_fail.yml 47 | vars: 48 | _msg1: "Jail {{ basejail }} already stopped" 49 | when: not _crash 50 | -------------------------------------------------------------------------------- /test/tasks/test_pkg.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: test_pkg: Check if pkg info works in started jail {{ jname }}" 15 | iocage: 16 | { 17 | "cmd": "info", 18 | "name": "{{ jname }}", 19 | "state": "pkg" 20 | } 21 | register: result 22 | - ansible.builtin.set_fact: 23 | _crash: false 24 | - ansible.builtin.debug: 25 | var: result 26 | when: debug2|bool 27 | - ansible.builtin.debug: 28 | var: result.msg 29 | when: debug|bool 30 | rescue: 31 | - ansible.builtin.debug: 32 | var: ansible_failed_result 33 | when: debug|bool 34 | - ansible.builtin.import_tasks: custom_stats_crash.yml 35 | 36 | - block: 37 | - ansible.builtin.assert: 38 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 39 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 40 | that: 41 | - _msg1 in result.msg 42 | - ansible.builtin.import_tasks: custom_stats_pass.yml 43 | rescue: 44 | - ansible.builtin.debug: 45 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }}" 46 | when: debug|bool 47 | - ansible.builtin.import_tasks: custom_stats_fail.yml 48 | vars: 49 | _msg1: "was executed in jail '{{ jname }}'" 50 | when: not _crash 51 | -------------------------------------------------------------------------------- /test/tasks/test_start.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: test_start: Check if jail {{ jname }} can be started" 15 | iocage: 16 | { 17 | "name": "{{ jname }}", 18 | "state": "started" 19 | } 20 | register: result 21 | - ansible.builtin.set_fact: 22 | _crash: false 23 | - ansible.builtin.debug: 24 | var: result 25 | when: debug2|bool 26 | - ansible.builtin.debug: 27 | var: result.msg 28 | when: debug|bool 29 | rescue: 30 | - ansible.builtin.debug: 31 | var: ansible_failed_result 32 | when: debug|bool 33 | - ansible.builtin.import_tasks: custom_stats_crash.yml 34 | 35 | - block: 36 | - ansible.builtin.assert: 37 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 38 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 39 | that: 40 | - _msg1 in result.msg or _msg2 == result.msg 41 | - ansible.builtin.import_tasks: custom_stats_pass.yml 42 | rescue: 43 | - ansible.builtin.debug: 44 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }} or {{ _msg2 }}" 45 | when: debug|bool 46 | - ansible.builtin.import_tasks: custom_stats_fail.yml 47 | vars: 48 | _msg1: "Jail {{ jname }} was started." 49 | _msg2: "Jail {{ jname }} already started" 50 | when: not _crash 51 | -------------------------------------------------------------------------------- /test/tasks/test_stop.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: test_stop: Check if jail {{ jname }} can be stopped" 15 | iocage: 16 | { 17 | "name": "{{ jname }}", 18 | "state": "stopped" 19 | } 20 | register: result 21 | - ansible.builtin.set_fact: 22 | _crash: false 23 | - ansible.builtin.debug: 24 | var: result 25 | when: debug2|bool 26 | - ansible.builtin.debug: 27 | var: result.msg 28 | when: debug|bool 29 | rescue: 30 | - ansible.builtin.debug: 31 | var: ansible_failed_result 32 | when: debug|bool 33 | - ansible.builtin.import_tasks: custom_stats_crash.yml 34 | 35 | - block: 36 | - ansible.builtin.assert: 37 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 38 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 39 | that: 40 | - _msg1 in result.msg or _msg2 == result.msg 41 | - ansible.builtin.import_tasks: custom_stats_pass.yml 42 | rescue: 43 | - ansible.builtin.debug: 44 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }} or {{ _msg2 }}" 45 | when: debug|bool 46 | - ansible.builtin.import_tasks: custom_stats_fail.yml 47 | vars: 48 | _msg1: "Jail {{ jname }} was stopped." 49 | _msg2: "Jail {{ jname }} already stopped" 50 | when: not _crash 51 | -------------------------------------------------------------------------------- /test/tasks/test_start3.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: test_start3: Check if jail {{ jname }} can be started again" 15 | iocage: 16 | { 17 | "name": "{{ jname }}", 18 | "state": "started" 19 | } 20 | register: result 21 | - ansible.builtin.set_fact: 22 | _crash: false 23 | - ansible.builtin.debug: 24 | var: result 25 | when: debug2|bool 26 | - ansible.builtin.debug: 27 | var: result.msg 28 | when: debug|bool 29 | rescue: 30 | - ansible.builtin.debug: 31 | var: ansible_failed_result 32 | when: debug|bool 33 | - ansible.builtin.import_tasks: custom_stats_crash.yml 34 | 35 | - block: 36 | - ansible.builtin.assert: 37 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 38 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 39 | that: 40 | - _msg1 in result.msg or _msg2 == result.msg 41 | - ansible.builtin.import_tasks: custom_stats_pass.yml 42 | rescue: 43 | - ansible.builtin.debug: 44 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }} or {{ _msg2 }}" 45 | when: debug|bool 46 | - ansible.builtin.import_tasks: custom_stats_fail.yml 47 | vars: 48 | _msg1: "Jail {{ jname }} was started." 49 | _msg2: "Jail {{ jname }} already started" 50 | when: not _crash 51 | -------------------------------------------------------------------------------- /test/tasks/test_present.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: test_present: Check if {{ jname }} can be created" 15 | iocage: 16 | { 17 | "name": "{{ jname }}", 18 | "state": "present" 19 | } 20 | register: result 21 | - ansible.builtin.set_fact: 22 | _crash: false 23 | - ansible.builtin.debug: 24 | var: result 25 | when: debug2|bool 26 | - ansible.builtin.debug: 27 | var: result.msg 28 | when: debug|bool 29 | rescue: 30 | - ansible.builtin.debug: 31 | var: ansible_failed_result 32 | when: debug|bool 33 | - ansible.builtin.import_tasks: custom_stats_crash.yml 34 | 35 | - block: 36 | - ansible.builtin.assert: 37 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 38 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 39 | that: 40 | - _msg1 in result.msg or _msg2 == result.msg 41 | - ansible.builtin.import_tasks: custom_stats_pass.yml 42 | rescue: 43 | - ansible.builtin.debug: 44 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }} or {{ _msg2 }}" 45 | when: debug|bool 46 | - ansible.builtin.import_tasks: custom_stats_fail.yml 47 | vars: 48 | _msg1: "Jail '{{ jname }}' was created with properties {}." 49 | _msg2: "{{ jname }} already exists" 50 | when: not _crash 51 | -------------------------------------------------------------------------------- /test/tasks/test_set.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: test_set: Set properties at {{ jname }}" 15 | iocage: 16 | { 17 | "name": "{{ jname }}", 18 | "properties": "{{ properties }}", 19 | "state": "set" 20 | } 21 | register: result 22 | - ansible.builtin.set_fact: 23 | _crash: false 24 | - ansible.builtin.debug: 25 | var: result 26 | when: debug2|bool 27 | - ansible.builtin.debug: 28 | var: result.msg 29 | when: debug|bool 30 | rescue: 31 | - ansible.builtin.debug: 32 | var: ansible_failed_result 33 | when: debug|bool 34 | - ansible.builtin.import_tasks: custom_stats_crash.yml 35 | 36 | - block: 37 | - ansible.builtin.assert: 38 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 39 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 40 | that: 41 | - _msg1 in result.msg or _msg2 in result.msg 42 | - ansible.builtin.import_tasks: custom_stats_pass.yml 43 | rescue: 44 | - ansible.builtin.debug: 45 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }} or {{ _msg2 }}" 46 | when: debug|bool 47 | - ansible.builtin.import_tasks: custom_stats_fail.yml 48 | vars: 49 | _msg1: "were set on jail '{{ jname }}'" 50 | _msg2: "already set for jail {{ jname }}" 51 | when: not _crash 52 | -------------------------------------------------------------------------------- /test/tasks/test_pkg_crash.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to crash with expected message(s). 5 | # Status: 6 | # pass ..... module crash with expected message(s) 7 | # fail ..... module crash without expected message(s) 8 | # crash .... module does not crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: false 12 | 13 | - block: 14 | - name: " >>> TEST START: test_pkg_crash: Check if pkg info does not work in not-started jail {{ jname }}" 15 | iocage: 16 | { 17 | "cmd": "info", 18 | "name": "{{ jname }}", 19 | "state": "pkg" 20 | } 21 | register: result 22 | - ansible.builtin.debug: 23 | var: result 24 | when: debug2|bool 25 | - ansible.builtin.import_tasks: custom_stats_crash.yml 26 | rescue: 27 | - ansible.builtin.set_fact: 28 | _crash: true 29 | - ansible.builtin.debug: 30 | var: ansible_failed_result 31 | when: debug|bool 32 | 33 | - block: 34 | - ansible.builtin.assert: 35 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ ansible_failed_result.msg }}" 36 | success_msg: "[OK] {{ _test_name }}: Passed: {{ ansible_failed_result.msg }}" 37 | that: 38 | - _msg1 == ansible_failed_result.msg or _msg2 == ansible_failed_result.msg 39 | - ansible.builtin.import_tasks: custom_stats_pass.yml 40 | rescue: 41 | - ansible.builtin.debug: 42 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }} or {{ _msg2 }}" 43 | when: debug|bool 44 | - ansible.builtin.import_tasks: custom_stats_fail.yml 45 | vars: 46 | _msg1: "Jail '{{ jname }}' doesn't exist" 47 | _msg2: "Jail '{{ jname }}' not running" 48 | when: _crash 49 | -------------------------------------------------------------------------------- /test/tasks/base_clone.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: base_clone: Check if {{ jname }} can be cloned" 15 | iocage: 16 | { 17 | "clone_from": "{{ basejail }}", 18 | "name": "{{ jname }}", 19 | "state": "cloned" 20 | } 21 | register: result 22 | - ansible.builtin.set_fact: 23 | _crash: false 24 | - ansible.builtin.debug: 25 | var: result 26 | when: debug2|bool 27 | - ansible.builtin.debug: 28 | var: result.msg 29 | when: debug|bool 30 | rescue: 31 | - ansible.builtin.debug: 32 | var: ansible_failed_result 33 | when: debug|bool 34 | - ansible.builtin.import_tasks: custom_stats_crash.yml 35 | 36 | - block: 37 | - ansible.builtin.assert: 38 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 39 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 40 | that: 41 | - _msg1 in result.msg or _msg2 == result.msg 42 | - ansible.builtin.import_tasks: custom_stats_pass.yml 43 | rescue: 44 | - ansible.builtin.debug: 45 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }} or {{ _msg2 }}" 46 | when: debug|bool 47 | - ansible.builtin.import_tasks: custom_stats_fail.yml 48 | vars: 49 | _msg1: "'{{ jname }}' was created with properties {}." 50 | _msg2: "{{ jname }} already exists" 51 | when: not _crash 52 | -------------------------------------------------------------------------------- /test/tasks/test_absent.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: test_absent: Check if jail {{ jname }} can be destroyed" 15 | iocage: 16 | { 17 | "name": "{{ jname }}", 18 | "state": "absent" 19 | } 20 | register: result 21 | - ansible.builtin.set_fact: 22 | _crash: false 23 | - ansible.builtin.debug: 24 | var: result 25 | when: debug2|bool 26 | - ansible.builtin.debug: 27 | var: result.msg 28 | when: debug|bool 29 | rescue: 30 | - ansible.builtin.debug: 31 | var: ansible_failed_result 32 | when: debug|bool 33 | - ansible.builtin.import_tasks: custom_stats_crash.yml 34 | 35 | - block: 36 | - ansible.builtin.assert: 37 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 38 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 39 | that: 40 | - _msg1 in result.msg or _msg2 == result.msg 41 | - ansible.builtin.import_tasks: custom_stats_pass.yml 42 | rescue: 43 | - ansible.builtin.debug: 44 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }} or {{ _msg2 }}" 45 | when: debug|bool 46 | - ansible.builtin.import_tasks: custom_stats_fail.yml 47 | vars: 48 | _msg1: "Jail '{{ jname }}' was destroyed., Jail {{ jname }} removed from iocage_jails." 49 | _msg2: "Jail {{ jname }} is already absent." 50 | when: not _crash 51 | -------------------------------------------------------------------------------- /test/tasks/test_clone.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: test_clone: Check if test jail can be cloned" 15 | iocage: 16 | { 17 | "clone_from": "{{ basejail }}", 18 | "name": "{{ jname }}", 19 | "state": "cloned" 20 | } 21 | register: result 22 | - ansible.builtin.set_fact: 23 | _crash: false 24 | - ansible.builtin.debug: 25 | var: result 26 | when: debug2|bool 27 | - ansible.builtin.debug: 28 | var: result.msg 29 | when: debug|bool 30 | rescue: 31 | - ansible.builtin.debug: 32 | var: ansible_failed_result 33 | when: debug|bool 34 | - ansible.builtin.import_tasks: custom_stats_crash.yml 35 | 36 | - block: 37 | - ansible.builtin.assert: 38 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 39 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 40 | that: 41 | - _msg1 in result.msg or _msg2 == result.msg 42 | - ansible.builtin.import_tasks: custom_stats_pass.yml 43 | rescue: 44 | - ansible.builtin.debug: 45 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }} or {{ _msg2 }}" 46 | when: debug|bool 47 | - ansible.builtin.import_tasks: custom_stats_fail.yml 48 | vars: 49 | _msg1: "Jail '{{ jname }}' was created with properties {}." 50 | _msg2: "{{ jname }} already exists" 51 | when: not _crash 52 | -------------------------------------------------------------------------------- /test/tasks/template_create.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: template_create: Check if template {{ basejail }} can be created" 15 | iocage: 16 | { 17 | "name": "{{ basejail }}", 18 | "release": "{{ release }}", 19 | "state": "template" 20 | } 21 | register: result 22 | - ansible.builtin.set_fact: 23 | _crash: false 24 | - ansible.builtin.debug: 25 | var: result 26 | when: debug2|bool 27 | - ansible.builtin.debug: 28 | var: result.msg 29 | when: debug|bool 30 | rescue: 31 | - ansible.builtin.debug: 32 | var: ansible_failed_result 33 | when: debug|bool 34 | - ansible.builtin.import_tasks: custom_stats_crash.yml 35 | 36 | - block: 37 | - ansible.builtin.assert: 38 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 39 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 40 | that: 41 | - _msg1 in result.msg or _msg2 in result.msg 42 | - ansible.builtin.import_tasks: custom_stats_pass.yml 43 | rescue: 44 | - ansible.builtin.debug: 45 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }} or {{ _msg2 }}" 46 | when: debug|bool 47 | - ansible.builtin.import_tasks: custom_stats_fail.yml 48 | vars: 49 | _msg1: "{{ basejail }} was created" 50 | _msg2: "{{ basejail }} already exists" 51 | when: not _crash 52 | -------------------------------------------------------------------------------- /test/tasks/jail_absent.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: jail_absent: Check if cloned jail {{ jname }} can be destroyed" 15 | iocage: 16 | { 17 | "name": "{{ jname }}", 18 | "state": "absent" 19 | } 20 | register: result 21 | - ansible.builtin.set_fact: 22 | _crash: false 23 | - ansible.builtin.debug: 24 | var: result 25 | when: debug2|bool 26 | - ansible.builtin.debug: 27 | var: result.msg 28 | when: debug|bool 29 | rescue: 30 | - ansible.builtin.debug: 31 | var: ansible_failed_result 32 | when: debug|bool 33 | - ansible.builtin.import_tasks: custom_stats_crash.yml 34 | 35 | - block: 36 | - ansible.builtin.assert: 37 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 38 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 39 | that: 40 | - _msg1 == result.msg or _msg2 == result.msg 41 | - ansible.builtin.import_tasks: custom_stats_pass.yml 42 | rescue: 43 | - ansible.builtin.debug: 44 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }} or {{ _msg2 }}" 45 | when: debug|bool 46 | - ansible.builtin.import_tasks: custom_stats_fail.yml 47 | vars: 48 | _msg1: "Jail '{{ jname }}' was destroyed., Jail {{ jname }} removed from iocage_jails." 49 | _msg2: "Jail {{ jname }} is already absent." 50 | when: not _crash 51 | -------------------------------------------------------------------------------- /test/tasks/base_create.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: base_create: Check if {{ basejail }} can be created" 15 | iocage: 16 | { 17 | "name": "{{ basejail }}", 18 | "release": "{{ release }}", 19 | "state": "basejail" 20 | } 21 | register: result 22 | - ansible.builtin.set_fact: 23 | _crash: false 24 | - ansible.builtin.debug: 25 | var: result 26 | when: debug2|bool 27 | - ansible.builtin.debug: 28 | var: result.msg 29 | when: debug|bool 30 | rescue: 31 | - ansible.builtin.debug: 32 | var: ansible_failed_result 33 | when: debug|bool 34 | - ansible.builtin.import_tasks: custom_stats_crash.yml 35 | 36 | - block: 37 | - ansible.builtin.assert: 38 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 39 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 40 | that: 41 | - _msg1 in result.msg or _msg2 == result.msg 42 | - ansible.builtin.import_tasks: custom_stats_pass.yml 43 | rescue: 44 | - ansible.builtin.debug: 45 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }} or {{ _msg2 }}" 46 | when: debug|bool 47 | - ansible.builtin.import_tasks: custom_stats_fail.yml 48 | vars: 49 | _msg1: "Jail '{{ basejail }}' was created with properties {}." 50 | _msg2: "{{ basejail }} already exists" 51 | when: not _crash 52 | -------------------------------------------------------------------------------- /test/tasks/facts.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: facts: Get all iocage_* facts by default" 15 | iocage: 16 | register: result 17 | - ansible.builtin.set_fact: 18 | _crash: false 19 | - ansible.builtin.debug: 20 | var: result 21 | when: debug2|bool 22 | - ansible.builtin.debug: 23 | msg: |- 24 | iocage_releases = {{ ansible_facts.iocage_releases }} 25 | iocage_templates.keys() = {{ ansible_facts.iocage_templates.keys()|list }} 26 | iocage_jails.keys() = {{ ansible_facts.iocage_jails.keys()|list }} 27 | when: debug|bool 28 | rescue: 29 | - ansible.builtin.debug: 30 | var: ansible_failed_result 31 | when: debug|bool 32 | - ansible.builtin.import_tasks: custom_stats_crash.yml 33 | 34 | - block: 35 | - ansible.builtin.assert: 36 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 37 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 38 | that: 39 | - not result.changed 40 | - not result.failed 41 | - result.stderr_lines|length == 0 42 | - result.stdout_lines|length == 0 43 | - ansible.builtin.import_tasks: custom_stats_pass.yml 44 | rescue: 45 | - ansible.builtin.debug: 46 | msg: "[ERR] {{ _test_name }} failed." 47 | when: debug|bool 48 | - ansible.builtin.import_tasks: custom_stats_fail.yml 49 | when: not _crash 50 | -------------------------------------------------------------------------------- /test/tasks/base_set.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: base_set: Verify that {{ basejail }} can be converted" 15 | iocage: 16 | { 17 | "name": "{{ basejail }}", 18 | "properties": "{{ properties }}", 19 | "state": "set" 20 | } 21 | register: result 22 | - ansible.builtin.set_fact: 23 | _crash: false 24 | - ansible.builtin.debug: 25 | var: result 26 | when: debug2|bool 27 | - ansible.builtin.debug: 28 | var: result.msg 29 | when: debug|bool 30 | - ansible.builtin.debug: 31 | var: iocage_templates[basejail].properties.template 32 | when: debug|bool 33 | rescue: 34 | - ansible.builtin.debug: 35 | var: ansible_failed_result 36 | when: debug|bool 37 | - ansible.builtin.import_tasks: custom_stats_crash.yml 38 | 39 | - block: 40 | - ansible.builtin.assert: 41 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 42 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 43 | that: 44 | - _msg1 in result.msg 45 | - ansible.builtin.import_tasks: custom_stats_pass.yml 46 | rescue: 47 | - ansible.builtin.debug: 48 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }}" 49 | when: debug|bool 50 | - ansible.builtin.import_tasks: custom_stats_fail.yml 51 | vars: 52 | _msg1: "already set for jail {{ basejail }}" 53 | when: not _crash 54 | -------------------------------------------------------------------------------- /test/tasks/base_set_template_no.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: base_set_template_no: Verify that {{ basejail }} can be converted" 15 | iocage: 16 | { 17 | "name": "{{ basejail }}", 18 | "properties": { 19 | "template": "no" 20 | }, 21 | "state": "set" 22 | } 23 | register: result 24 | - ansible.builtin.set_fact: 25 | _crash: false 26 | - ansible.builtin.debug: 27 | var: result 28 | when: debug2|bool 29 | - ansible.builtin.debug: 30 | var: result.msg 31 | when: debug|bool 32 | - ansible.builtin.debug: 33 | var: iocage_templates[basejail].properties.template 34 | when: debug|bool 35 | rescue: 36 | - ansible.builtin.debug: 37 | var: ansible_failed_result 38 | when: debug|bool 39 | - ansible.builtin.import_tasks: custom_stats_crash.yml 40 | 41 | - block: 42 | - ansible.builtin.assert: 43 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 44 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 45 | that: 46 | - _msg1 in result.msg 47 | - ansible.builtin.import_tasks: custom_stats_pass.yml 48 | rescue: 49 | - ansible.builtin.debug: 50 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }}" 51 | when: debug|bool 52 | - ansible.builtin.import_tasks: custom_stats_fail.yml 53 | vars: 54 | _msg1: "already set for jail {{ basejail }}" 55 | when: not _crash 56 | -------------------------------------------------------------------------------- /test/tasks/jail_restore.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | # Expect iocage to pass with expected message(s). 5 | # Status: 6 | # pass ..... module pass with expected message(s) 7 | # fail ..... module pass without expected message(s) 8 | # crash .... module crash 9 | 10 | - ansible.builtin.set_fact: 11 | _crash: true 12 | 13 | - block: 14 | - name: " >>> TEST START: jail_restore: Verify that base jail {{ basejail }} can be converted back" 15 | iocage: 16 | { 17 | "name": "{{ basejail }}", 18 | "properties": { 19 | "template": "yes" 20 | }, 21 | "state": "set" 22 | } 23 | register: result 24 | - ansible.builtin.set_fact: 25 | _crash: false 26 | - ansible.builtin.debug: 27 | var: result 28 | when: debug2|bool 29 | - ansible.builtin.debug: 30 | var: iocage_templates[basejail].properties.template 31 | when: debug|bool 32 | - ansible.builtin.debug: 33 | var: result.msg 34 | when: debug|bool 35 | rescue: 36 | - ansible.builtin.debug: 37 | var: ansible_failed_result 38 | when: debug|bool 39 | - ansible.builtin.import_tasks: custom_stats_crash.yml 40 | 41 | - block: 42 | - ansible.builtin.assert: 43 | fail_msg: "[ERR] {{ _test_name }}: Failed: {{ result.msg }}" 44 | success_msg: "[OK] {{ _test_name }}: Passed: {{ result.msg }}" 45 | that: 46 | - _msg1 in result.msg 47 | - ansible.builtin.import_tasks: custom_stats_pass.yml 48 | rescue: 49 | - ansible.builtin.debug: 50 | msg: "[ERR] {{ _test_name }} failed. Missing: {{ _msg1 }}" 51 | when: debug|bool 52 | - ansible.builtin.import_tasks: custom_stats_fail.yml 53 | vars: 54 | _msg1: "already set for jail {{ basejail }}" 55 | when: not _crash 56 | -------------------------------------------------------------------------------- /test/templates/command.j2: -------------------------------------------------------------------------------- 1 | #jinja2: trim_blocks: False 2 | --- 3 | # {{ ansible_managed }} 4 | 5 | # Expect iocage to pass with expected message(s). 6 | # Status: 7 | # pass ..... module pass with expected message(s) 8 | # fail ..... module pass without expected message(s) 9 | # crash .... module crash 10 | 11 | - ansible.builtin.set_fact: 12 | _crash: true 13 | 14 | - block: 15 | - name: " >>> TEST START: {{ test.label }}" 16 | iocage: 17 | {%- if test.iocage is defined %} 18 | {{ test.iocage|to_nice_json(indent=2)|indent(width=8) }} 19 | {%- endif %} 20 | register: result 21 | - ansible.builtin.set_fact: 22 | _crash: false 23 | - ansible.builtin.debug: 24 | var: result 25 | when: debug2|bool 26 | {%- for i in test.debug|default([]) %} 27 | - ansible.builtin.debug: 28 | {%- if i.msg is defined %} 29 | msg: |- 30 | {{ i.msg|indent(width=10) }} 31 | {%- endif %} 32 | {%- if i.var is defined %} 33 | var: {{ i.var }} 34 | {%- endif %} 35 | when: debug|bool 36 | {%- endfor %} 37 | rescue: 38 | - ansible.builtin.debug: 39 | var: ansible_failed_result 40 | when: debug|bool 41 | - ansible.builtin.import_tasks: custom_stats_crash.yml 42 | 43 | - block: 44 | - ansible.builtin.assert: 45 | fail_msg: "[ERR] {{ lbr }} _test_name {{ rbr }}: Failed: {{ lbr }} result.msg {{ rbr }}" 46 | success_msg: "[OK] {{ lbr }} _test_name {{ rbr }}: Passed: {{ lbr }} result.msg {{ rbr }}" 47 | that: 48 | {%- for i in test.assert %} 49 | - {{ i }} 50 | {%- endfor %} 51 | - ansible.builtin.import_tasks: custom_stats_pass.yml 52 | rescue: 53 | - ansible.builtin.debug: 54 | msg: "{{ test.msg_err }}" 55 | when: debug|bool 56 | - ansible.builtin.import_tasks: custom_stats_fail.yml 57 | {%- if test.vars|default({})|length > 0 %} 58 | vars: 59 | {%- for k,v in (test.vars|default({})).items() %} 60 | {{ k }}: {{ v }} 61 | {%- endfor %} 62 | {%- endif %} 63 | when: not _crash 64 | -------------------------------------------------------------------------------- /test/templates/command_crash.j2: -------------------------------------------------------------------------------- 1 | #jinja2: trim_blocks: False 2 | --- 3 | # {{ ansible_managed }} 4 | 5 | # Expect iocage to crash with expected message(s). 6 | # Status: 7 | # pass ..... module crash with expected message(s) 8 | # fail ..... module crash without expected message(s) 9 | # crash .... module does not crash 10 | 11 | - ansible.builtin.set_fact: 12 | _crash: false 13 | 14 | - block: 15 | - name: " >>> TEST START: {{ test.label }}" 16 | iocage: 17 | {%- if test.iocage is defined %} 18 | {{ test.iocage|to_nice_json(indent=2)|indent(width=8) }} 19 | {%- endif %} 20 | register: result 21 | - ansible.builtin.debug: 22 | var: result 23 | when: debug2|bool 24 | {%- for i in test.debug|default([]) %} 25 | - ansible.builtin.debug: 26 | {%- if i.msg is defined %} 27 | msg: |- 28 | {{ i.msg|indent(width=10) }} 29 | {%- endif %} 30 | {%- if i.var is defined %} 31 | var: {{ i.var }} 32 | {%- endif %} 33 | when: debug|bool 34 | {%- endfor %} 35 | - ansible.builtin.import_tasks: custom_stats_crash.yml 36 | rescue: 37 | - ansible.builtin.set_fact: 38 | _crash: true 39 | - ansible.builtin.debug: 40 | var: ansible_failed_result 41 | when: debug|bool 42 | 43 | - block: 44 | - ansible.builtin.assert: 45 | fail_msg: "[ERR] {{ lbr }} _test_name {{ rbr }}: Failed: {{ lbr }} ansible_failed_result.msg {{ rbr }}" 46 | success_msg: "[OK] {{ lbr }} _test_name {{ rbr }}: Passed: {{ lbr }} ansible_failed_result.msg {{ rbr }}" 47 | that: 48 | {%- for i in test.assert %} 49 | - {{ i }} 50 | {%- endfor %} 51 | - ansible.builtin.import_tasks: custom_stats_pass.yml 52 | rescue: 53 | - ansible.builtin.debug: 54 | msg: "{{ test.msg_err }}" 55 | when: debug|bool 56 | - ansible.builtin.import_tasks: custom_stats_fail.yml 57 | {%- if test.vars|default({})|length > 0 %} 58 | vars: 59 | {%- for k,v in (test.vars|default({})).items() %} 60 | {{ k }}: {{ v }} 61 | {%- endfor %} 62 | {%- endif %} 63 | when: _crash 64 | -------------------------------------------------------------------------------- /test/iocage_test.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | - hosts: "{{ my_hosts|default('localhost') }}" 5 | strategy: "{{ my_strategy|default('linear') }}" 6 | gather_facts: false 7 | become: true 8 | become_method: sudo 9 | 10 | vars: 11 | 12 | python_required: "{{ my_python_required|default('36') }}" 13 | jname: "{{ my_jname|default('test_jail') }}" 14 | release: "{{ my_release|default('13.0-RELEASE') }}" 15 | label_default: "{{ release|regex_replace('[\\W]', '_') }}" 16 | label: "{{ my_label|default(label_default) }}" 17 | basejail_default: "test_basejail_{{ label }}" 18 | basejail: "{{ my_basejail|default(basejail_default) }}" 19 | properties: "{{ my_properties|default({}) }}" 20 | debug: "{{ my_debug|default(false) }}" 21 | debug2: "{{ my_debug2|default(false) }}" 22 | 23 | tasks: 24 | 25 | - ansible.builtin.import_tasks: tasks/custom_stats_start.yml 26 | tags: always 27 | 28 | - ansible.builtin.import_tasks: tasks/group_absent.yml 29 | tags: group_absent 30 | 31 | - ansible.builtin.import_tasks: tasks/group_all.yml 32 | tags: group_all 33 | 34 | - ansible.builtin.import_tasks: tasks/group_base.yml 35 | tags: group_base 36 | 37 | - ansible.builtin.import_tasks: tasks/group_jail.yml 38 | tags: group_jail 39 | 40 | - ansible.builtin.import_tasks: tasks/group_present_absent_restart.yml 41 | tags: group_present_absent_restart 42 | 43 | - ansible.builtin.import_tasks: tasks/group_present_start_exec_set1.yml 44 | tags: group_present_start_exec_set1 45 | 46 | - ansible.builtin.import_tasks: tasks/group_setup.yml 47 | tags: group_setup 48 | 49 | - ansible.builtin.import_tasks: tasks/group_start_restart_stop.yml 50 | tags: group_start_restart_stop 51 | 52 | - ansible.builtin.import_tasks: tasks/group_start_restart_stop_crash.yml 53 | tags: group_start_restart_stop_crash 54 | 55 | - ansible.builtin.import_tasks: tasks/group_template.yml 56 | tags: group_template 57 | 58 | - ansible.builtin.import_tasks: tasks/group_test.yml 59 | tags: group_test 60 | 61 | - ansible.builtin.import_tasks: tasks/custom_stats_end.yml 62 | tags: always 63 | -------------------------------------------------------------------------------- /test/configure.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Configure iocage 4 | hosts: localhost 5 | connection: local 6 | gather_facts: false 7 | # become: true 8 | # become_method: sudo 9 | 10 | vars: 11 | 12 | lbr: "{{ '{{' }}" 13 | rbr: "{{ '}}' }}" 14 | 15 | tasks: 16 | 17 | - name: Create vars 18 | block: 19 | - name: Create iocage_test_db and my_tests 20 | ansible.builtin.include_vars: 21 | dir: vars/tests.d 22 | name: iocage_test_db 23 | extensions: ['yaml', 'yml'] 24 | ignore_unknown_extensions: true 25 | - ansible.builtin.set_fact: 26 | my_tests: "{{ iocage_test_db.keys()|list }}" 27 | when: my_tests is undefined 28 | - name: Create iocage_group_db and my_groups 29 | ansible.builtin.include_vars: 30 | dir: vars/groups.d 31 | name: iocage_group_db 32 | extensions: ['yaml', 'yml'] 33 | ignore_unknown_extensions: true 34 | - ansible.builtin.set_fact: 35 | my_groups: "{{ iocage_group_db.keys()|list }}" 36 | when: my_groups is undefined 37 | tags: [always, create_vars] 38 | 39 | - name: Create test files in directory tasks 40 | ansible.builtin.template: 41 | src: '{{ test.template }}.j2' 42 | dest: '{{ playbook_dir }}/tasks/{{ item }}.yml' 43 | mode: '0664' 44 | backup: true 45 | validate: ansible-lint %s 46 | loop: '{{ [my_tests]|flatten }}' 47 | vars: 48 | test: '{{ iocage_test_db[item] }}' 49 | tags: create_tests 50 | 51 | - name: Create group files in directory tasks 52 | ansible.builtin.template: 53 | src: '{{ group.template }}.j2' 54 | dest: '{{ playbook_dir }}/tasks/{{ item }}.yml' 55 | mode: '0664' 56 | backup: true 57 | validate: ansible-lint %s 58 | loop: '{{ [my_groups]|flatten }}' 59 | vars: 60 | group: '{{ iocage_group_db[item] }}' 61 | tags: create_groups 62 | 63 | - name: Create playbook iocage_test.yml 64 | ansible.builtin.template: 65 | src: iocage_test.yml.j2 66 | dest: iocage_test.yml 67 | mode: '0664' 68 | backup: true 69 | validate: ansible-lint %s 70 | tags: create_iocage_test 71 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | CHANGELOG 2 | ========= 3 | 4 | 5 | Generate tests from templates. 2020-08-28 6 | ----------------------------------------- 7 | 8 | * All files related to tests moved to directory test/ 9 | * Add playbook configure.yml 10 | * Add FQCN ansible.builtin.* 11 | * Create tests, groups, playbook from templates 12 | * Store templates in templates/ 13 | * Store configuration files in vars/ 14 | * Store examples of extra-vars files in extra-vars/ 15 | * Update .ansible-lint Skip unnamed-task to simplify code for testing 16 | * Update README 17 | 18 | 19 | iocage_test.yml 2020-08-24 20 | -------------------------- 21 | 22 | * hosts accepts var test_iocage. Default localhost 23 | * Add tasks/custom_stats_* to enable ANSIBLE_SHOW_CUSTOM_STATS 24 | * Add var _test_name to enhance the stats 25 | * Update README 26 | 27 | 28 | 2020-08-19 29 | ---------- 30 | 31 | * Add sanity test to iocage_test.yml 32 | * Update README.md 33 | * Update docs requirements. 34 | * Delete iocage. Was replaced by iocage.py 35 | 36 | 37 | iocage.py (2020-08-16) 38 | ---------------------- 39 | 40 | * Use f-strings everywhere. 41 | * Fix create cmd strings. -r -n values were interchanged. 42 | * Facts updated in doc. 43 | * Add (c) 2021 vbotka@gmail.com to the license. 44 | * All contibutors added to the authors in doc. 45 | 46 | 47 | iocage_test.yml (2020-08-11) 48 | ---------------------------- 49 | 50 | * All tests put into tagged block/rescue. 51 | * Module assert used to test rescued results and some of the 52 | successful results as well. 53 | * Optional debug output. 54 | * All tests passed. 55 | Controller: Ubuntu 20.04, ansible-base 2.10.12-1ppa~focal 56 | Node: FreeBSD 13.0-RELEASE, py38-iocage-1.2_9 57 | 58 | 59 | iocage.py (2020-08-11) 60 | ---------------------- 61 | 62 | * Copy iocage to iocage.py 63 | 64 | * Add function _command_fail 65 | 66 | * Add conversion of types and text transformation for Module utilities 67 | https://docs.ansible.com/ansible/latest/reference_appendices/module_utils.html 68 | 69 | * Removed quotation from the strings in examples. Quotation kept 70 | around IP. 71 | 72 | * Changed Boolean properties to 'true'/'false'. 73 | 74 | EXAMPLES = ''' 75 | ... 76 | properties: 77 | ip4_addr: 'lo1|10.1.0.5' 78 | boot: true 79 | allow_sysvipc: true 80 | 81 | * Removed option "force". It was used in the function *jail_start* 82 | only, but the command "iocage start ..." does not recognize *force*. 83 | 84 | * Removed options "stdout" and "stderr" from module_args 85 | 86 | * Removed empty defaults (name="", properties={}, ). The default of 87 | such options will be None. This will simplify the conditions (if 88 | name is not None). If needed such variables must be declared in the 89 | code (properties={}). 90 | 91 | * Default user for executing commands in a jail is root. Moved this 92 | assignment from the reading of module.params to module_args 93 | 94 | * Return _changed instead of values True/False 95 | 96 | * Add messages when state=absent 97 | 98 | _msg = "Jail {0} removed from iocage_templates.".format(name) 99 | _msg = "Jail {0} removed from iocage_jails.".format(name) 100 | _msg = "Jail {0} is already absent.".format(name) 101 | 102 | * Add rc to the result of state=exec 103 | 104 | 105 | # EOF 106 | -------------------------------------------------------------------------------- /test/tasks/group_all.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Ansible managed 3 | 4 | - ansible.builtin.import_tasks: tasks/absent_absent.yml 5 | vars: 6 | _test_name: absent_absent 7 | tags: [never, absent_absent] 8 | 9 | - ansible.builtin.import_tasks: tasks/absent_restart_crash.yml 10 | vars: 11 | _test_name: absent_restart_crash 12 | tags: [never, absent_restart_crash] 13 | 14 | - ansible.builtin.import_tasks: tasks/absent_start_crash.yml 15 | vars: 16 | _test_name: absent_start_crash 17 | tags: [never, absent_start_crash] 18 | 19 | - ansible.builtin.import_tasks: tasks/absent_stop_crash.yml 20 | vars: 21 | _test_name: absent_stop_crash 22 | tags: [never, absent_stop_crash] 23 | 24 | - ansible.builtin.import_tasks: tasks/base_clone.yml 25 | vars: 26 | _test_name: base_clone 27 | tags: [never, base_clone] 28 | 29 | - ansible.builtin.import_tasks: tasks/base_create.yml 30 | vars: 31 | _test_name: base_create 32 | tags: [never, base_create] 33 | 34 | - ansible.builtin.import_tasks: tasks/base_exists.yml 35 | vars: 36 | _test_name: base_exists 37 | tags: [never, base_exists] 38 | 39 | - ansible.builtin.import_tasks: tasks/base_set.yml 40 | vars: 41 | _test_name: base_set 42 | tags: [never, base_set] 43 | 44 | - ansible.builtin.import_tasks: tasks/base_set_template_no.yml 45 | vars: 46 | _test_name: base_set_template_no 47 | tags: [never, base_set_template_no] 48 | 49 | - ansible.builtin.import_tasks: tasks/facts.yml 50 | vars: 51 | _test_name: facts 52 | tags: [never, facts] 53 | 54 | - ansible.builtin.import_tasks: tasks/fetch.yml 55 | vars: 56 | _test_name: fetch 57 | tags: [never, fetch] 58 | 59 | - ansible.builtin.import_tasks: tasks/jail_absent.yml 60 | vars: 61 | _test_name: jail_absent 62 | tags: [never, jail_absent] 63 | 64 | - ansible.builtin.import_tasks: tasks/jail_restore.yml 65 | vars: 66 | _test_name: jail_restore 67 | tags: [never, jail_restore] 68 | 69 | - ansible.builtin.import_tasks: tasks/template_create.yml 70 | vars: 71 | _test_name: template_create 72 | tags: [never, template_create] 73 | 74 | - ansible.builtin.import_tasks: tasks/template_start_crash.yml 75 | vars: 76 | _test_name: template_start_crash 77 | tags: [never, template_start_crash] 78 | 79 | - ansible.builtin.import_tasks: tasks/template_stop.yml 80 | vars: 81 | _test_name: template_stop 82 | tags: [never, template_stop] 83 | 84 | - ansible.builtin.import_tasks: tasks/test_absent.yml 85 | vars: 86 | _test_name: test_absent 87 | tags: [never, test_absent] 88 | 89 | - ansible.builtin.import_tasks: tasks/test_absent2.yml 90 | vars: 91 | _test_name: test_absent2 92 | tags: [never, test_absent2] 93 | 94 | - ansible.builtin.import_tasks: tasks/test_clone.yml 95 | vars: 96 | _test_name: test_clone 97 | tags: [never, test_clone] 98 | 99 | - ansible.builtin.import_tasks: tasks/test_exec.yml 100 | vars: 101 | _test_name: test_exec 102 | tags: [never, test_exec] 103 | 104 | - ansible.builtin.import_tasks: tasks/test_pkg.yml 105 | vars: 106 | _test_name: test_pkg 107 | tags: [never, test_pkg] 108 | 109 | - ansible.builtin.import_tasks: tasks/test_pkg_crash.yml 110 | vars: 111 | _test_name: test_pkg_crash 112 | tags: [never, test_pkg_crash] 113 | 114 | - ansible.builtin.import_tasks: tasks/test_present.yml 115 | vars: 116 | _test_name: test_present 117 | tags: [never, test_present] 118 | 119 | - ansible.builtin.import_tasks: tasks/test_restart.yml 120 | vars: 121 | _test_name: test_restart 122 | tags: [never, test_restart] 123 | 124 | - ansible.builtin.import_tasks: tasks/test_restart_crash.yml 125 | vars: 126 | _test_name: test_restart_crash 127 | tags: [never, test_restart_crash] 128 | 129 | - ansible.builtin.import_tasks: tasks/test_set.yml 130 | vars: 131 | _test_name: test_set 132 | tags: [never, test_set] 133 | 134 | - ansible.builtin.import_tasks: tasks/test_start.yml 135 | vars: 136 | _test_name: test_start 137 | tags: [never, test_start] 138 | 139 | - ansible.builtin.import_tasks: tasks/test_start2.yml 140 | vars: 141 | _test_name: test_start2 142 | tags: [never, test_start2] 143 | 144 | - ansible.builtin.import_tasks: tasks/test_start3.yml 145 | vars: 146 | _test_name: test_start3 147 | tags: [never, test_start3] 148 | 149 | - ansible.builtin.import_tasks: tasks/test_start_crash.yml 150 | vars: 151 | _test_name: test_start_crash 152 | tags: [never, test_start_crash] 153 | 154 | - ansible.builtin.import_tasks: tasks/test_stop.yml 155 | vars: 156 | _test_name: test_stop 157 | tags: [never, test_stop] 158 | 159 | - ansible.builtin.import_tasks: tasks/test_stop_crash.yml 160 | vars: 161 | _test_name: test_stop_crash 162 | tags: [never, test_stop_crash] 163 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ansible-iocage 2 | ============== 3 | 4 | [![license](https://img.shields.io/badge/license-BSD-red.svg)](https://www.freebsd.org/doc/en/articles/bsdl-gpl/article.html) 5 | 6 | [iocage](https://github.com/iocage/iocage) module for Ansible. 7 | 8 | Home on https://github.com/fractalcells/ansible-iocage 9 | 10 | 11 | Description 12 | ----------- 13 | 14 | This module is an Ansible 'wrapper' of the iocage command. 15 | 16 | * Works with new Python3 iocage, not anymore with shell version 17 | * Release is host's one if not specified 18 | * Release is automatically fetched if missing 19 | 20 | 21 | Requirements (on the node) 22 | -------------------------- 23 | 24 | * lang/python >= 3.6 25 | * sysutils/iocage 26 | 27 | 28 | Install 29 | ------- 30 | 31 | Put the module to DEFAULT_MODULE_PATH 32 | 33 | ``` 34 | shell> ansible-config dump|grep DEFAULT_MODULE_PATH 35 | DEFAULT_MODULE_PATH(default) = ['/home/admin/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] 36 | ``` 37 | 38 | 39 | Documentation 40 | ------------- 41 | 42 | Only the inline documentation of the module is available. Run the command 43 | 44 | ``` 45 | shell> ansible-doc -t module iocage 46 | ``` 47 | 48 | Read the [iocage documentation at readthedocs.io](https://iocage.readthedocs.io/en/latest/) 49 | 50 | 51 | Example 52 | ------- 53 | 54 | No option of the module is required. Without any option the module 55 | gathers facts about the jails. For example the play below 56 | 57 | ```yaml 58 | shell> cat playbook.yml 59 | - hosts: srv.example.net 60 | tasks: 61 | - iocage: 62 | - debug: 63 | msg: |- 64 | iocage_releases = {{ ansible_facts.iocage_releases }} 65 | iocage_templates.keys() = {{ ansible_facts.iocage_templates.keys()|list }} 66 | iocage_jails.keys() = {{ ansible_facts.iocage_jails.keys()|list }} 67 | ``` 68 | 69 | gives 70 | 71 | ```yaml 72 | 73 | shell> ansible-playbook playbook.yml 74 | ... 75 | msg: |- 76 | iocage_releases = ['13.0-RELEASE'] 77 | iocage_templates.keys() = [] 78 | iocage_jails.keys() = ['NewJail', 'test_31', 'test_basejail_13_0_RELEASE'] 79 | ``` 80 | 81 | 82 | Use-cases 83 | --------- 84 | 85 | * Fetch 11.0-RELEASE 86 | 87 | ``` 88 | iocage: state=fetched release=11.0-RELEASE 89 | ``` 90 | 91 | * Fetch host's RELEASE 92 | 93 | ``` 94 | iocage: state=fetched 95 | ``` 96 | 97 | * Fetch just the base component of host's RELEASE 98 | 99 | ``` 100 | iocage: state=fetched components=base.txz 101 | ``` 102 | 103 | * Fetch host's RELEASE, limited to base and doc components 104 | 105 | ``` 106 | iocage: state=fetched components=base.txz,doc.txz 107 | ``` 108 | 109 | * Create basejail 110 | ``` 111 | iocage: state=basejail name="foo" release=11.0-RELEASE 112 | ``` 113 | 114 | * Create template 115 | 116 | ``` 117 | iocage: 118 | state: template 119 | name: mytemplate 120 | properties: 121 | ip4_addr: 'lo0|10.1.0.1' 122 | resolver: 'nameserver 127.0.0.1' 123 | ``` 124 | 125 | * Clone existing jail 126 | 127 | ``` 128 | iocage: 129 | state: present 130 | name: "foo" 131 | clone_from: "mytemplate" 132 | pkglist: /path/to/pkglist.json 133 | properties: 134 | ip4_addr: 'lo0|10.1.0.5' 135 | boot: "on" 136 | allow_sysvipc: 1 137 | defaultrouter: '10.1.0.1' 138 | host_hostname: 'myjail.my.domain' 139 | ``` 140 | 141 | * Create jail (without cloning) 142 | 143 | ``` 144 | iocage: 145 | state: present 146 | name: "foo" 147 | pkglist: /path/to/pkglist.json 148 | properties: 149 | ip4_addr: 'lo0|10.1.0.5' 150 | boot: "on" 151 | allow_sysvipc: 1 152 | defaultrouter: '10.1.0.1' 153 | host_hostname: 'myjail.my.domain' 154 | ``` 155 | 156 | * Ensure jail is started 157 | 158 | ``` 159 | iocage: state=started name="foo" 160 | ``` 161 | 162 | * Ensure jail is stopped 163 | 164 | ``` 165 | iocage: state=stopped name="foo" 166 | ``` 167 | 168 | * Restart existing jail 169 | 170 | ``` 171 | iocage: state=restarted name="myjail" 172 | ``` 173 | 174 | * Execute command in (running) jail 175 | 176 | ``` 177 | iocage: state=exec name="myjail" user="root" cmd="service sshd start" 178 | ``` 179 | 180 | * Destroy jail 181 | 182 | ``` 183 | iocage: state=absent name="myjail" 184 | ``` 185 | 186 | * Set attributes on jail 187 | 188 | ``` 189 | iocage: 190 | state: set 191 | name: "myjail" 192 | properties: 193 | template: "yes" 194 | ``` 195 | 196 | 197 | Tests 198 | ----- 199 | 200 | The project comes with set of tests stored in the directory test/tasks. Run 201 | the complete collection of the tests at localhost 202 | 203 | ``` 204 | shell> cd test 205 | shell> ansible-playbook -M . iocage_test.yml 206 | ``` 207 | 208 | This should display a report similar to this one 209 | 210 | ```sh 211 | PLAY RECAP *********************************************************************** 212 | localhost: ok=158 changed=17 unreachable=0 failed=0 skipped=65 rescued=6 ignored=0 213 | ``` 214 | 215 | Custom stats will provide you with more details if you run the tests 216 | on multiple nodes. See *ansible.builtin.set_stats*. For example run 217 | the complete collection of the tests on two nodes *test_23* and 218 | *test_29* 219 | 220 | ```sh 221 | shell> ANSIBLE_SHOW_CUSTOM_STATS=true ansible-playbook iocage_test.yml -M . -e my_hosts=test_23,test_29 222 | ``` 223 | 224 | This should display a report similar to this one 225 | 226 | ```sh 227 | PLAY RECAP ********************************************************************* 228 | test_23: ok=207 changed=17 unreachable=0 failed=0 skipped=28 rescued=6 ignored=0 229 | test_29: ok=207 changed=17 unreachable=0 failed=0 skipped=28 rescued=6 ignored=0 230 | 231 | CUSTOM STATS: ****************************************************************** 232 | test_23: a1: Aug 29 21:46:23 a2: Aug 29 21:52:12 ok: 35 233 | test_29: a1: Aug 29 21:46:23 a2: Aug 29 22:03:57 ok: 35 234 | ``` 235 | 236 | 237 | Advanced tests 238 | -------------- 239 | 240 | Most of the tests and groups are generated from templates (see 241 | directory templates) by the dictionaries *iocage_test_db* and 242 | *iocage_group_db* stored in the files in directory vars. Do not edit 243 | the tasks and groups manually. Modify or create new templates and 244 | dictionaries, and run the playbook *configure.yml*. For example, add 245 | new group of tests in *vars/groups.d/group_present_absent_restart.yml* 246 | 247 | ```yaml 248 | --- 249 | group_present_absent_restart: 250 | template: group 251 | tests: 252 | - test: test_present 253 | - test: test_absent 254 | - test: test_restart_crash 255 | ``` 256 | 257 | Run playbook *configure.yml* and create the group *group_present_absent_restart* 258 | 259 | ```sh 260 | shell> ansible-playbook configure.yml -e my_groups=group_present_absent_restart -t create_groups,create_iocage_test 261 | ... 262 | TASK [Create group files in directory tasks] ********************************* 263 | ok: [localhost] => (item=group_present_absent_restart) 264 | 265 | TASK [Create playbook iocage_test.yml] *************************************** 266 | ok: [localhost] 267 | ``` 268 | 269 | Create file with the parameters of the tests, e.g. run the tests on 270 | the nodes *test_23,test_29*, use jail *test_31*, enable debug, and set 271 | strategy *free* 272 | 273 | ```yaml 274 | shell> cat extra_vars/test_31-debug-n2.yml 275 | --- 276 | my_hosts: test_23,test_29 277 | my_jname: test_31 278 | my_debug: true 279 | my_strategy: free 280 | ``` 281 | 282 | Run the tests and display custom stats 283 | 284 | ```sh 285 | shell> ANSIBLE_SHOW_CUSTOM_STATS=true ansible-playbook iocage_test.yml -M . -e @extra_vars/test_31-debug-n2.yml -t group_present_absent_restart 286 | ``` 287 | 288 | This should display a report similar to this abridged one 289 | 290 | ```yaml 291 | 292 | PLAY [test_23,test_29] ***************************************************************** 293 | 294 | TASK [>>> TEST START: test_present: Check if test_31 can be created] ******************* 295 | ok: [test_23] => 296 | result.msg: |- 297 | Jail 'test_31' was created with properties {}. 298 | /usr/local/bin/iocage create -n test_31 -r 13.0-RELEASE 299 | ok: [test_29] => 300 | result.msg: |- 301 | Jail 'test_31' was created with properties {}. 302 | /usr/local/bin/iocage create -n test_31 -r 13.0-RELEASE 303 | 304 | ok: [test_23] => changed=false 305 | msg: |- 306 | [OK] test_present: Passed: Jail 'test_31' was created with properties {}. 307 | ok: [test_29] => changed=false 308 | msg: |- 309 | [OK] test_present: Passed: Jail 'test_31' was created with properties {}. 310 | 311 | TASK [>>> TEST START: test_absent: Check if jail test_31 can be destroyed] ************* 312 | ok: [test_23] => 313 | result.msg: Jail 'test_31' was destroyed., Jail test_31 removed from iocage_jails. 314 | ok: [test_29] => 315 | result.msg: Jail 'test_31' was destroyed., Jail test_31 removed from iocage_jails. 316 | 317 | ok: [test_23] => changed=false 318 | msg: '[OK] test_absent: Passed: Jail ''test_31'' was destroyed., Jail test_31 removed from iocage_jails.' 319 | ok: [test_29] => changed=false 320 | msg: '[OK] test_absent: Passed: Jail ''test_31'' was destroyed., Jail test_31 removed from iocage_jails.' 321 | 322 | TASK [>>> TEST START: test_restart_crash: Check if jail test_31 can not be restarted] ** 323 | fatal: [test_23]: FAILED! => changed=false 324 | msg: Jail 'test_31' doesn't exist 325 | fatal: [test_29]: FAILED! => changed=false 326 | msg: Jail 'test_31' doesn't exist 327 | 328 | ok: [test_23] => changed=false 329 | msg: '[OK] test_restart_crash: Passed: Jail ''test_31'' doesn''t exist' 330 | ok: [test_29] => changed=false 331 | msg: '[OK] test_restart_crash: Passed: Jail ''test_31'' doesn''t exist' 332 | 333 | 334 | CUSTOM STATS: ************************************************************************** 335 | test_23: a1: Aug 25 23:26:31 a2: Aug 25 23:27:01 ok: 3 336 | test_29: a1: Aug 25 23:26:31 a2: Aug 25 23:28:06 ok: 3 337 | ``` 338 | 339 | 340 | Variables and parameters of the tests 341 | ------------------------------------- 342 | 343 | In this framework, there are three sources of the tests' parameters 344 | 345 | * Hard-coded parameters in the test files and group files. If you want 346 | to customize them change the data in vars/ and run the playbook 347 | *configure.yml*. You can also add you own test and group files 348 | preferably in the form of the data in vars/ and templates. Add 349 | templates if needed. 350 | 351 | * Defaults in the playbook iocage_test.yml. If you want to customize 352 | them change the template *iocage_test.yml.j2* and run the playbook 353 | *configure.yml*. 354 | 355 | * Extra vars on the command line. See examples in the directory 356 | extra_vars/ on how to create files with extra variables. 357 | 358 | Except of this you can customize the variables at any other precedence 359 | you want to, of course. 360 | 361 | 362 | See also 363 | -------- 364 | 365 | * [iocage - A FreeBSD Jail Manager - iocage documentation at readthedocs.io](https://iocage.readthedocs.io/en/latest/) 366 | * [iocage - Jail manager using ZFS and VNET - FreeBSD System Manager's Manual](https://www.freebsd.org/cgi/man.cgi?query=iocage) 367 | -------------------------------------------------------------------------------- /iocage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Copyright 2015, Perceivon Hosting Inc. 5 | # Copyright 2021, Vladimir Botka 6 | # 7 | # Redistribution and use in source and binary forms, with or without 8 | # modification, are permitted provided that the following conditions are met: 9 | # 10 | # 1. Redistributions of source code must retain the above copyright notice, this 11 | # list of conditions and the following disclaimer. 12 | # 13 | # 2. Redistributions in binary form must reproduce the above copyright notice, 14 | # this list of conditions and the following disclaimer in the documentation 15 | # and/or other materials provided with the distribution. 16 | # 17 | # THIS SOFTWARE IS PROVIDED BY [COPYRIGHT HOLDER] AND CONTRIBUTORS "AS IS" AND 18 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | # DISCLAIMED. IN NO EVENT SHALL [COPYRIGHT HOLDER] OR CONTRIBUTORS BE LIABLE FOR 21 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 24 | # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | 28 | from __future__ import (absolute_import, division, print_function) 29 | __metaclass__ = type 30 | 31 | DOCUMENTATION = r''' 32 | --- 33 | module: iocage 34 | 35 | short_description: FreeBSD iocage jail handling 36 | 37 | description: 38 | - The M(iocage) module allows several iocage commands to be executed through ansible. 39 | - document use-cases here 40 | options: 41 | state: 42 | description: 43 | - I(state) of the desired result. 44 | type: str 45 | choices: [basejail, thickjail, template, present, cloned, started, 46 | stopped, restarted, fetched, exec, pkg, exists, absent, 47 | set, facts] 48 | default: facts 49 | name: 50 | description: 51 | - I(name) of the jail (former uuid). 52 | type: str 53 | pkglist: 54 | description: 55 | - Path to a JSON file containing packages to install. Only applicable when creating a jail. 56 | type: path 57 | properties: 58 | description: 59 | - I(properties) of the jail. 60 | type: dict 61 | args: 62 | description: 63 | - Additional arguments. 64 | type: dict 65 | user: 66 | description: 67 | - I(user) who runs the command I(cmd). 68 | type: str 69 | default: root 70 | cmd: 71 | description: 72 | - Execute the command I(cmd) inside the specified jail I(name). 73 | type: str 74 | clone_from: 75 | description: 76 | - Clone the jail I(clone_from) to I(name). Use I(properties) to configure the clone. 77 | type: str 78 | release: 79 | description: 80 | - Specify which RELEASE to fetch, update, or create a jail. 81 | type: str 82 | update: 83 | description: 84 | - Update the fetch to the latest patch level. 85 | type: bool 86 | default: False 87 | components: 88 | description: 89 | - Uses a local file directory for the root directory instead 90 | of HTTP to downloads and/or updates releases. 91 | type: list 92 | elements: path 93 | aliases: [files, component] 94 | requirements: 95 | - lang/python >= 3.6 96 | - sysutils/iocage 97 | notes: 98 | - Supports C(check_mode). 99 | - The module always creates facts B(iocage_releases), B(iocage_templates), and B(iocage_jails) 100 | - There is no mandatory option. 101 | - Returns B(module_args) when debugging is set B(ANSIBLE_DEBUG=true) 102 | seealso: 103 | - name: iocage - A FreeBSD Jail Manager 104 | description: iocage 1.2 documentation 105 | link: https://iocage.readthedocs.io/en/latest/ 106 | - name: iocage -- jail manager using ZFS and VNET 107 | description: FreeBSD System Manager's Manual 108 | link: https://www.freebsd.org/cgi/man.cgi?query=iocage 109 | author: 110 | - Johannes Meixner (@xmj) 111 | - dgeo (@dgeo) 112 | - Berend de Boer (@berenddeboer) 113 | - Dr Josef Karthauser (@Infiniverse) 114 | - Kevin P. Fleming (@kpfleming) 115 | - Ross Williams (@overhacked) 116 | - david8001 (@david8001) 117 | - luto (@luto) 118 | - Keve Müller (@kevemueller) 119 | - Mårten Lindblad (@martenlindblad) 120 | - Vladimir Botka (@vbotka) 121 | ''' 122 | 123 | EXAMPLES = r''' 124 | - name: Create all iocage_* ansible_facts 125 | iocage: 126 | 127 | - name: Display lists of bases, names of templates, and names of jails 128 | debug: 129 | msg: |- 130 | {{ iocage_releases }} 131 | {{ iocage_templates.keys()|list }} 132 | {{ iocage_jails.keys()|list }} 133 | 134 | - name: Create jail without cloning 135 | iocage: 136 | name: foo 137 | state: present 138 | pkglist: /path/to/pkglist.json 139 | properties: 140 | ip4_addr: 'lo1|10.1.0.5' 141 | boot: true 142 | allow_sysvipc: true 143 | defaultrouter: '10.1.0.1' 144 | 145 | - name: Create template 146 | iocage: 147 | name: tplfoo 148 | state: template 149 | pkglist: /path/to/pkglist.json 150 | properties: 151 | ip4_addr: 'lo1|10.1.0.5' 152 | boot: true 153 | allow_sysvipc: true 154 | defaultrouter: '10.1.0.1' 155 | 156 | - name: Create a cloned jail. Creates basejail if needed. 157 | iocage: 158 | name: foo 159 | state: present 160 | clone_from: tplfoo 161 | pkglist: /path/to/pkglist.json 162 | properties: 163 | ip4_addr: 'lo1|10.1.0.5' 164 | boot: true 165 | allow_sysvipc: true 166 | defaultrouter: '10.1.0.1' 167 | 168 | - name: Start existing jail 169 | iocage: 170 | name: foo 171 | state: started 172 | 173 | - name: Stop existing jail 174 | iocage: 175 | name: foo 176 | state: stopped 177 | 178 | - name: Restart existing jail 179 | iocage: 180 | name: foo 181 | state: restarted 182 | 183 | - name: Execute command in running jail 184 | iocage: 185 | name: foo 186 | state: exec 187 | cmd: service sshd start 188 | 189 | - name: Destroy jail 190 | iocage: 191 | name: foo 192 | state: absent 193 | ''' 194 | 195 | RETURN = r''' 196 | ansible_facts: 197 | description: Facts to add to ansible_facts. 198 | returned: always 199 | type: dict 200 | contains: 201 | iocage_releases: 202 | description: List of all bases. 203 | returned: always 204 | type: list 205 | elements: str 206 | sample: ['13.0-RELEASE'] 207 | iocage_templates: 208 | description: Dictionary of all templates. 209 | returned: always 210 | type: dict 211 | sample: {} 212 | iocage_jails: 213 | description: Dictionary of all jails. 214 | returned: always 215 | type: dict 216 | sample: {} 217 | module_args: 218 | description: Information on how the module was invoked. 219 | returned: debug 220 | type: dict 221 | ''' 222 | 223 | import json 224 | import re 225 | 226 | from ansible.module_utils.basic import AnsibleModule 227 | from ansible.module_utils._text import to_bytes 228 | 229 | 230 | def _command_fail(module, label, cmd, rc, stdout, stderr): 231 | module.fail_json(msg=f"{label}\ncmd: '{cmd}' return: {rc}\nstdout: '{stdout}'\nstderr: '{stderr}'") 232 | 233 | 234 | def _get_iocage_facts(module, iocage_path, argument="all", name=None): 235 | 236 | opt = dict(jails="list -hl", 237 | templates="list -hlt", 238 | releases="list -hr", 239 | init="list -h") 240 | 241 | if argument == "all": 242 | # _init = _get_iocage_facts(module, iocage_path, "init") 243 | _jails = _get_iocage_facts(module, iocage_path, "jails") 244 | _templates = _get_iocage_facts(module, iocage_path, "templates") 245 | _releases = _get_iocage_facts(module, iocage_path, "releases") 246 | return dict(iocage_jails=_jails, 247 | iocage_templates=_templates, 248 | iocage_releases=_releases) 249 | elif argument in opt: 250 | cmd = f"{iocage_path} {opt[argument]}" 251 | else: 252 | module.fail_json(msg=f"_get_iocage_facts({argument}): argument not understood") 253 | 254 | rc, state, err = module.run_command(to_bytes(cmd, errors='surrogate_or_strict'), 255 | errors='surrogate_or_strict') 256 | if rc != 0 and argument != "init": 257 | _command_fail(module, "_get_iocage_facts()", cmd, rc, state, err) 258 | elif argument == "init": 259 | return {} 260 | 261 | if argument == 'releases': 262 | _releases = [] 263 | for line in state.split('\n'): 264 | if re.match(r'\s*\d', line): 265 | _releases.append(line.strip()) 266 | return _releases 267 | 268 | _jails = {} 269 | try: 270 | for line in state.split('\n'): 271 | if line == "": 272 | continue 273 | _jid = line.split('\t')[0] 274 | if _jid == '---': 275 | # non-iocage jails: skip all 276 | break 277 | elif re.match(r'(\d+|-|None)', _jid): 278 | _fragments = line.split('\t') 279 | if len(_fragments) == 10: 280 | (_jid, _name, _boot, _state, _type, _release, _ip4, _ip6, _template, _basejail) = _fragments 281 | else: 282 | (_jid, _name, _boot, _state, _type, _release, _ip4, _ip6, _template) = _fragments 283 | if _name != "": 284 | _properties = _jail_get_properties(module, iocage_path, _name) 285 | _jails[_name] = {"jid": _jid, "name": _name, "state": _state, "properties": _properties} 286 | else: 287 | module.fail_json(msg=f"_get_iocage_facts():\nUnreadable stdout line from cmd '{cmd}': '{line}'") 288 | except ValueError: 289 | module.fail_json(msg=f"unable to parse {state}") 290 | 291 | if name is not None: 292 | if name in _jails: 293 | return _jails[name] 294 | else: 295 | return {} 296 | 297 | return _jails 298 | 299 | 300 | def _jail_started(module, iocage_path, name): 301 | 302 | cmd = f"{iocage_path} list -h" 303 | rc, state, err = module.run_command(to_bytes(cmd, errors='surrogate_or_strict'), 304 | errors='surrogate_or_strict') 305 | if rc != 0: 306 | _command_fail(module, f"jail_started({name})", cmd, rc, state, err) 307 | 308 | st = None 309 | for line in state.split('\n'): 310 | u = line.split('\t')[1] 311 | if u == name: 312 | s = line.split('\t')[2] 313 | if s == 'up': 314 | st = True 315 | break 316 | elif s == 'down': 317 | st = False 318 | break 319 | else: 320 | module.fail_json(msg=f"Jail {name} unknown state: {line}") 321 | 322 | return st 323 | 324 | 325 | def jail_exists(module, iocage_path, argument=None, assume_absent=False): 326 | 327 | cmd = f"{iocage_path} get host_hostuuid {argument}" 328 | rc, name, err = module.run_command(to_bytes(cmd, errors='surrogate_or_strict'), 329 | errors='surrogate_or_strict') 330 | if not rc == 0: 331 | name = "" 332 | 333 | # local variable '_msg' is assigned to but never used [F841] 334 | # _msg = "" 335 | 336 | if name != "" and assume_absent: 337 | module.fail_json(msg=f"Jail {argument} exists.") 338 | 339 | return name.strip() 340 | 341 | 342 | def jail_start(module, iocage_path, name): 343 | 344 | cmd = f"{iocage_path} start {name}" 345 | rc = 1 346 | out = "" 347 | _msg = "" 348 | _changed = True 349 | if not module.check_mode: 350 | rc, out, err = module.run_command(to_bytes(cmd, errors='surrogate_or_strict'), 351 | errors='surrogate_or_strict') 352 | if not rc == 0: 353 | _command_fail(module, f"Jail {name} could not be started.", cmd, rc, out, err) 354 | _msg = f"Jail {name} was started.\n{out}" 355 | else: 356 | _msg = f"Jail {name} would have been started." 357 | 358 | return _changed, _msg 359 | 360 | 361 | def _props_to_str(props): 362 | 363 | argstr = "" 364 | # local variable 'minargs' is assigned to but never used [F841] 365 | # minargs = "" 366 | for _prop in props: 367 | _val = props[_prop] 368 | if _val == '-' or _val == '' or not _val: 369 | continue 370 | if _val in ['yes', 'on', True]: 371 | argstr += f"{_prop}=1 " 372 | elif _val in ['no', 'off', False]: 373 | argstr += f"{_prop}=0 " 374 | elif _val in ['-', 'none']: 375 | argstr += f"{_prop}={_val} " 376 | else: 377 | argstr += f"{_prop}={str(_val)} " 378 | 379 | return argstr 380 | 381 | 382 | def release_fetch(module, iocage_path, update=False, release="NO-RELEASE", components=None, args=""): 383 | 384 | if not module.check_mode: 385 | if update: 386 | args += " -U" 387 | if components is not None: 388 | for _component in components: 389 | if _component != "": 390 | args += f" -F {_component}" 391 | cmd = f"{iocage_path} fetch -r {release} {args}" 392 | rc = 1 393 | rc, out, err = module.run_command(to_bytes(cmd, errors='surrogate_or_strict'), 394 | errors='surrogate_or_strict') 395 | if not rc == 0: 396 | _command_fail(module, f"Release {release} could not be fetched.", cmd, rc, out, err) 397 | _changed = True 398 | if update: 399 | _msg = f"Release {release} was successfully updated." 400 | else: 401 | _msg = f"Release {release} was successfully fetched." 402 | else: 403 | _changed = True 404 | _msg = f"Release {release} would have been fetched." 405 | 406 | return release, _changed, _msg 407 | 408 | 409 | def jail_restart(module, iocage_path, name): 410 | 411 | cmd = f"{iocage_path} restart {name}" 412 | rc = 1 413 | out = "" 414 | _msg = "" 415 | _changed = True 416 | if not module.check_mode: 417 | rc, out, err = module.run_command(to_bytes(cmd, errors='surrogate_or_strict'), 418 | errors='surrogate_or_strict') 419 | if not rc == 0: 420 | _command_fail(module, f"Jail {name} could not be restarted.", cmd, rc, out, err) 421 | _msg = f"Jail {name} was restarted.\n{rc}" 422 | else: 423 | _msg = f"Jail {name} would have been restarted." 424 | 425 | return _changed, _msg 426 | 427 | 428 | def jail_stop(module, iocage_path, name): 429 | 430 | cmd = f"{iocage_path} stop {name}" 431 | _changed = False 432 | rc = 1 433 | out = "" 434 | _msg = "" 435 | 436 | if not module.check_mode: 437 | rc, out, err = module.run_command(to_bytes(cmd, errors='surrogate_or_strict'), 438 | errors='surrogate_or_strict') 439 | if not rc == 0: 440 | _command_fail(module, f"Jail {name} could not be stopped.", cmd, rc, out, err) 441 | _msg = f"Jail {name} was stopped.\n" 442 | else: 443 | _msg = f"Jail {name} would have been stopped" 444 | 445 | return _changed, _msg 446 | 447 | 448 | def jail_exec(module, iocage_path, name, user="root", _cmd='/usr/bin/true'): 449 | 450 | rc = 1 451 | out = "" 452 | err = "" 453 | _msg = "" 454 | _changed = True 455 | if not module.check_mode: 456 | cmd = f"{iocage_path} exec -u {user} {name} -- {_cmd}" 457 | rc, out, err = module.run_command(to_bytes(cmd, errors='surrogate_or_strict'), 458 | errors='surrogate_or_strict') 459 | if not rc == 0: 460 | _command_fail(module, 461 | f"Command '{_cmd}' could not be executed in jail '{name}'.", 462 | cmd, rc, out, err) 463 | _msg = (f"Command '{cmd}' was executed in jail '{name}'.\nrc: {rc}\nstdout:\n{out}\nstderr:\n{err}") 464 | else: 465 | _msg = f"Command '{_cmd}' would have been executed in jail '{name}'." 466 | 467 | return _changed, _msg, out, err 468 | 469 | 470 | def jail_pkg(module, iocage_path, name, _cmd='info'): 471 | 472 | rc = 1 473 | out = "" 474 | err = "" 475 | _msg = "" 476 | _changed = True 477 | if not module.check_mode: 478 | cmd = f"{iocage_path} pkg {name} {_cmd}" 479 | rc, out, err = module.run_command(to_bytes(cmd, errors='surrogate_or_strict'), 480 | errors='surrogate_or_strict') 481 | if not rc == 0: 482 | _command_fail(module, 483 | f"pkg '{_cmd}' could not be executed in jail '{name}'.", 484 | cmd, rc, out, err) 485 | _msg = (f"pkg '{_cmd}' was executed in jail '{name}'.\nstdout:\n{out}\nstderr:\n{err}") 486 | 487 | else: 488 | _msg = f"pkg '{_cmd}' would have been executed in jail '{name}'." 489 | 490 | return _changed, _msg, out, err 491 | 492 | 493 | def _jail_get_properties(module, iocage_path, name): 494 | 495 | rc = 1 496 | out = "" 497 | if name is not None and name != "": 498 | properties = {} 499 | cmd = f"{iocage_path} get all {name}" 500 | rc, out, err = module.run_command(to_bytes(cmd, errors='surrogate_or_strict'), 501 | errors='surrogate_or_strict') 502 | if rc == 0: 503 | _properties = [line.strip() for line in out.strip().split('\n')] 504 | for p in _properties: 505 | for _property in [p.split(':', 1)]: 506 | if len(_property) == 2: 507 | properties[_property[0]] = _property[1] 508 | else: 509 | module.fail_json(msg=f"error parsing property {p} from {str(properties)}") 510 | else: 511 | _command_fail(module, f"_jail_get_properties({name})", cmd, rc, out, err) 512 | elif module.check_mode and name == "CHECK_MODE_FAKE_UUID": 513 | properties = {"CHECK_NEW_JAIL": True} 514 | else: 515 | module.fail_json(msg=f"jail {name} not found.") 516 | return properties 517 | 518 | 519 | def jail_set(module, iocage_path, name, properties=None): 520 | 521 | if properties is None: 522 | properties = {} 523 | 524 | rc = 1 525 | out = "" 526 | _msg = "" 527 | _changed = False 528 | cmd = "" 529 | _existing_props = _jail_get_properties(module, iocage_path, name) 530 | _props_to_be_changed = {} 531 | for _property in properties: 532 | if _property not in _existing_props: 533 | continue 534 | if _existing_props[_property] == '-' and not properties[_property]: 535 | continue 536 | if _property == "template": 537 | continue 538 | 539 | propval = None 540 | _val = properties[_property] 541 | _oval = _existing_props[_property] 542 | if _val in [0, 'no', 'off', False]: 543 | propval = 0 544 | elif _val in [1, 'yes', 'on', True]: 545 | propval = 1 546 | elif isinstance(_oval, str): 547 | if _val == '': 548 | propval = 'none' 549 | else: 550 | propval = f'{_val}' 551 | else: 552 | module.fail_json(msg="Unable to set attribute {0} to {1} for jail {2}" 553 | .format(_property, str(_val).replace("'", "'\\''"), name)) 554 | 555 | if 'CHECK_NEW_JAIL' in _existing_props or \ 556 | (_property in _existing_props.keys() and str(_existing_props[_property]) != str(propval)) and \ 557 | propval is not None: 558 | _props_to_be_changed[_property] = propval 559 | 560 | if len(_props_to_be_changed) > 0: 561 | need_restart = False 562 | for p in _props_to_be_changed.keys(): 563 | if p in ['ip4_addr', 'ip6_addr', 'template', 'interfaces', 'vnet', 'host_hostname']: 564 | need_restart = _jail_started(module, iocage_path, name) 565 | 566 | cmd = f"{iocage_path} set {_props_to_str(_props_to_be_changed)} {name}" 567 | 568 | if not module.check_mode: 569 | if need_restart: 570 | jail_stop(module, iocage_path, name) 571 | rc, out, err = module.run_command(cmd) 572 | if need_restart: 573 | jail_start(module, iocage_path, name) 574 | if not rc == 0 or (rc == 1 and "is already a jail!" in err): 575 | _command_fail(module, f"Attributes could not be set on jail '{name}'.", cmd, rc, out, err) 576 | _msg = f"properties {str(_props_to_be_changed.keys())} were set on jail '{name}' with cmd={cmd}." 577 | else: 578 | _msg = f"properties {str(_props_to_be_changed.keys())} would have been changed for jail {name} with command {cmd}" 579 | _msg += str(_props_to_be_changed) 580 | _changed = True 581 | 582 | else: 583 | _changed = False 584 | _msg = f"properties {properties.keys()} already set for jail {name}" 585 | 586 | return _changed, _msg 587 | 588 | 589 | def jail_create(module, iocage_path, name=None, properties=None, clone_from_name=None, 590 | clone_from_template=None, release=None, basejail=False, thickjail=False, pkglist=None): 591 | 592 | if properties is None: 593 | properties = {} 594 | 595 | rc = 1 596 | out = "" 597 | _msg = "" 598 | 599 | if clone_from_name is None and clone_from_template is None: 600 | if basejail: 601 | cmd = f"{iocage_path} create -b -n {name} -r {release}" 602 | 603 | elif thickjail: 604 | cmd = f"{iocage_path} create -T -n {name} -r {release} {_props_to_str(properties)}" 605 | 606 | else: 607 | cmd = f"{iocage_path} create -n {name} -r {release} {_props_to_str(properties)}" 608 | 609 | if pkglist: 610 | cmd += " --pkglist=" + pkglist 611 | 612 | elif clone_from_name: 613 | cmd = f"{iocage_path} clone {clone_from_name} -n {name} {_props_to_str(properties)}" 614 | elif clone_from_template: 615 | cmd = f"{iocage_path} create -t {clone_from_template} -n {name} {_props_to_str(properties)}" 616 | 617 | if not module.check_mode: 618 | rc, out, err = module.run_command(to_bytes(cmd, errors='surrogate_or_strict'), 619 | errors='surrogate_or_strict') 620 | if not rc == 0: 621 | _command_fail(module, f"Jail '{name}' could not be created.", cmd, rc, out, err) 622 | _msg += f"Jail '{name}' was created with properties {str(properties)}.\n\n{cmd}" 623 | name = jail_exists(module, iocage_path, name) 624 | if not name: 625 | module.fail_json(msg=f"Jail '{name}' not created ???\ncmd: {cmd}\nstdout:\n{out}\nstderr:\n{err}") 626 | 627 | else: 628 | _msg += f"Jail {name} would be created with command:\n{cmd}\n" 629 | name = f"CHECK_MODE_FAKE_UUID_FOR_{name}" 630 | 631 | return name, True, _msg 632 | 633 | 634 | def jail_update(module, iocage_path, name): 635 | 636 | rc = 1 637 | out = "" 638 | _msg = "" 639 | _changed = False 640 | cmd = f"{iocage_path} update {name}" 641 | if not module.check_mode: 642 | rc, out, err = module.run_command(to_bytes(cmd, errors='surrogate_or_strict'), 643 | errors='surrogate_or_strict') 644 | if not rc == 0: 645 | _command_fail(module, f"Jail '{name}' not updated.", cmd, rc, out, err) 646 | if "No updates needed" in out: 647 | _changed = False 648 | elif "updating to" in out: 649 | nv = re.search(r' ([^ ]*):$', filter((lambda x: 'updating to' in x), out.split('\n'))[0]).group(1) 650 | _msg = f"jail {name} updated to {nv}" 651 | _changed = True 652 | else: 653 | _msg = "Unable to check for updates in check_mode" 654 | 655 | return _changed, _msg 656 | 657 | 658 | def jail_destroy(module, iocage_path, name): 659 | 660 | rc = 1 661 | out = "" 662 | _msg = "" 663 | _changed = True 664 | if not module.check_mode: 665 | cmd = f"{iocage_path} destroy -f {name}" 666 | rc, out, err = module.run_command(to_bytes(cmd, errors='surrogate_or_strict'), 667 | errors='surrogate_or_strict') 668 | if not rc == 0: 669 | _command_fail(module, f"Jail '{name}' could not be destroyed.", cmd, rc, out, err) 670 | _msg = f"Jail '{name}' was destroyed." 671 | jail_exists(module, iocage_path, name, True) 672 | else: 673 | _msg = f"Jail {name} would have been destroyed." 674 | 675 | return name, _changed, _msg 676 | 677 | 678 | def run_module(): 679 | 680 | module_args = dict( 681 | state=dict(type='str', 682 | default="facts", 683 | choices=["basejail", "thickjail", "template", "present", "cloned", "started", 684 | "stopped", "restarted", "fetched", "exec", "pkg", "exists", "absent", 685 | "set", "facts"],), 686 | name=dict(type='str'), 687 | pkglist=dict(type='path'), 688 | properties=dict(type='dict'), 689 | args=dict(type='dict'), 690 | user=dict(type='str', default="root"), 691 | cmd=dict(type='str'), 692 | clone_from=dict(type='str'), 693 | release=dict(type='str'), 694 | update=dict(type='bool', default=False,), 695 | components=dict(type='list', elements='path', aliases=["files", "component"],),) 696 | 697 | module = AnsibleModule(argument_spec=module_args, 698 | supports_check_mode=True) 699 | 700 | iocage_path = module.get_bin_path('iocage', True) 701 | if not iocage_path: 702 | module.fail_json(msg='Utility iocage not found!') 703 | 704 | p = module.params 705 | name = p["name"] 706 | properties = p["properties"] 707 | cmd = p["cmd"] 708 | args = p["args"] 709 | clone_from = p["clone_from"] 710 | user = p["user"] 711 | release = p["release"] 712 | update = p["update"] 713 | components = p["components"] 714 | pkglist = p["pkglist"] 715 | 716 | msgs = [] 717 | changed = False 718 | out = "" 719 | err = "" 720 | 721 | facts = _get_iocage_facts(module, iocage_path, "all") 722 | 723 | jails = {} 724 | for u in facts["iocage_jails"]: 725 | jails[u] = facts["iocage_jails"][u] 726 | for u in facts["iocage_templates"]: 727 | jails[u] = facts["iocage_templates"][u] 728 | 729 | if p["state"] == "facts": 730 | result = dict(changed=changed, 731 | msg=", ".join(msgs), 732 | ansible_facts=facts, 733 | stdout=out, 734 | stderr=err, 735 | ) 736 | if module._debug: 737 | result['module_args'] = f"{(json.dumps(module.params, indent=4))}" 738 | module.exit_json(**result) 739 | 740 | # Input validation 741 | 742 | # states that need name of jail 743 | if name is None and p["state"] in ["started", "stopped", "restarted", "exists", "set", "exec", "pkg", "absent"]: 744 | module.fail_json(msg=f"name needed for state {p['state']}") 745 | 746 | # states that need release defined 747 | if p["state"] in ["basejail", "thickjail", "template", "fetched", "present"] or p["update"]: 748 | if release is None or release == "": 749 | # if name and not (upgrade): 750 | # _jail_props = _jail_get_properties(module, iocage_path, name) 751 | # release = _jail_props["release"] 752 | # else: 753 | rc, out, err = module.run_command("uname -r") 754 | if rc != 0: 755 | module.fail_json(msg="Unable to run uname -r ???") 756 | 757 | matches = re.match(r'(\d+\.\d+)\-(RELEASE|RC\d+).*', out.strip()) 758 | if matches is not None: 759 | release = matches.group(1) + "-RELEASE" 760 | else: 761 | module.fail_json(msg=f"Release not recognised: {out}") 762 | 763 | # need existing jail 764 | if p["state"] in ["started", "stopped", "restarted", "set", "exec", "pkg", "exists"]: 765 | if name not in jails: 766 | module.fail_json(msg=f"Jail '{name}' doesn't exist") 767 | 768 | # states that need running jail 769 | if p["state"] in ["exec", "pkg"] and jails[name]["state"] != "up": 770 | module.fail_json(msg=f"Jail '{name}' not running") 771 | 772 | if p["state"] == "started": 773 | if jails[name]["state"] != "up": 774 | changed, _msg = jail_start(module, iocage_path, name) 775 | msgs.append(_msg) 776 | jails[name] = _get_iocage_facts(module, iocage_path, "jails", name) 777 | if jails[name]["state"] != "up" and not module.check_mode: 778 | module.fail_json(msg=f"Starting jail {name} failed with {_msg}") 779 | else: 780 | msgs.append(f"Jail {name} already started") 781 | 782 | elif p["state"] == "stopped": 783 | if jails[name]["state"] == "up": 784 | changed, _msg = jail_stop(module, iocage_path, name) 785 | msgs.append(_msg) 786 | if not module.check_mode: 787 | jails[name] = _get_iocage_facts(module, iocage_path, "jails", name) 788 | if jails[name]["state"] != "down": 789 | module.fail_json(msg=f"Stopping jail {name} failed with {_msg}") 790 | else: 791 | msgs.append(f"Jail {name} already stopped") 792 | 793 | elif p["state"] == "restarted": 794 | changed, _msg = jail_restart(module, iocage_path, name) 795 | jails[name] = _get_iocage_facts(module, iocage_path, "jails", name) 796 | if jails[name]["state"] != "up": 797 | module.fail_json(msg=f"Restarting jail {name} failed with {_msg}") 798 | msgs.append(_msg) 799 | 800 | elif p["state"] == "exec": 801 | changed, _msg, out, err = jail_exec(module, iocage_path, name, user, cmd) 802 | msgs.append(_msg) 803 | 804 | elif p["state"] == "pkg": 805 | changed, _msg, out, err = jail_pkg(module, iocage_path, name, cmd) 806 | msgs.append(_msg) 807 | 808 | elif p["state"] == "exists": 809 | msgs.append(f"Jail {name} exists") 810 | 811 | elif p["state"] == "fetched": 812 | if update or release not in facts["iocage_releases"]: 813 | rel, changed, _msg = release_fetch(module, iocage_path, update, release, components, args) 814 | msgs.append(_msg) 815 | facts["iocage_releases"] = _get_iocage_facts(module, iocage_path, "releases") 816 | if release not in facts["iocage_releases"] or update: 817 | module.fail_json(msg=f"Fetching release {release} failed with {_msg}") 818 | else: 819 | msgs.append(f"Release {release} already fetched") 820 | 821 | elif p["state"] == "set": 822 | changed, _msg = jail_set(module, iocage_path, name, properties) 823 | msgs.append(_msg) 824 | jails[name] = _get_iocage_facts(module, iocage_path, "jails", name) 825 | 826 | elif p["state"] in ["present", "cloned", "template", "basejail", "thickjail"]: 827 | 828 | do_basejail = False 829 | do_thickjail = False 830 | clone_from_name = None 831 | clone_from_template = None 832 | # local variable 'jail_exists' is assigned to but never used [F841] 833 | # jail_exists = False 834 | 835 | if p["state"] != "cloned" and release not in facts["iocage_releases"]: 836 | release, _release_changed, _release_msg = release_fetch(module, iocage_path, update, release, components, args) 837 | if _release_changed: 838 | facts["iocage_releases"] = _get_iocage_facts(module, iocage_path, "releases") 839 | msgs.append(_release_msg) 840 | 841 | if p["state"] == "template": 842 | if properties is None: 843 | properties = {} 844 | properties["template"] = "true" 845 | properties["boot"] = "false" 846 | if name in facts["iocage_templates"]: 847 | # local variable 'jail_exists' is assigned to but never used [F841] 848 | # jail_exists = True 849 | pass 850 | 851 | elif p["state"] == "basejail": 852 | properties = {} 853 | do_basejail = True 854 | 855 | elif p["state"] == "thickjail": 856 | do_thickjail = True 857 | 858 | elif clone_from: 859 | if clone_from in facts["iocage_jails"]: 860 | clone_from_name = clone_from 861 | elif clone_from in facts["iocage_templates"]: 862 | clone_from_template = clone_from 863 | else: 864 | if module.check_mode: 865 | # todo: use facts to check if basejail would have been created before 866 | msgs.append(f"Jail {name} would have been cloned from (nonexisting) jail or template {clone_from}") 867 | else: 868 | module.fail_json(msg=f"unable to create jail {name}\nbasejail {clone_from} doesn't exist") 869 | 870 | if name not in facts["iocage_templates"] and name not in facts["iocage_jails"]: 871 | name, changed, _msg = jail_create(module, iocage_path, name, properties, clone_from_name, 872 | clone_from_template, release, do_basejail, do_thickjail, 873 | pkglist) 874 | msgs.append(_msg) 875 | else: 876 | changed, _msg = jail_set(module, iocage_path, name, properties) 877 | msgs.append("%s already exists" % (name)) 878 | if changed: 879 | msgs.append(_msg) 880 | 881 | if p["update"]: 882 | if release not in facts["iocage_releases"]: 883 | release, _release_changed, _release_msg = release_fetch(module, iocage_path, update, release, components, args) 884 | if _release_changed: 885 | _msg += _release_msg 886 | facts["iocage_releases"] = _get_iocage_facts(module, iocage_path, "releases") 887 | 888 | release, changed, _msg = jail_update(module, iocage_path, name, release) 889 | msgs.append(_msg) 890 | 891 | # # re-set properties (iocage missing them on creation - iocage-sh bug) 892 | # if len(p["properties"]) > 0: 893 | # changed, _msg = jail_set(module, iocage_path, name, properties) 894 | # if changed: 895 | # msgs.append(_msg) 896 | 897 | if changed: 898 | if p["state"] == "template": 899 | facts["iocage_templates"][name] = _get_iocage_facts(module, iocage_path, "templates", name) 900 | else: 901 | facts["iocage_jails"][name] = _get_iocage_facts(module, iocage_path, "jails", name) 902 | 903 | elif p["state"] == "absent": 904 | if name in jails: 905 | if jails[name]['state'] == "up": 906 | changed, _msg = jail_stop(module, iocage_path, name) 907 | msgs.append(_msg) 908 | name, changed, _msg = jail_destroy(module, iocage_path, name) 909 | msgs.append(_msg) 910 | del(jails[name]) 911 | else: 912 | _msg = f"Jail {name} is already absent." 913 | msgs.append(_msg) 914 | if name in facts["iocage_jails"]: 915 | del(facts["iocage_jails"][name]) 916 | _msg = f"Jail {name} removed from iocage_jails." 917 | msgs.append(_msg) 918 | if name in facts["iocage_templates"]: 919 | del(facts["iocage_templates"][name]) 920 | _msg = f"Jail {name} removed from iocage_templates." 921 | msgs.append(_msg) 922 | 923 | result = dict(changed=changed, 924 | msg=", ".join(msgs), 925 | ansible_facts=facts, 926 | stdout=out, 927 | stderr=err, 928 | ) 929 | if module._debug: 930 | result['module_args'] = f"{(json.dumps(module.params, indent=4))}" 931 | 932 | module.exit_json(**result) 933 | 934 | 935 | def main(): 936 | run_module() 937 | 938 | 939 | if __name__ == '__main__': 940 | main() 941 | --------------------------------------------------------------------------------