diff --git a/.github/BOTMETA.yml b/.github/BOTMETA.yml index 251bb71bff..bf8a0a5050 100644 --- a/.github/BOTMETA.yml +++ b/.github/BOTMETA.yml @@ -484,6 +484,8 @@ files: $modules/apache2_module.py: ignore: robinro maintainers: berendt n0trax + $modules/apache2_site.py: + maintainers: Francisco-Xiq $modules/apk.py: ignore: kbrebanov labels: apk diff --git a/plugins/modules/apache2_site.py b/plugins/modules/apache2_site.py new file mode 100644 index 0000000000..0907b61e62 --- /dev/null +++ b/plugins/modules/apache2_site.py @@ -0,0 +1,104 @@ +#!/usr/bin/python + +# Copyright (c) 2026, Francisco Pereira (@Francisco-Xiq) +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import annotations + +DOCUMENTATION = r""" +module: apache2_site +author: + - Francisco Pereira (@Francisco-Xiq) +short_description: Enables/disables a site of the Apache2 webserver +description: + - Enables or disables a specified site of the Apache2 webserver. + - Uses C(a2ensite) and C(a2dissite) under the hood. +version_added: 13.1.0 +notes: + - This module is only supported on Debian/Ubuntu-based systems, + as it depends on C(a2ensite) and C(a2dissite). +extends_documentation_fragment: + - community.general._attributes +attributes: + check_mode: + support: full + diff_mode: + support: none +options: + name: + type: str + description: + - Name of the site to enable/disable as given to C(a2ensite)/C(a2dissite). + - The name should not include the C(.conf) extension. + required: true + state: + type: str + description: + - Desired state of the site. + choices: [present, absent] + required: true +""" + +EXAMPLES = r""" +- name: Enable my_cool_site + community.general.apache2_site: + state: present + name: my_cool_site + +- name: Disable old site + community.general.apache2_site: + state: absent + name: very_old_site +""" + +RETURN = r""" +name: + description: Name of the site. + returned: success + type: str + sample: my_cool_site +""" + +import os + +from ansible.module_utils.basic import AnsibleModule + + +def site_is_enabled(name): + return os.path.islink(f"/etc/apache2/sites-enabled/{name}.conf") + + +def main(): + module = AnsibleModule( + argument_spec=dict( + name=dict(type="str", required=True), + state=dict(type="str", required=True, choices=["present", "absent"]), + ), + supports_check_mode=True, + ) + + name = module.params["name"] + state = module.params["state"] + want_enabled = state == "present" + is_enabled = site_is_enabled(name) + + changed = False + + if want_enabled and not is_enabled: + changed = True + if not module.check_mode: + a2ensite = module.get_bin_path("a2ensite", required=True) + module.run_command([a2ensite, name], check_rc=True) + + elif not want_enabled and is_enabled: + changed = True + if not module.check_mode: + a2dissite = module.get_bin_path("a2dissite", required=True) + module.run_command([a2dissite, name], check_rc=True) + + module.exit_json(changed=changed, name=name) + + +if __name__ == "__main__": + main() diff --git a/tests/integration/targets/apache2_site/aliases b/tests/integration/targets/apache2_site/aliases new file mode 100644 index 0000000000..fa3119327f --- /dev/null +++ b/tests/integration/targets/apache2_site/aliases @@ -0,0 +1,11 @@ +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +azp/posix/3 +destructive + +skip/rhel +skip/freebsd +skip/macos +skip/alpine diff --git a/tests/integration/targets/apache2_site/meta/main.yml b/tests/integration/targets/apache2_site/meta/main.yml new file mode 100644 index 0000000000..f32339acf0 --- /dev/null +++ b/tests/integration/targets/apache2_site/meta/main.yml @@ -0,0 +1,7 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +dependencies: + - setup_apache2 diff --git a/tests/integration/targets/apache2_site/tasks/actualtest.yml b/tests/integration/targets/apache2_site/tasks/actualtest.yml new file mode 100644 index 0000000000..6b8ce14b8f --- /dev/null +++ b/tests/integration/targets/apache2_site/tasks/actualtest.yml @@ -0,0 +1,84 @@ +--- +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +- name: Create test site config + ansible.builtin.copy: + dest: /etc/apache2/sites-available/ansible_test_site.conf + content: | + + ServerName ansible-test.local + DocumentRoot /var/www/html + + +- name: Enable test site + community.general.apache2_site: + name: ansible_test_site + state: present + register: enable_first + +- name: Ensure changed on first enable + ansible.builtin.assert: + that: + - enable_first is changed + +- name: Enable test site again (idempotency check) + community.general.apache2_site: + name: ansible_test_site + state: present + register: enable_second + +- name: Ensure idempotency on enable + ansible.builtin.assert: + that: + - enable_second is not changed + +- name: Disable test site + community.general.apache2_site: + name: ansible_test_site + state: absent + register: disable_first + +- name: Ensure changed on first disable + ansible.builtin.assert: + that: + - disable_first is changed + +- name: Disable test site again (idempotency check) + community.general.apache2_site: + name: ansible_test_site + state: absent + register: disable_second + +- name: Ensure idempotency on disable + ansible.builtin.assert: + that: + - disable_second is not changed + +- name: Enable test site in check_mode + community.general.apache2_site: + name: ansible_test_site + state: present + check_mode: true + register: check_mode_result + +- name: Ensure check_mode reports changed + ansible.builtin.assert: + that: + - check_mode_result is changed + +- name: Ensure check_mode did not actually enable the site + ansible.builtin.stat: + path: /etc/apache2/sites-enabled/ansible_test_site.conf + register: site_stat + +- name: Assert symlink was not created in check_mode + ansible.builtin.assert: + that: + - not site_stat.stat.exists + +- name: Remove test site config + ansible.builtin.file: + path: /etc/apache2/sites-available/ansible_test_site.conf + state: absent diff --git a/tests/integration/targets/apache2_site/tasks/main.yml b/tests/integration/targets/apache2_site/tasks/main.yml new file mode 100644 index 0000000000..f4bc089d97 --- /dev/null +++ b/tests/integration/targets/apache2_site/tasks/main.yml @@ -0,0 +1,39 @@ +--- +#################################################################### +# WARNING: These are designed specifically for Ansible tests # +# and should not be used as examples of how to write Ansible roles # +#################################################################### + +# Copyright (c) Ansible Project +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +- name: test apache2_site + + when: ansible_facts.os_family == 'Debian' + + block: + - name: get list of enabled sites before tests + ansible.builtin.command: ls /etc/apache2/sites-enabled/ + register: sites_before + changed_when: false + + - name: include actual tests + ansible.builtin.include_tasks: actualtest.yml + + - name: get list of enabled sites after tests + ansible.builtin.command: ls /etc/apache2/sites-enabled/ + register: sites_after + changed_when: false + + - name: sites before tests + ansible.builtin.debug: + var: sites_before.stdout_lines + + - name: sites after tests + ansible.builtin.debug: + var: sites_after.stdout_lines + + - name: ensure that all test sites are disabled again + ansible.builtin.assert: + that: sites_before.stdout == sites_after.stdout